.nicEdit-main p { margin: 0; }
-
-
-
-
-
-Accelerometer
-
-
- The goal of this script is to demonstrate the usage of accelerometer.
-
-
- The orientation specification can be found here .
-
-
-
- browser, vendor, mobile, orientation
-
-
-Device motion
-
-
-
-
-Device orientation
-
-
-
-
-MOZ orientation
-
-
-
-
-
-
+
+
+
+
+
+
+ OpenLayers Accelerometer Usage
+
+
+
+
+
+
+
+
+Accelerometer
+
+
+ The goal of this script is to demonstrate the usage of accelerometer.
+
+
+ The orientation specification can be found here .
+
+
+
+ browser, vendor, mobile, orientation
+
+
+Device motion
+
+
+
+
+Device orientation
+
+
+
+
+MOZ orientation
+
+
+
+
+
+
diff --git a/src/geonode-client/app/static/externals/openlayers/examples/browser.html b/src/geonode-client/app/static/externals/openlayers/examples/browser.html
index 195f7d4..f5568ed 100644
--- a/src/geonode-client/app/static/externals/openlayers/examples/browser.html
+++ b/src/geonode-client/app/static/externals/openlayers/examples/browser.html
@@ -1,152 +1,152 @@
-
-
-
-
-
-
- OpenLayers Browser Detection
-
-
-
-
-
-
-
-Browser detection
-
-
- browser, vendor, mobile, events, HTML5, gesture, touch
-
-
-
- The goal of this script is to inform about the capacity of the browser used by the user.
-
-
-
-
-Your browser information
-
-
-
-
-Click or touch the red square to get information about the selected events
-
-
-
-
-
-
+
+
+
+
+
+
+ OpenLayers Browser Detection
+
+
+
+
+
+
+
+Browser detection
+
+
+ browser, vendor, mobile, events, HTML5, gesture, touch
+
+
+
+ The goal of this script is to inform about the capacity of the browser used by the user.
+
+
+
+
+Your browser information
+
+
+
+
+Click or touch the red square to get information about the selected events
+
+
+
+
+
+
diff --git a/src/geonode-client/app/static/externals/openlayers/examples/browser.js b/src/geonode-client/app/static/externals/openlayers/examples/browser.js
index a593ca6..24e7ad4 100644
--- a/src/geonode-client/app/static/externals/openlayers/examples/browser.js
+++ b/src/geonode-client/app/static/externals/openlayers/examples/browser.js
@@ -1,241 +1,241 @@
-var isEventSupported = (function(undef) {
-
- var TAGNAMES = {
- 'select':'input',
- 'change':'input',
- 'submit':'form',
- 'reset':'form',
- 'error':'img',
- 'load':'img',
- 'abort':'img'
- };
-
- function isEventSupported(eventName, element) {
- element = element || document.createElement(TAGNAMES[eventName] || 'div');
- eventName = 'on' + eventName;
-
- var isSupported = (eventName in element);
-
- if (!isSupported) {
- // if it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
- if (!element.setAttribute) {
- element = document.createElement('div');
- }
- if (element.setAttribute && element.removeAttribute) {
- element.setAttribute(eventName, '');
- isSupported = typeof element[eventName] == 'function';
-
- // if property was created, "remove it" (by setting value to `undefined`)
- if (typeof element[eventName] != 'undefined') {
- element[eventName] = undef;
- }
- element.removeAttribute(eventName);
- }
- }
-
- element = null;
- return isSupported;
- }
-
- return isEventSupported;
-})();
-
-function divResult(category, name, element, div) {
- div.innerHTML = div.innerHTML + category + " " + name + ": ";
- div.innerHTML = div.innerHTML + (
- isEventSupported(name, element)
- ? 'true '
- : 'false '
- );
- div.innerHTML = div.innerHTML + " ";
-}
-var counter = 1;
-
-function log(title, detail) {
- var logDiv = document.getElementById("log");
- idString = "'id" + counter + "'";
- var newlink = document.createElement('a');
- newlink.setAttribute('href', "javascript:toggle_visibility(" + idString + ")");
- newlink.innerHTML = counter + ". " + title;
- var br1 = document.createElement('br');
- logDiv.appendChild(newlink);
- logDiv.appendChild(br1);
-
- var childDiv = document.createElement('div');
- childDiv.setAttribute("id", idString.replace("'", "").replace("'", ""));
- childDiv.setAttribute("style", 'display: none; margin-left : 5px;');
- childDiv.innerHTML = detail;
- var br2 = document.createElement('br');
- logDiv.appendChild(childDiv);
-
- counter = counter + 1;
-}
-
-function inspect(obj) {
- if (typeof obj === "undefined") {
- return "undefined";
- }
- var _props = [];
-
- for (var i in obj) {
- _props.push(i + " : " + obj[i]);
- }
- return " {" + _props.join(", ") + "} ";
-}
-
-function click(e) {
- if (document.getElementById("clickID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function dblclick(e) {
- if (document.getElementById("dblclickID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function mousedown(e) {
- if (document.getElementById("mousedownID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function mouseup(e) {
- if (document.getElementById("mouseupID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function mouseover(e) {
- if (document.getElementById("mouseoverID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function mousemove(e) {
- if (document.getElementById("mousemoveID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function mouseout(e) {
- if (document.getElementById("mouseoutID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function touchstart(e) {
- if (document.getElementById("touchstartID").checked) {
- var box = document.getElementById("box");
- var result = inspect(e);
- for (var i = 0; i < e.touches.length; i++) {
- result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
- }
- log(e.type, result);
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function touchend(e) {
- if (document.getElementById("touchendID").checked) {
- var box = document.getElementById("box");
- var result = inspect(e);
- for (var i = 0; i < e.touches.length; i++) {
- result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
- }
- log(e.type, result);
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function touchmove(e) {
- if (document.getElementById("touchmoveID").checked) {
- var targetEvent = e.touches.item(0);
- var box = document.getElementById("box");
- box.style.left = targetEvent.clientX + "px";
- box.style.top = targetEvent.clientY + "px";
- var result = inspect(e);
- for (var i = 0; i < e.touches.length; i++) {
- result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
- }
- log(e.type, result);
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function touchcancel(e) {
- if (document.getElementById("touchcancelID").checked) {
- var box = document.getElementById("box");
- var result = inspect(e);
- for (var i = 0; i < e.touches.length; i++) {
- result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
- }
- log(e.type, result);
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function gesturestart(e) {
- if (document.getElementById("gesturestartID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function gesturechange(e) {
- if (document.getElementById("gesturechangeID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function gestureend(e) {
- if (document.getElementById("gestureendID").checked) {
- var box = document.getElementById("box");
- log(e.type, inspect(e));
- if (e.preventDefault) e.preventDefault();
- }
- return false;
-}
-
-function toggle_visibility(id) {
- var e = document.getElementById(id);
- if (e.style.display == 'block') {
- e.style.display = 'none';
- } else {
- e.style.display = 'block';
- }
-}
-
-
-
+var isEventSupported = (function(undef) {
+
+ var TAGNAMES = {
+ 'select':'input',
+ 'change':'input',
+ 'submit':'form',
+ 'reset':'form',
+ 'error':'img',
+ 'load':'img',
+ 'abort':'img'
+ };
+
+ function isEventSupported(eventName, element) {
+ element = element || document.createElement(TAGNAMES[eventName] || 'div');
+ eventName = 'on' + eventName;
+
+ var isSupported = (eventName in element);
+
+ if (!isSupported) {
+ // if it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
+ if (!element.setAttribute) {
+ element = document.createElement('div');
+ }
+ if (element.setAttribute && element.removeAttribute) {
+ element.setAttribute(eventName, '');
+ isSupported = typeof element[eventName] == 'function';
+
+ // if property was created, "remove it" (by setting value to `undefined`)
+ if (typeof element[eventName] != 'undefined') {
+ element[eventName] = undef;
+ }
+ element.removeAttribute(eventName);
+ }
+ }
+
+ element = null;
+ return isSupported;
+ }
+
+ return isEventSupported;
+})();
+
+function divResult(category, name, element, div) {
+ div.innerHTML = div.innerHTML + category + " " + name + ": ";
+ div.innerHTML = div.innerHTML + (
+ isEventSupported(name, element)
+ ? 'true '
+ : 'false '
+ );
+ div.innerHTML = div.innerHTML + " ";
+}
+var counter = 1;
+
+function log(title, detail) {
+ var logDiv = document.getElementById("log");
+ idString = "'id" + counter + "'";
+ var newlink = document.createElement('a');
+ newlink.setAttribute('href', "javascript:toggle_visibility(" + idString + ")");
+ newlink.innerHTML = counter + ". " + title;
+ var br1 = document.createElement('br');
+ logDiv.appendChild(newlink);
+ logDiv.appendChild(br1);
+
+ var childDiv = document.createElement('div');
+ childDiv.setAttribute("id", idString.replace("'", "").replace("'", ""));
+ childDiv.setAttribute("style", 'display: none; margin-left : 5px;');
+ childDiv.innerHTML = detail;
+ var br2 = document.createElement('br');
+ logDiv.appendChild(childDiv);
+
+ counter = counter + 1;
+}
+
+function inspect(obj) {
+ if (typeof obj === "undefined") {
+ return "undefined";
+ }
+ var _props = [];
+
+ for (var i in obj) {
+ _props.push(i + " : " + obj[i]);
+ }
+ return " {" + _props.join(", ") + "} ";
+}
+
+function click(e) {
+ if (document.getElementById("clickID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function dblclick(e) {
+ if (document.getElementById("dblclickID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function mousedown(e) {
+ if (document.getElementById("mousedownID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function mouseup(e) {
+ if (document.getElementById("mouseupID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function mouseover(e) {
+ if (document.getElementById("mouseoverID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function mousemove(e) {
+ if (document.getElementById("mousemoveID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function mouseout(e) {
+ if (document.getElementById("mouseoutID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function touchstart(e) {
+ if (document.getElementById("touchstartID").checked) {
+ var box = document.getElementById("box");
+ var result = inspect(e);
+ for (var i = 0; i < e.touches.length; i++) {
+ result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
+ }
+ log(e.type, result);
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function touchend(e) {
+ if (document.getElementById("touchendID").checked) {
+ var box = document.getElementById("box");
+ var result = inspect(e);
+ for (var i = 0; i < e.touches.length; i++) {
+ result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
+ }
+ log(e.type, result);
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function touchmove(e) {
+ if (document.getElementById("touchmoveID").checked) {
+ var targetEvent = e.touches.item(0);
+ var box = document.getElementById("box");
+ box.style.left = targetEvent.clientX + "px";
+ box.style.top = targetEvent.clientY + "px";
+ var result = inspect(e);
+ for (var i = 0; i < e.touches.length; i++) {
+ result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
+ }
+ log(e.type, result);
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function touchcancel(e) {
+ if (document.getElementById("touchcancelID").checked) {
+ var box = document.getElementById("box");
+ var result = inspect(e);
+ for (var i = 0; i < e.touches.length; i++) {
+ result = result + " Touches nr." + i + " " + inspect(e.touches[i]);
+ }
+ log(e.type, result);
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function gesturestart(e) {
+ if (document.getElementById("gesturestartID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function gesturechange(e) {
+ if (document.getElementById("gesturechangeID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function gestureend(e) {
+ if (document.getElementById("gestureendID").checked) {
+ var box = document.getElementById("box");
+ log(e.type, inspect(e));
+ if (e.preventDefault) e.preventDefault();
+ }
+ return false;
+}
+
+function toggle_visibility(id) {
+ var e = document.getElementById(id);
+ if (e.style.display == 'block') {
+ e.style.display = 'none';
+ } else {
+ e.style.display = 'block';
+ }
+}
+
+
+
diff --git a/src/geonode-client/app/static/externals/openlayers/examples/sos.html b/src/geonode-client/app/static/externals/openlayers/examples/sos.html
index 096d19d..4f2ccd5 100644
--- a/src/geonode-client/app/static/externals/openlayers/examples/sos.html
+++ b/src/geonode-client/app/static/externals/openlayers/examples/sos.html
@@ -1,189 +1,189 @@
-
-
-
-
-
-
- SOS Client Example
-
-
-
-
-
-
-
- SOS client example
-
-
- sos, sensor, observation, popup, advanced
-
-
- Shows how to connect OpenLayers to a Sensor Observation Service (SOS)
-
-
-
-
This example uses a vector layer with a Protocol.SOS and a fixed Strategy.
-
When clicking on a point feature (the weather stations offered by the SOS), the
- latest values for all offerings are displayed in a popup.
-
-
-
+
+
+
+
+
+
+ SOS Client Example
+
+
+
+
+
+
+
+ SOS client example
+
+
+ sos, sensor, observation, popup, advanced
+
+
+ Shows how to connect OpenLayers to a Sensor Observation Service (SOS)
+
+
+
+
This example uses a vector layer with a Protocol.SOS and a fixed Strategy.
+
When clicking on a point feature (the weather stations offered by the SOS), the
+ latest values for all offerings are displayed in a popup.
+
+
+
diff --git a/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js b/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js
index 3e10064..ca6e7df 100644
--- a/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js
+++ b/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js
@@ -1,128 +1,128 @@
-/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/WMSCapabilities/v1.js
- */
-
-/**
- * Class: OpenLayers.Format.WMSCapabilities/v1_3
- * Abstract base class for WMS Capabilities version 1.3.X.
- * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
- * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
- *
- * Inherits from:
- * -
- */
-OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(
- OpenLayers.Format.WMSCapabilities.v1, {
-
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {
- "wms": OpenLayers.Util.applyDefaults({
- "WMS_Capabilities": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "LayerLimit": function(node, obj) {
- obj.layerLimit = parseInt(this.getChildValue(node));
- },
- "MaxWidth": function(node, obj) {
- obj.maxWidth = parseInt(this.getChildValue(node));
- },
- "MaxHeight": function(node, obj) {
- obj.maxHeight = parseInt(this.getChildValue(node));
- },
- "BoundingBox": function(node, obj) {
- var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]);
- bbox.srs = node.getAttribute("CRS");
- obj.bbox[bbox.srs] = bbox;
- },
- "CRS": function(node, obj) {
- // CRS is the synonym of SRS
- this.readers.wms.SRS.apply(this, [node, obj]);
- },
- "EX_GeographicBoundingBox": function(node, obj) {
- // replacement of LatLonBoundingBox
- obj.llbbox = [];
- this.readChildNodes(node, obj.llbbox);
-
- },
- "westBoundLongitude": function(node, obj) {
- obj[0] = this.getChildValue(node);
- },
- "eastBoundLongitude": function(node, obj) {
- obj[2] = this.getChildValue(node);
- },
- "southBoundLatitude": function(node, obj) {
- obj[1] = this.getChildValue(node);
- },
- "northBoundLatitude": function(node, obj) {
- obj[3] = this.getChildValue(node);
- },
- "MinScaleDenominator": function(node, obj) {
- obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16);
- },
- "MaxScaleDenominator": function(node, obj) {
- obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16);
- },
- "Dimension": function(node, obj) {
- // dimension has extra attributes: default, multipleValues,
- // nearestValue, current which used to be part of Extent. It now
- // also contains the values.
- var name = node.getAttribute("name").toLowerCase();
- var dim = {
- name: name,
- units: node.getAttribute("units"),
- unitsymbol: node.getAttribute("unitSymbol"),
- nearestVal: node.getAttribute("nearestValue") === "1",
- multipleVal: node.getAttribute("multipleValues") === "1",
- "default": node.getAttribute("default") || "",
- current: node.getAttribute("current") === "1",
- values: this.getChildValue(node).split(",")
-
- };
- // Theoretically there can be more dimensions with the same
- // name, but with a different unit. Until we meet such a case,
- // let's just keep the same structure as the WMS 1.1
- // GetCapabilities parser uses. We will store the last
- // one encountered.
- obj.dimensions[dim.name] = dim;
- },
- "Keyword": function(node, obj) {
- // TODO: should we change the structure of keyword in v1.js?
- // Make it an object with a value instead of a string?
- var keyword = {value: this.getChildValue(node),
- vocabulary: node.getAttribute("vocabulary")};
- if (obj.keywords) {
- obj.keywords.push(keyword);
- }
- }
- }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]),
- "sld": {
- "UserDefinedSymbolization": function(node, obj) {
- this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]);
- // add the two extra attributes
- obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1;
- obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1;
- },
- "DescribeLayer": function(node, obj) {
- this.readers.wms.DescribeLayer.apply(this, [node, obj]);
- },
- "GetLegendGraphic": function(node, obj) {
- this.readers.wms.GetLegendGraphic.apply(this, [node, obj]);
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3"
-
-});
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_3
+ * Abstract base class for WMS Capabilities version 1.3.X.
+ * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
+ * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
+ *
+ * Inherits from:
+ * -
+ */
+OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(
+ OpenLayers.Format.WMSCapabilities.v1, {
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "wms": OpenLayers.Util.applyDefaults({
+ "WMS_Capabilities": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "LayerLimit": function(node, obj) {
+ obj.layerLimit = parseInt(this.getChildValue(node));
+ },
+ "MaxWidth": function(node, obj) {
+ obj.maxWidth = parseInt(this.getChildValue(node));
+ },
+ "MaxHeight": function(node, obj) {
+ obj.maxHeight = parseInt(this.getChildValue(node));
+ },
+ "BoundingBox": function(node, obj) {
+ var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]);
+ bbox.srs = node.getAttribute("CRS");
+ obj.bbox[bbox.srs] = bbox;
+ },
+ "CRS": function(node, obj) {
+ // CRS is the synonym of SRS
+ this.readers.wms.SRS.apply(this, [node, obj]);
+ },
+ "EX_GeographicBoundingBox": function(node, obj) {
+ // replacement of LatLonBoundingBox
+ obj.llbbox = [];
+ this.readChildNodes(node, obj.llbbox);
+
+ },
+ "westBoundLongitude": function(node, obj) {
+ obj[0] = this.getChildValue(node);
+ },
+ "eastBoundLongitude": function(node, obj) {
+ obj[2] = this.getChildValue(node);
+ },
+ "southBoundLatitude": function(node, obj) {
+ obj[1] = this.getChildValue(node);
+ },
+ "northBoundLatitude": function(node, obj) {
+ obj[3] = this.getChildValue(node);
+ },
+ "MinScaleDenominator": function(node, obj) {
+ obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16);
+ },
+ "MaxScaleDenominator": function(node, obj) {
+ obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16);
+ },
+ "Dimension": function(node, obj) {
+ // dimension has extra attributes: default, multipleValues,
+ // nearestValue, current which used to be part of Extent. It now
+ // also contains the values.
+ var name = node.getAttribute("name").toLowerCase();
+ var dim = {
+ name: name,
+ units: node.getAttribute("units"),
+ unitsymbol: node.getAttribute("unitSymbol"),
+ nearestVal: node.getAttribute("nearestValue") === "1",
+ multipleVal: node.getAttribute("multipleValues") === "1",
+ "default": node.getAttribute("default") || "",
+ current: node.getAttribute("current") === "1",
+ values: this.getChildValue(node).split(",")
+
+ };
+ // Theoretically there can be more dimensions with the same
+ // name, but with a different unit. Until we meet such a case,
+ // let's just keep the same structure as the WMS 1.1
+ // GetCapabilities parser uses. We will store the last
+ // one encountered.
+ obj.dimensions[dim.name] = dim;
+ },
+ "Keyword": function(node, obj) {
+ // TODO: should we change the structure of keyword in v1.js?
+ // Make it an object with a value instead of a string?
+ var keyword = {value: this.getChildValue(node),
+ vocabulary: node.getAttribute("vocabulary")};
+ if (obj.keywords) {
+ obj.keywords.push(keyword);
+ }
+ }
+ }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]),
+ "sld": {
+ "UserDefinedSymbolization": function(node, obj) {
+ this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]);
+ // add the two extra attributes
+ obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1;
+ obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1;
+ },
+ "DescribeLayer": function(node, obj) {
+ this.readers.wms.DescribeLayer.apply(this, [node, obj]);
+ },
+ "GetLegendGraphic": function(node, obj) {
+ this.readers.wms.GetLegendGraphic.apply(this, [node, obj]);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3"
+
+});
diff --git a/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js b/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js
index 82da245..063a3d5 100644
--- a/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js
+++ b/src/geonode-client/app/static/externals/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js
@@ -1,30 +1,30 @@
-/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/WMSCapabilities/v1_3.js
- */
-
-/**
- * Class: OpenLayers.Format.WMSCapabilities/v1_3_0
- * Read WMS Capabilities version 1.3.0.
- * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
- * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
- *
- * Inherits from:
- * -
- */
-OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(
- OpenLayers.Format.WMSCapabilities.v1_3, {
-
- /**
- * Property: version
- * {String} The specific parser version.
- */
- version: "1.3.0",
-
- CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0"
-
-});
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1_3.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_3_0
+ * Read WMS Capabilities version 1.3.0.
+ * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
+ * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
+ *
+ * Inherits from:
+ * -
+ */
+OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(
+ OpenLayers.Format.WMSCapabilities.v1_3, {
+
+ /**
+ * Property: version
+ * {String} The specific parser version.
+ */
+ version: "1.3.0",
+
+ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0"
+
+});
diff --git a/src/geonode-client/app/static/script/app/GeoExplorer/GeoExplorer.js b/src/geonode-client/app/static/script/app/GeoExplorer/GeoExplorer.js
index 1919d0c..6ead18c 100755
--- a/src/geonode-client/app/static/script/app/GeoExplorer/GeoExplorer.js
+++ b/src/geonode-client/app/static/script/app/GeoExplorer/GeoExplorer.js
@@ -198,6 +198,8 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
premiumSizeLabel: 'UT: Premium',
printTipText: "UT:Print Map",
printBtnText: "UT:Print",
+ infoActionText: "UT:About",
+ infoBtnText: "UT:About us",
printWindowTitleText: "UT:Print Preview",
propertiesText: "UT:Properties",
publishActionText: 'UT:Link To Map',
@@ -237,7 +239,8 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
worldmapDataText: 'Search',
externalDataText: 'External Data',
leavePageWarningText: 'If you leave this page, unsaved changes will be lost.',
-
+ cgaharvardText: 'Center for Geographic Analysis',
+ bdandcampText: 'Bigdata and CAMAP Innovation Team',
constructor: function(config) {
this.config = config;
this.popupCache = {};
@@ -265,6 +268,7 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
Ext.preg("gx_wmssource", gxp.plugins.WMSSource);
Ext.preg("gx_olsource", gxp.plugins.OLSource);
Ext.preg("gx_googlesource", gxp.plugins.GoogleSource);
+ Ext.preg("gx_tianditusource", gxp.plugins.TiandituSource);
Ext.preg("gx_gnsource", gxp.plugins.GeoNodeSource);
// global request proxy and error handling
@@ -1091,7 +1095,7 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
var record = records[i];
// add an existing layers
if ('uuid' in record.data){
- if (record.data['service_type'] == 'Hypermap:WorldMap'){
+ if (record.data['service_type'] == 'Hypermap:WorldMap2'){
this.addLayerAjax(wmSource, this.worldMapSourceKey, record);
} else {
url = this.hypermapRegistryUrl + '/registry/hypermap/layer/' + record.data['uuid'] + '/map/wmts/' + record.data['name'] + '/default_grid/${z}/${x}/${y}.png';
@@ -1153,12 +1157,14 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
"source": key,
"buffer": 0,
"tiled": true,
- "local": thisRecord.get('service_type') === 'Hypermap:WorldMap'
+ "local": thisRecord.get('service_type') === 'Hypermap:WorldMap2'
};
-
if (thisRecord.get('service_type') === 'Hypermap:WorldMap'){
layer_detail_url = 'http://worldmap.harvard.edu/data/' + thisRecord.get('name');
};
+ if (thisRecord.get('service_type') === 'Hypermap:WorldMap2'){
+ layer_detail_url = 'http://amap.zju.edu.cn:8000/data/' + thisRecord.get('name');
+ };
if(layer.local){
// url is always the generic GeoServer endpoint for WM layers
@@ -1404,7 +1410,11 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
*/
createMapOverlay: function() {
var cgaLink = new Ext.BoxComponent({
- html:''
+ html:''
+ });
+
+ var bdamapLink = new Ext.BoxComponent({
+ html:''
});
var scaleLinePanel = new Ext.BoxComponent({
@@ -1491,6 +1501,7 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
items: [
scaleLinePanel,
zoomSelectorWrapper,
+ bdamapLink,
cgaLink
]
});
@@ -1522,8 +1533,8 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
// create an info control to show introductory text window
var infoButton = new Ext.Button({
id: 'infoButtonId',
- tooltip: 'About',
- text: 'About ',
+ tooltip: this.infoActionText,
+ text: '' + this.infoBtnText + ' ',
handler: this.showInfoWindow,
scope:this
});
@@ -1659,8 +1670,6 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
{
xtype: "gx_linkembedmapdialog",
linkUrl: this.rest + (this.about["urlsuffix"] ? this.about["urlsuffix"] : this.mapID) + '/' + encodedSnapshotId,
- linkMessage: 'Paste link in email or IM: ',
- publishMessage: 'Paste HTML to embed in website: ',
url: this.rest + (this.about["urlsuffix"] ? this.about["urlsuffix"] : this.mapID) + '/' + encodedSnapshotId + "/embed"
}
]
@@ -1944,8 +1953,8 @@ var GeoExplorer = Ext.extend(gxp.Viewer, {
closeAction: 'hide',
items: this.infoTextPanel,
modal: true,
- width: 500,
- height:400,
+ width: 512,
+ height:215,
autoScroll: true
});
},
diff --git a/src/geonode-client/app/static/script/app/GeoExplorer/ogp/HeatmapLayer.js b/src/geonode-client/app/static/script/app/GeoExplorer/ogp/HeatmapLayer.js
index bc02aa2..b75b5df 100644
--- a/src/geonode-client/app/static/script/app/GeoExplorer/ogp/HeatmapLayer.js
+++ b/src/geonode-client/app/static/script/app/GeoExplorer/ogp/HeatmapLayer.js
@@ -1,301 +1,301 @@
-/*
- * Copyright (c) 2010 Bjoern Hoehrmann .
- * This module is licensed under the same terms as OpenLayers itself.
- *
- */
-
-Heatmap = {};
-
-/**
- * Class: Heatmap.Source
- */
-Heatmap.Source = OpenLayers.Class({
-
- /**
- * APIProperty: lonlat
- * {OpenLayers.LonLat} location of the heat source
- */
- lonlat: null,
-
- /**
- * APIProperty: radius
- * {Number} Heat source radius
- */
- radius: null,
-
- /**
- * APIProperty: intensity
- * {Number} Heat source intensity
- */
- intensity: null,
-
- /**
- * Constructor: Heatmap.Source
- * Create a heat source.
- *
- * Parameters:
- * lonlat - {OpenLayers.LonLat} Coordinates of the heat source
- * radius - {Number} Optional radius
- * intensity - {Number} Optional intensity
- */
- initialize: function(lonlat, radius, intensity) {
- this.lonlat = lonlat;
- this.radius = radius;
- this.intensity = intensity;
- },
-
- CLASS_NAME: 'Heatmap.Source'
-});
-
-/**
- * Class: Heatmap.Layer
- *
- * Inherits from:
- * -
- */
-Heatmap.Layer = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Heatmap layer is never a base layer.
- */
- isBaseLayer: false,
-
- /**
- * Property: points
- * {Array()} internal coordinate list
- */
- points: null,
-
- /**
- * Property: cache
- * {Object} Hashtable with CanvasGradient objects
- */
- cache: null,
-
- /**
- * Property: gradient
- * {Array(Number)} RGBA gradient map used to colorize the intensity map.
- */
- gradient: null,
-
- /**
- * Property: canvas
- * {DOMElement} Canvas element.
- */
- canvas: null,
-
- /**
- * APIProperty: defaultRadius
- * {Number} Heat source default radius
- */
- defaultRadius: null,
-
- /**
- * APIProperty: defaultIntensity
- * {Number} Heat source default intensity
- */
- defaultIntensity: null,
-
- /**
- * Constructor: Heatmap.Layer
- * Create a heatmap layer.
- *
- * Parameters:
- * name - {String} Name of the Layer
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
- this.points = [];
- this.cache = {};
- this.canvas = document.createElement('canvas');
- this.canvas.style.position = 'absolute';
- this.defaultRadius = 20;
- this.defaultIntensity = 0.2;
- this.setGradientStops({
- 0.00: 0xffffff00,
- 0.10: 0x99e9fdff,
- 0.20: 0x00c9fcff,
- 0.30: 0x00e9fdff,
- 0.30: 0x00a5fcff,
- 0.40: 0x0078f2ff,
- 0.50: 0x0e53e9ff,
- 0.60: 0x4a2cd9ff,
- 0.70: 0x890bbfff,
- 0.80: 0x99019aff,
- 0.90: 0x990664ff,
- 0.99: 0x660000ff,
- 1.00: 0x000000ff
- });
-
- // For some reason OpenLayers.Layer.setOpacity assumes there is
- // an additional div between the layer's div and its contents.
- var sub = document.createElement('div');
- sub.appendChild(this.canvas);
- this.div.appendChild(sub);
- },
-
- /**
- * APIMethod: setGradientStops
- * ...
- *
- * Parameters:
- * stops - {Object} Hashtable with stop position as keys and colors
- * as values. Stop positions are numbers between 0
- * and 1, color values numbers in 0xRRGGBBAA form.
- */
- setGradientStops: function(stops) {
-
- // There is no need to perform the linear interpolation manually,
- // it is sufficient to let the canvas implementation do that.
-
- var ctx = document.createElement('canvas').getContext('2d');
- var grd = ctx.createLinearGradient(0, 0, 256, 0);
-
- for (var i in stops) {
- grd.addColorStop(i, 'rgba(' +
- ((stops[i] >> 24) & 0xFF) + ',' +
- ((stops[i] >> 16) & 0xFF) + ',' +
- ((stops[i] >> 8) & 0xFF) + ',' +
- ((stops[i] >> 0) & 0xFF) + ')');
- }
-
- ctx.fillStyle = grd;
- ctx.fillRect(0, 0, 256, 1);
- this.gradient = ctx.getImageData(0, 0, 256, 1).data;
- },
-
- /**
- * APIMethod: addSource
- * Adds a heat source to the layer.
- *
- * Parameters:
- * source - {}
- */
- addSource: function(source) {
- this.points.push(source);
- },
-
- /**
- * APIMethod: removeSource
- * Removes a heat source from the layer.
- *
- * Parameters:
- * source - {}
- */
- removeSource: function(source) {
- if (this.points && this.points.length) {
- OpenLayers.Util.removeItem(this.points, source);
- }
- },
-
- /**
- * Method: moveTo
- *
- * Parameters:
- * bounds - {}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo: function(bounds, zoomChanged, dragging) {
-
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
- // The code is too slow to update the rendering during dragging.
- if (dragging)
- return;
-
- // Pick some point on the map and use it to determine the offset
- // between the map's 0,0 coordinate and the layer's 0,0 position.
- var someLoc = new OpenLayers.LonLat(0,0);
- var offsetX = this.map.getViewPortPxFromLonLat(someLoc).x -
- this.map.getLayerPxFromLonLat(someLoc).x;
- var offsetY = this.map.getViewPortPxFromLonLat(someLoc).y -
- this.map.getLayerPxFromLonLat(someLoc).y;
-
- this.canvas.width = this.map.getSize().w;
- this.canvas.height = this.map.getSize().h;
-
- var ctx = this.canvas.getContext('2d');
-
- ctx.save(); // Workaround for a bug in Google Chrome
- ctx.fillStyle = 'transparent';
- ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
- ctx.restore();
-
- for (var i=0;i}
- */
- getDataExtent: function () {
- var maxExtent = null;
-
- if (this.points && (this.points.length > 0)) {
- var maxExtent = new OpenLayers.Bounds();
- for(var i = 0, len = this.points.length; i < len; ++i) {
- var point = this.points[i];
- maxExtent.extend(point.lonlat);
- }
- }
-
- return maxExtent;
- },
-
- CLASS_NAME: 'Heatmap.Layer'
-
-});
+/*
+ * Copyright (c) 2010 Bjoern Hoehrmann .
+ * This module is licensed under the same terms as OpenLayers itself.
+ *
+ */
+
+Heatmap = {};
+
+/**
+ * Class: Heatmap.Source
+ */
+Heatmap.Source = OpenLayers.Class({
+
+ /**
+ * APIProperty: lonlat
+ * {OpenLayers.LonLat} location of the heat source
+ */
+ lonlat: null,
+
+ /**
+ * APIProperty: radius
+ * {Number} Heat source radius
+ */
+ radius: null,
+
+ /**
+ * APIProperty: intensity
+ * {Number} Heat source intensity
+ */
+ intensity: null,
+
+ /**
+ * Constructor: Heatmap.Source
+ * Create a heat source.
+ *
+ * Parameters:
+ * lonlat - {OpenLayers.LonLat} Coordinates of the heat source
+ * radius - {Number} Optional radius
+ * intensity - {Number} Optional intensity
+ */
+ initialize: function(lonlat, radius, intensity) {
+ this.lonlat = lonlat;
+ this.radius = radius;
+ this.intensity = intensity;
+ },
+
+ CLASS_NAME: 'Heatmap.Source'
+});
+
+/**
+ * Class: Heatmap.Layer
+ *
+ * Inherits from:
+ * -
+ */
+Heatmap.Layer = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Heatmap layer is never a base layer.
+ */
+ isBaseLayer: false,
+
+ /**
+ * Property: points
+ * {Array()} internal coordinate list
+ */
+ points: null,
+
+ /**
+ * Property: cache
+ * {Object} Hashtable with CanvasGradient objects
+ */
+ cache: null,
+
+ /**
+ * Property: gradient
+ * {Array(Number)} RGBA gradient map used to colorize the intensity map.
+ */
+ gradient: null,
+
+ /**
+ * Property: canvas
+ * {DOMElement} Canvas element.
+ */
+ canvas: null,
+
+ /**
+ * APIProperty: defaultRadius
+ * {Number} Heat source default radius
+ */
+ defaultRadius: null,
+
+ /**
+ * APIProperty: defaultIntensity
+ * {Number} Heat source default intensity
+ */
+ defaultIntensity: null,
+
+ /**
+ * Constructor: Heatmap.Layer
+ * Create a heatmap layer.
+ *
+ * Parameters:
+ * name - {String} Name of the Layer
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, options) {
+ OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+ this.points = [];
+ this.cache = {};
+ this.canvas = document.createElement('canvas');
+ this.canvas.style.position = 'absolute';
+ this.defaultRadius = 20;
+ this.defaultIntensity = 0.2;
+ this.setGradientStops({
+ 0.00: 0xffffff00,
+ 0.10: 0x99e9fdff,
+ 0.20: 0x00c9fcff,
+ 0.30: 0x00e9fdff,
+ 0.30: 0x00a5fcff,
+ 0.40: 0x0078f2ff,
+ 0.50: 0x0e53e9ff,
+ 0.60: 0x4a2cd9ff,
+ 0.70: 0x890bbfff,
+ 0.80: 0x99019aff,
+ 0.90: 0x990664ff,
+ 0.99: 0x660000ff,
+ 1.00: 0x000000ff
+ });
+
+ // For some reason OpenLayers.Layer.setOpacity assumes there is
+ // an additional div between the layer's div and its contents.
+ var sub = document.createElement('div');
+ sub.appendChild(this.canvas);
+ this.div.appendChild(sub);
+ },
+
+ /**
+ * APIMethod: setGradientStops
+ * ...
+ *
+ * Parameters:
+ * stops - {Object} Hashtable with stop position as keys and colors
+ * as values. Stop positions are numbers between 0
+ * and 1, color values numbers in 0xRRGGBBAA form.
+ */
+ setGradientStops: function(stops) {
+
+ // There is no need to perform the linear interpolation manually,
+ // it is sufficient to let the canvas implementation do that.
+
+ var ctx = document.createElement('canvas').getContext('2d');
+ var grd = ctx.createLinearGradient(0, 0, 256, 0);
+
+ for (var i in stops) {
+ grd.addColorStop(i, 'rgba(' +
+ ((stops[i] >> 24) & 0xFF) + ',' +
+ ((stops[i] >> 16) & 0xFF) + ',' +
+ ((stops[i] >> 8) & 0xFF) + ',' +
+ ((stops[i] >> 0) & 0xFF) + ')');
+ }
+
+ ctx.fillStyle = grd;
+ ctx.fillRect(0, 0, 256, 1);
+ this.gradient = ctx.getImageData(0, 0, 256, 1).data;
+ },
+
+ /**
+ * APIMethod: addSource
+ * Adds a heat source to the layer.
+ *
+ * Parameters:
+ * source - {}
+ */
+ addSource: function(source) {
+ this.points.push(source);
+ },
+
+ /**
+ * APIMethod: removeSource
+ * Removes a heat source from the layer.
+ *
+ * Parameters:
+ * source - {}
+ */
+ removeSource: function(source) {
+ if (this.points && this.points.length) {
+ OpenLayers.Util.removeItem(this.points, source);
+ }
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * bounds - {}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo: function(bounds, zoomChanged, dragging) {
+
+ OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+ // The code is too slow to update the rendering during dragging.
+ if (dragging)
+ return;
+
+ // Pick some point on the map and use it to determine the offset
+ // between the map's 0,0 coordinate and the layer's 0,0 position.
+ var someLoc = new OpenLayers.LonLat(0,0);
+ var offsetX = this.map.getViewPortPxFromLonLat(someLoc).x -
+ this.map.getLayerPxFromLonLat(someLoc).x;
+ var offsetY = this.map.getViewPortPxFromLonLat(someLoc).y -
+ this.map.getLayerPxFromLonLat(someLoc).y;
+
+ this.canvas.width = this.map.getSize().w;
+ this.canvas.height = this.map.getSize().h;
+
+ var ctx = this.canvas.getContext('2d');
+
+ ctx.save(); // Workaround for a bug in Google Chrome
+ ctx.fillStyle = 'transparent';
+ ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
+ ctx.restore();
+
+ for (var i=0;i}
+ */
+ getDataExtent: function () {
+ var maxExtent = null;
+
+ if (this.points && (this.points.length > 0)) {
+ var maxExtent = new OpenLayers.Bounds();
+ for(var i = 0, len = this.points.length; i < len; ++i) {
+ var point = this.points[i];
+ maxExtent.extend(point.lonlat);
+ }
+ }
+
+ return maxExtent;
+ },
+
+ CLASS_NAME: 'Heatmap.Layer'
+
+});
diff --git a/src/geonode-client/app/static/script/app/GeoNode/ogp/SearchTableSolr.js b/src/geonode-client/app/static/script/app/GeoNode/ogp/SearchTableSolr.js
index 0592ca6..eae72c3 100755
--- a/src/geonode-client/app/static/script/app/GeoNode/ogp/SearchTableSolr.js
+++ b/src/geonode-client/app/static/script/app/GeoNode/ogp/SearchTableSolr.js
@@ -23,7 +23,10 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
originatorSearchLabelText: 'Source',
dataTypeSearchLableText: 'UT: Data Type',
originatorText: 'Source',
-
+ dateHeaderText: 'Date',
+ fromyearHeaderText: 'from year',
+ toyearHeaderText: 'to year',
+ resetButtonText: 'Reset',
searchOnLoad: false,
linkableTitle: true,
@@ -244,9 +247,11 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
if (this.queryInput.getValue() === ''){
GeoNode.queryTerms.q = '*';
}
+ else{
+ GeoNode.queryTerms.q = '*' + this.queryInput.getValue() + '*';
+ }
GeoNode.queryTerms.start = 0;
-
// now trigger the heatmap update
this.heatmap.fireEvent('fireSearch', false);
@@ -356,7 +361,7 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
sortable: true
},
{
- header: 'Date',
+ header: this.dateHeaderText,
id: 'date',
width: 50,
sortable: true,
@@ -414,6 +419,7 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
layers_data = [
['', 'All Layers'],
+ ['service_type:"Hypermap:WorldMap2"', 'AcadamicMap Layers'],
['service_type:"Hypermap:WorldMap"', 'WorldMap Layers'],
['service_type:"OGC:WMS"', 'WMS'],
['service_type:"ESRI:ArcGIS:ImageServer"', 'ESRI Image'],
@@ -490,7 +496,7 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
});
this.dateLabelPanel = new Ext.Panel({
- items: [new Ext.form.Label({text: 'from year'}), dateStartTextField, new Ext.form.Label({text: 'to year'}), dateEndTextField],
+ items: [new Ext.form.Label({text: this.fromyearHeaderText}), dateStartTextField, new Ext.form.Label({text: this.toyearHeaderText}), dateEndTextField],
cls: 'search-bar date-form'
});
@@ -518,7 +524,7 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
searchButton.on('click', this.updateQuery, this);
var clearSearchLink = new Ext.Button({
- text: "Reset",
+ text: this.resetButtonText,
iconCls: 'not-prominent-btn',
cls: 'search-bar clear-search-button',
listeners: {
@@ -546,8 +552,8 @@ GeoNode.SearchTable = Ext.extend(Ext.util.Observable, {
this.queryInput,
this.originatorInput,
this.dataTypeInput, //dropdown
- searchButton,
- clearSearchLink
+ clearSearchLink,
+ searchButton
],
colspan: 4
},{
diff --git a/src/geonode-client/app/static/script/app/GeoNode/ogp/ogpConfig.js b/src/geonode-client/app/static/script/app/GeoNode/ogp/ogpConfig.js
index 4d54cc2..0300254 100644
--- a/src/geonode-client/app/static/script/app/GeoNode/ogp/ogpConfig.js
+++ b/src/geonode-client/app/static/script/app/GeoNode/ogp/ogpConfig.js
@@ -7,7 +7,7 @@ $(document).ready(function () {
sort: "score desc",
//qf: "LayerTitleSynonyms^0.2 ThemeKeywordsSynonymsIso^0.1 ThemeKeywordsSynonymsLcsh^0.1 PlaceKeywordsSynonyms^0.1 Publisher^0.1 layer_originator^0.1 Abstract^0.2",
fl: "id, uuid, name, title, abstract, min_x, min_y, max_x, max_y, layer_originator, is_public, url, service_type, bbox, location, layer_datetype, srs",
- qf: "title_txt^1 abstract_txt^0.2 originator_txt layer_username",
+ qf: "title^1 abstract^0.2 layer_originator^1 layer_datetype^0.2",
wt: "json",
defType: "edismax",
q: "*",
diff --git a/src/geonode-client/app/static/theme/app/geoexplorer.css b/src/geonode-client/app/static/theme/app/geoexplorer.css
index ba2551d..cecb231 100755
--- a/src/geonode-client/app/static/theme/app/geoexplorer.css
+++ b/src/geonode-client/app/static/theme/app/geoexplorer.css
@@ -1,537 +1,537 @@
-/* do wrap lines on any tooltips */
-.x-tip {
-}
-
-/* get images on buttons with text to line up with those with no text */
-.x-btn-text-icon .x-btn-center .x-btn-text {
- background-position: 0 3px;
-}
-
-/* apply some margin when using the row expander */
-.x-grid3-row-body p {
- margin: 5px !important;
-}
-
-/* workaround for semi-alpha pixels in IE7: background needs to be the same
- * as the toolbar's background color */
-.ext-ie .x-item-disabled .x-btn-text {
- background-color: #EAEAEA;
-}
-
-.x-tree-node-leaf .gx-tree-layer-icon {
- background-image: url(img/geosilk/vector.png);
-}
-
-.x-tree-node-leaf .gx-tree-rasterlayer-icon {
- background-image: url(img/geosilk/raster.png);
-}
-
-.x-menu-group-item .x-menu-item-icon {
- background: transparent url(../../externals/ext/resources/images/default/form/radio.gif) no-repeat 0 0;
- height: 13px;
- width: 13px;
- margin: 2px;
-}
-
-.x-menu-item-checked .x-menu-group-item .x-menu-item-icon {
- background: transparent url(../../externals/ext/resources/images/default/form/radio.gif) no-repeat -13px -13px;
- height: 13px;
- width: 13px;
- margin: 2px;
-}
-
-.x-btn .icon-geoexplorer {
- background-image: url(img/geoexplorer.png);
-}
-
-.x-btn .icon-addlayers {
- background-image: url(img/silk/add.png);
-}
-
-.x-btn .icon-removelayers, .x-menu-item .icon-removelayers {
- background-image: url(img/silk/delete.png);
-}
-
-.x-btn .icon-layerproperties, .x-menu-item .icon-layerproperties {
- background-image: url(img/silk/wrench.png);
-}
-
-.x-btn .icon-layerstyles, .x-menu-item .icon-layerstyles {
- background-image: url(img/silk/palette.png);
-}
-
-.x-btn .icon-getfeatureinfo {
- background-image: url(img/silk/information.png);
-}
-
-.x-btn .icon-3D {
- background-image: url(img/geosilk/google_earth.png);
-}
-
-.x-btn .icon-save {
- background-image: url(img/geosilk/map_save.png);
-}
-
-/* Really for CAPRA, watch out! */
-
-.x-menu-group-item .icon-point,
-.x-btn .icon-point {
- background: transparent url(img/geosilk/bullet_orange.png) no-repeat center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-menu-group-item .icon-line,
-.x-btn .icon-line {
- background: transparent url(img/geosilk/line_orange.png) no-repeat center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-menu-group-item .icon-polygon,
-.x-btn .icon-polygon {
- background: transparent url(img/geosilk/shape_square_orange.png) center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-btn .icon-visibility {
- background-image: url(img/silk/eye.png);
-}
-
-.x-btn .icon-pdf {
- background-image: url(img/silk/page_white_acrobat.png);
-}
-
-div.report {
- background-color: white;
- height: 100%;
-}
-
-div.report table, div.report td, div.report th {
- padding: .4em;
-}
-
-div.report th {
- background-color: #CCC;
-}
-
-div.report tr.odd {
- background-color: #EEF;
-}
-
-.report td.corner{
- background-color:white;
-}
-
-
-/* ------------ */
-
-.x-btn .icon-export {
- background-image: url(img/silk/map_go.png);
-}
-.x-btn .icon-measure {
- background-image: url(img/geosilk/measure.png);
-}
-
-.icon-measure-length {
- background-image: url(img/geosilk/ruler.png) !important;
-}
-
-.icon-measure-area {
- background: url(img/geosilk/ruler_square.png) no-repeat 0 0 !important;
- margin: 0 !important;
- width: 16px !important;
- height: 16px !important;
-}
-
-.x-btn .icon-layer-switcher {
- background-image: url(img/silk/layers.png);
-}
-
-.x-btn .icon-zoom-in {
- background-image: url(img/silk/magnifier_zoom_in.png);
-}
-
-.x-btn .icon-zoom-out {
- background-image: url(img/silk/magnifier_zoom_out.png);
-}
-
-.x-btn .icon-zoom-previous {
- background-image: url(img/silk/arrow_left.png);
-}
-
-.x-btn .icon-zoom-next {
- background-image: url(img/silk/arrow_right.png);
-}
-
-.x-btn .icon-zoom-visible, .x-menu-item .icon-zoom-visible {
- background-image: url(img/silk/arrow_out.png);
-}
-
-.x-btn .icon-zoom-to, .x-menu-item .icon-zoom-to {
- background-image: url(img/silk/magnifier.png);
-}
-
-.x-btn .icon-pan {
- background-image: url(img/geosilk/pan.png);
-}
-
-.legend-item {
- margin: 0.5em 10px;
-}
-
-div.map-overlay {
- z-index: 4000;
- position: absolute;
- right: 10px;
- bottom: 10px;
- background:transparent;
-}
-
-div.map-overlay div.overlay-element {
- display:inline;
- float: left;
- margin: 5px;
- background:transparent;
-}
-
-div.overlay-scaleline {
- bottom: 0px;
- left: 0px;
- margin-top: 0px;
- z-index: 10000;
-}
-
-.olControlAttribution{
- color: gray;
- bottom: .5em;
- left: .4em;
- right: 220px;
- font-size: smaller;
-}
-
-.olControlScaleLineTop,
-.olControlScaleLineBottom {
- font-size:10px;
-}
-
-/* Pan- and Zoom- Panel Styles*/
-
-.olControlPanPanel div {
- background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
- height:15px;
- width:15px;
- /* workaround for button height in IE */
- font-size:0px;
-}
-
-.olControlPanPanel .olControlPanNorthItemInactive {
- background-position:15px -60px;
- left:16px
-}
-.olControlPanPanel .olControlPanEastItemInactive {
- background-position:15px -120px;
- left: 30px;
- top: 16px;
-}
-.olControlPanPanel .olControlPanSouthItemInactive {
- background-position:15px -75px;
- left: 16px;
- top: 32px;
-}
-.olControlPanPanel .olControlPanWestItemInactive {
- background-position:15px -105px;
- left: 2px;
- top: 16px;
-}
-
-.olControlZoomPanel {
- left:21px;
-}
-
-.olControlZoomPanel div {
- background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
- height:15px;
- width:15px;
- /* workaround for button height in IE */
- font-size:0px;
-}
-
-.olControlZoomPanel .olControlZoomInItemInactive {
- background-position:15px -240px;
-}
-
-.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
- display: none;
-}
-
-.olControlZoomPanel .olControlZoomOutItemInactive {
- background-position:15px -255px;
- top: 123px;
-}
-
-.olControlScaleLine {
- line-height: 10px;
- display: block;
- position: relative;
- font-family: tahoma,arial,helvetica,sans-serif;
-}
-
-/* position the zoom slider within map panel */
-.gx-zoomslider {
- top: 90px;
- left: 17px
-}
-
-
-.gx-layer-menu {
- background: #F0F0F0;
-}
-
-.gx-field-label {
- font-weight: bold;
- margin: 4px;
- vertical-align: baseline;
-}
-
-.gx-snippet-area textarea {
- color: black;
- opacity: 1;
-}
-
-.gx-info-panel {
- margin: 1em;
-}
-
-.gx-info-panel h2 {
- margin-top: 1em;
-}
-
-.gx-wizard-description p {
- margin: 4px auto;
- background: none;
-}
-
-.gx-wizard-pane {
- padding: 4px;
-}
-
-.gx-grid-true {
- background: red;
-}
-
-.gx-grid-false {
- background: blue;
-}
-
-.gx-wizard-active button {
- font-weight: bold;
-}
-
-.gx-wizard-pane .x-panel-body {
- background: none;
-}
-
-.gx-wizard-pane .x-grid3-dirty-cell {
- background-image: none;
-}
-
-.gx-layer-visibility {
- background-image: url(img/silk/eye.png);
- width: 16px;
- height: 16px;
- display: block;
-}
-
-.error-details {
- font: 8pt courier,courier new,monospace;
- padding: 5px;
-}
-
-.user_item button {
- width: 16px;
- height: 16px;
- margin: 4px;
-}
-
-#more-info{
- float:right;
-}
-
-/* gxp overrides for different folder structure */
-.olControlZoomPanel div {
- background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
-}
-.x-tree-node img.gxp-folder, .x-tree-node-collapsed img.gxp-folder{
- background: url(../../externals/ext/resources/images/default/tree/folder.gif);
-}
-.x-tree-node-expanded img.gxp-folder {
- background: url(../../externals/ext/resources/images/default/tree/folder-open.gif);
-}
-
-.olLayerGoogleV3.olLayerGoogleCopyright {
- bottom: 1em !important;
-}
-.olLayerGoogleV3.olLayerGooglePoweredBy {
- bottom: 2em !important;
-}
-
-/* WorldMap additions/modifications */
-
-.x-btn-text {
- font-size: 8pt;
- text-decoration: underline;
- color: #18469C;
- padding-right:5px;
- border-right: 1px solid #99BBE8;
-}
-
-.x-btn-text button {
- font-size: 8pt;
- text-decoration: underline;
- color: #18469C;
-}
-
-.x-btn-link-medium {
- text-decoration:underline;
- float:right;
- text-align:right;
-}
-
-.x-btn .icon-add, .x-menu-item .icon-add {
- background-image: url(img/silk/add.png);
-}
-
-
-.x-span-font-eight {
- font-size: 8pt;
-}
-
-.x-form-field-inline {
- display:inline;
- padding:0 0 30px 0;
- margin:0px;
-}
-
-.transparent-panel {
- background:transparent;
-}
-
-cga-logo-overlay {
- z-index: 10000;
- position: absolute;
- left: 100px;
- bottom: 10px;
- width:151px;
- height:39px;
- background: transparent;
-}
-
-.more-overlay-element {
- float: left;
- z-index: 4000;
- position: absolute;
- right: 150px;
- top: 10px;
- height:25px;
- width:50px;
- background: #FFF;
- text-decoration: none;
- border: 1px solid #000;
-}
-
-.more-overlay-element .x-btn-small td {background-image: none; text-decoration:none;}
-.more-overlay-element .x-btn-small td button {text-decoration:none;}
-
-.language-overlay-element {
- float: left;
- z-index: 4000;
- position: absolute;
- right: 10px;
- bottom: 70px;
- height:25px;
- text-decoration: none;
-}
-
-div.cga-link {
- margin:3px;
- font-size:8pt;
- clear: both;
-}
-
-.featureDetailList {
-}
-.featureDetailList li {
- margin:4px 5px;
- min-height:16px;
- position:relative;
-}
-* html .featureDetailList li {
- height:16px;
-}
-.featureDetailList li label {
- font-weight:bold;
- left:0;
- position:absolute;
- top:0;
- width:150px;
-}
-.featureDetailList li span {
- margin-left:160px;
-}
-
-.nicEdit-selected {
- border: 2px solid #0000ff !important;
-}
-
-.nicEdit-panel {
- background-color: #fff !important;
-}
-
-.nicEdit-button {
- background-color: #fff !important;
-}
-
-.wtf {
- padding: 0px 10px 0px 10px;
- border-right: 1px solid #000;
-}
-
-div.cql-overlay {
- z-index: 10000;
- position: absolute;
- margin: 0 15%;
- background:#FFF;
- opacity: 0.9
-}
-
-div.chart-overlay {
- z-index: 10000;
- position: absolute;
- //left: 10px;
- bottom: 10px;
- margin: 0 15%;
- background:#FFF;
- opacity: 1.0
-}
-
-.icon-picasa {
- background-image: url('img/picasa.png');
-}
-
-.icon-youtube {
- background-image: url('img/youtube.png');
-}
-
-
-.icon-harvard {
- background-image: url('img/harvard.png');
-}
-
-.icon-flickr {
- background-image: url('img/flickr.png');
+/* do wrap lines on any tooltips */
+.x-tip {
+}
+
+/* get images on buttons with text to line up with those with no text */
+.x-btn-text-icon .x-btn-center .x-btn-text {
+ background-position: 0 3px;
+}
+
+/* apply some margin when using the row expander */
+.x-grid3-row-body p {
+ margin: 5px !important;
+}
+
+/* workaround for semi-alpha pixels in IE7: background needs to be the same
+ * as the toolbar's background color */
+.ext-ie .x-item-disabled .x-btn-text {
+ background-color: #EAEAEA;
+}
+
+.x-tree-node-leaf .gx-tree-layer-icon {
+ background-image: url(img/geosilk/vector.png);
+}
+
+.x-tree-node-leaf .gx-tree-rasterlayer-icon {
+ background-image: url(img/geosilk/raster.png);
+}
+
+.x-menu-group-item .x-menu-item-icon {
+ background: transparent url(../../externals/ext/resources/images/default/form/radio.gif) no-repeat 0 0;
+ height: 13px;
+ width: 13px;
+ margin: 2px;
+}
+
+.x-menu-item-checked .x-menu-group-item .x-menu-item-icon {
+ background: transparent url(../../externals/ext/resources/images/default/form/radio.gif) no-repeat -13px -13px;
+ height: 13px;
+ width: 13px;
+ margin: 2px;
+}
+
+.x-btn .icon-geoexplorer {
+ background-image: url(img/geoexplorer.png);
+}
+
+.x-btn .icon-addlayers {
+ background-image: url(img/silk/add.png);
+}
+
+.x-btn .icon-removelayers, .x-menu-item .icon-removelayers {
+ background-image: url(img/silk/delete.png);
+}
+
+.x-btn .icon-layerproperties, .x-menu-item .icon-layerproperties {
+ background-image: url(img/silk/wrench.png);
+}
+
+.x-btn .icon-layerstyles, .x-menu-item .icon-layerstyles {
+ background-image: url(img/silk/palette.png);
+}
+
+.x-btn .icon-getfeatureinfo {
+ background-image: url(img/silk/information.png);
+}
+
+.x-btn .icon-3D {
+ background-image: url(img/geosilk/google_earth.png);
+}
+
+.x-btn .icon-save {
+ background-image: url(img/geosilk/map_save.png);
+}
+
+/* Really for CAPRA, watch out! */
+
+.x-menu-group-item .icon-point,
+.x-btn .icon-point {
+ background: transparent url(img/geosilk/bullet_orange.png) no-repeat center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-menu-group-item .icon-line,
+.x-btn .icon-line {
+ background: transparent url(img/geosilk/line_orange.png) no-repeat center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-menu-group-item .icon-polygon,
+.x-btn .icon-polygon {
+ background: transparent url(img/geosilk/shape_square_orange.png) center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-btn .icon-visibility {
+ background-image: url(img/silk/eye.png);
+}
+
+.x-btn .icon-pdf {
+ background-image: url(img/silk/page_white_acrobat.png);
+}
+
+div.report {
+ background-color: white;
+ height: 100%;
+}
+
+div.report table, div.report td, div.report th {
+ padding: .4em;
+}
+
+div.report th {
+ background-color: #CCC;
+}
+
+div.report tr.odd {
+ background-color: #EEF;
+}
+
+.report td.corner{
+ background-color:white;
+}
+
+
+/* ------------ */
+
+.x-btn .icon-export {
+ background-image: url(img/silk/map_go.png);
+}
+.x-btn .icon-measure {
+ background-image: url(img/geosilk/measure.png);
+}
+
+.icon-measure-length {
+ background-image: url(img/geosilk/ruler.png) !important;
+}
+
+.icon-measure-area {
+ background: url(img/geosilk/ruler_square.png) no-repeat 0 0 !important;
+ margin: 0 !important;
+ width: 16px !important;
+ height: 16px !important;
+}
+
+.x-btn .icon-layer-switcher {
+ background-image: url(img/silk/layers.png);
+}
+
+.x-btn .icon-zoom-in {
+ background-image: url(img/silk/magnifier_zoom_in.png);
+}
+
+.x-btn .icon-zoom-out {
+ background-image: url(img/silk/magnifier_zoom_out.png);
+}
+
+.x-btn .icon-zoom-previous {
+ background-image: url(img/silk/arrow_left.png);
+}
+
+.x-btn .icon-zoom-next {
+ background-image: url(img/silk/arrow_right.png);
+}
+
+.x-btn .icon-zoom-visible, .x-menu-item .icon-zoom-visible {
+ background-image: url(img/silk/arrow_out.png);
+}
+
+.x-btn .icon-zoom-to, .x-menu-item .icon-zoom-to {
+ background-image: url(img/silk/magnifier.png);
+}
+
+.x-btn .icon-pan {
+ background-image: url(img/geosilk/pan.png);
+}
+
+.legend-item {
+ margin: 0.5em 10px;
+}
+
+div.map-overlay {
+ z-index: 4000;
+ position: absolute;
+ right: 10px;
+ bottom: 10px;
+ background:transparent;
+}
+
+div.map-overlay div.overlay-element {
+ display:inline;
+ float: left;
+ margin: 5px;
+ background:transparent;
+}
+
+div.overlay-scaleline {
+ bottom: 0px;
+ left: 0px;
+ margin-top: 0px;
+ z-index: 10000;
+}
+
+.olControlAttribution{
+ color: gray;
+ bottom: .5em;
+ left: .4em;
+ right: 220px;
+ font-size: smaller;
+}
+
+.olControlScaleLineTop,
+.olControlScaleLineBottom {
+ font-size:10px;
+}
+
+/* Pan- and Zoom- Panel Styles*/
+
+.olControlPanPanel div {
+ background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
+ height:15px;
+ width:15px;
+ /* workaround for button height in IE */
+ font-size:0px;
+}
+
+.olControlPanPanel .olControlPanNorthItemInactive {
+ background-position:15px -60px;
+ left:16px
+}
+.olControlPanPanel .olControlPanEastItemInactive {
+ background-position:15px -120px;
+ left: 30px;
+ top: 16px;
+}
+.olControlPanPanel .olControlPanSouthItemInactive {
+ background-position:15px -75px;
+ left: 16px;
+ top: 32px;
+}
+.olControlPanPanel .olControlPanWestItemInactive {
+ background-position:15px -105px;
+ left: 2px;
+ top: 16px;
+}
+
+.olControlZoomPanel {
+ left:21px;
+}
+
+.olControlZoomPanel div {
+ background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
+ height:15px;
+ width:15px;
+ /* workaround for button height in IE */
+ font-size:0px;
+}
+
+.olControlZoomPanel .olControlZoomInItemInactive {
+ background-position:15px -240px;
+}
+
+.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
+ display: none;
+}
+
+.olControlZoomPanel .olControlZoomOutItemInactive {
+ background-position:15px -255px;
+ top: 123px;
+}
+
+.olControlScaleLine {
+ line-height: 10px;
+ display: block;
+ position: relative;
+ font-family: tahoma,arial,helvetica,sans-serif;
+}
+
+/* position the zoom slider within map panel */
+.gx-zoomslider {
+ top: 90px;
+ left: 17px
+}
+
+
+.gx-layer-menu {
+ background: #F0F0F0;
+}
+
+.gx-field-label {
+ font-weight: bold;
+ margin: 4px;
+ vertical-align: baseline;
+}
+
+.gx-snippet-area textarea {
+ color: black;
+ opacity: 1;
+}
+
+.gx-info-panel {
+ margin: 1em;
+}
+
+.gx-info-panel h2 {
+ margin-top: 1em;
+}
+
+.gx-wizard-description p {
+ margin: 4px auto;
+ background: none;
+}
+
+.gx-wizard-pane {
+ padding: 4px;
+}
+
+.gx-grid-true {
+ background: red;
+}
+
+.gx-grid-false {
+ background: blue;
+}
+
+.gx-wizard-active button {
+ font-weight: bold;
+}
+
+.gx-wizard-pane .x-panel-body {
+ background: none;
+}
+
+.gx-wizard-pane .x-grid3-dirty-cell {
+ background-image: none;
+}
+
+.gx-layer-visibility {
+ background-image: url(img/silk/eye.png);
+ width: 16px;
+ height: 16px;
+ display: block;
+}
+
+.error-details {
+ font: 8pt courier,courier new,monospace;
+ padding: 5px;
+}
+
+.user_item button {
+ width: 16px;
+ height: 16px;
+ margin: 4px;
+}
+
+#more-info{
+ float:right;
+}
+
+/* gxp overrides for different folder structure */
+.olControlZoomPanel div {
+ background-image:url(../../externals/ext/resources/images/gray/panel/tool-sprites.gif);
+}
+.x-tree-node img.gxp-folder, .x-tree-node-collapsed img.gxp-folder{
+ background: url(../../externals/ext/resources/images/default/tree/folder.gif);
+}
+.x-tree-node-expanded img.gxp-folder {
+ background: url(../../externals/ext/resources/images/default/tree/folder-open.gif);
+}
+
+.olLayerGoogleV3.olLayerGoogleCopyright {
+ bottom: 1em !important;
+}
+.olLayerGoogleV3.olLayerGooglePoweredBy {
+ bottom: 2em !important;
+}
+
+/* WorldMap additions/modifications */
+
+.x-btn-text {
+ font-size: 8pt;
+ text-decoration: underline;
+ color: #18469C;
+ padding-right:5px;
+ border-right: 1px solid #99BBE8;
+}
+
+.x-btn-text button {
+ font-size: 8pt;
+ text-decoration: underline;
+ color: #18469C;
+}
+
+.x-btn-link-medium {
+ text-decoration:underline;
+ float:right;
+ text-align:right;
+}
+
+.x-btn .icon-add, .x-menu-item .icon-add {
+ background-image: url(img/silk/add.png);
+}
+
+
+.x-span-font-eight {
+ font-size: 8pt;
+}
+
+.x-form-field-inline {
+ display:inline;
+ padding:0 0 30px 0;
+ margin:0px;
+}
+
+.transparent-panel {
+ background:transparent;
+}
+
+cga-logo-overlay {
+ z-index: 10000;
+ position: absolute;
+ left: 100px;
+ bottom: 10px;
+ width:151px;
+ height:39px;
+ background: transparent;
+}
+
+.more-overlay-element {
+ float: left;
+ z-index: 4000;
+ position: absolute;
+ right: 150px;
+ top: 10px;
+ height:25px;
+ width:50px;
+ background: #FFF;
+ text-decoration: none;
+ border: 1px solid #000;
+}
+
+.more-overlay-element .x-btn-small td {background-image: none; text-decoration:none;}
+.more-overlay-element .x-btn-small td button {text-decoration:none;}
+
+.language-overlay-element {
+ float: left;
+ z-index: 4000;
+ position: absolute;
+ right: 10px;
+ bottom: 70px;
+ height:25px;
+ text-decoration: none;
+}
+
+div.cga-link {
+ margin:3px;
+ font-size:8pt;
+ clear: both;
+}
+
+.featureDetailList {
+}
+.featureDetailList li {
+ margin:4px 5px;
+ min-height:16px;
+ position:relative;
+}
+* html .featureDetailList li {
+ height:16px;
+}
+.featureDetailList li label {
+ font-weight:bold;
+ left:0;
+ position:absolute;
+ top:0;
+ width:150px;
+}
+.featureDetailList li span {
+ margin-left:160px;
+}
+
+.nicEdit-selected {
+ border: 2px solid #0000ff !important;
+}
+
+.nicEdit-panel {
+ background-color: #fff !important;
+}
+
+.nicEdit-button {
+ background-color: #fff !important;
+}
+
+.wtf {
+ padding: 0px 10px 0px 10px;
+ border-right: 1px solid #000;
+}
+
+div.cql-overlay {
+ z-index: 10000;
+ position: absolute;
+ margin: 0 15%;
+ background:#FFF;
+ opacity: 0.9
+}
+
+div.chart-overlay {
+ z-index: 10000;
+ position: absolute;
+ //left: 10px;
+ bottom: 10px;
+ margin: 0 15%;
+ background:#FFF;
+ opacity: 1.0
+}
+
+.icon-picasa {
+ background-image: url('img/picasa.png');
+}
+
+.icon-youtube {
+ background-image: url('img/youtube.png');
+}
+
+
+.icon-harvard {
+ background-image: url('img/harvard.png');
+}
+
+.icon-flickr {
+ background-image: url('img/flickr.png');
}
\ No newline at end of file
diff --git a/src/geonode-client/app/static/theme/app/geoexplorer_white.css b/src/geonode-client/app/static/theme/app/geoexplorer_white.css
index 42f77d0..278e79c 100644
--- a/src/geonode-client/app/static/theme/app/geoexplorer_white.css
+++ b/src/geonode-client/app/static/theme/app/geoexplorer_white.css
@@ -1,997 +1,998 @@
- /* do wrap lines on any tooltips */
-.x-tip {
-}
-
-/* get images on buttons with text to line up with those with no text */
-.x-btn-text-icon .x-btn-center .x-btn-text {
- background-position: 0 3px;
-}
-
-/* apply some margin when using the row expander */
-.x-grid3-row-body p {
- margin: 5px !important;
-}
-
-/* workaround for semi-alpha pixels in IE7: background needs to be the same
- * as the toolbar's background color */
-.ext-ie .x-item-disabled .x-btn-text {
- background-color: #EAEAEA;
-}
-
-.x-tree-node-leaf .gx-tree-layer-icon {
- background-image: url(img/geosilk/vector.png);
-}
-
-.x-tree-node-leaf .gx-tree-rasterlayer-icon {
- background-image: url(img/geosilk/raster.png);
-}
-
-.x-menu-group-item .x-menu-item-icon {
- background: transparent url(../../externals/ext/resources/images/white/form/radio.gif) no-repeat 0 0;
- height: 13px;
- width: 13px;
- margin: 2px;
-}
-
-.x-menu-item-checked .x-menu-group-item .x-menu-item-icon {
- background: transparent url(../../externals/ext/resources/images/white/form/radio.gif) no-repeat -13px -13px;
- height: 13px;
- width: 13px;
- margin: 2px;
-}
-
-.x-btn .icon-geoexplorer {
- background-image: url(img/geoexplorer.png);
-}
-
-.x-btn .icon-addlayers {
- background-image: url(img/silk/add.png);
-}
-
-.x-btn .icon-removelayers, .x-menu-item .icon-removelayers {
- background-image: url(img/silk/delete.png);
-}
-
-.x-btn .icon-layerproperties, .x-menu-item .icon-layerproperties {
- background-image: url(img/silk/wrench.png);
-}
-
-.x-btn .icon-layerstyles, .x-menu-item .icon-layerstyles {
- background-image: url(img/silk/palette.png);
-}
-
-.x-btn .icon-getfeatureinfo {
- background-image: url(img/silk/information.png);
-}
-
-.x-btn .icon-3D {
- background-image: url(img/geosilk/google_earth.png);
-}
-
-.x-btn .icon-save {
- background-image: url(img/geosilk/map_save.png);
-}
-
-/* Really for CAPRA, watch out! */
-
-.x-menu-group-item .icon-point,
-.x-btn .icon-point {
- background: transparent url(img/geosilk/bullet_orange.png) no-repeat center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-menu-group-item .icon-line,
-.x-btn .icon-line {
- background: transparent url(img/geosilk/line_orange.png) no-repeat center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-menu-group-item .icon-polygon,
-.x-btn .icon-polygon {
- background: transparent url(img/geosilk/shape_square_orange.png) center center !important;
- margin: 0px;
- height: 16px;
- width: 16px;
-}
-
-.x-btn .icon-visibility {
- background-image: url(img/silk/eye.png);
-}
-
-.x-btn .icon-pdf {
- background-image: url(img/silk/page_white_acrobat.png);
-}
-
-div.report {
- background-color: white;
- height: 100%;
-}
-
-div.report table, div.report td, div.report th {
- padding: .4em;
-}
-
-div.report th {
- background-color: #CCC;
-}
-
-div.report tr.odd {
- background-color: #EEF;
-}
-
-.report td.corner{
- background-color:white;
-}
-
-
-/* ------------ */
-
-.x-btn .icon-export {
- background-image: url(img/silk/map_go.png);
-}
-.x-btn .icon-measure {
- background-image: url(img/geosilk/measure.png);
-}
-
-.icon-measure-length {
- background-image: url(img/geosilk/ruler.png) !important;
-}
-
-.icon-measure-area {
- background: url(img/geosilk/ruler_square.png) no-repeat 0 0 !important;
- margin: 0 !important;
- width: 16px !important;
- height: 16px !important;
-}
-
-.x-btn .icon-layer-switcher {
- background-image: url(img/silk/layers.png);
-}
-
-.x-btn .icon-zoom-in {
- background-image: url(img/silk/magnifier_zoom_in.png);
-}
-
-.x-btn .icon-zoom-out {
- background-image: url(img/silk/magnifier_zoom_out.png);
-}
-
-.x-btn .icon-zoom-previous {
- background-image: url(img/silk/arrow_left.png);
-}
-
-.x-btn .icon-zoom-next {
- background-image: url(img/silk/arrow_right.png);
-}
-
-.x-btn .icon-zoom-visible, .x-menu-item .icon-zoom-visible {
- background-image: url(img/silk/arrow_out.png);
-}
-
-.x-btn .icon-zoom-to, .x-menu-item .icon-zoom-to {
- background-image: url(img/silk/magnifier.png);
-}
-
-.x-btn .icon-pan {
- background-image: url(img/geosilk/pan.png);
-}
-
-.legend-item {
- margin: 0.5em 10px;
-}
-
-div.map-overlay {
- z-index: 4000;
- position: absolute;
- right: 10px;
- bottom: 10px;
- background:transparent;
-}
-
-div.map-overlay div.overlay-element {
- display:inline;
- float: left;
- margin: 5px;
- background:transparent;
-}
-
-div.overlay-scaleline {
- bottom: 0px;
- left: 0px;
- margin-top: 0px;
- z-index: 10000;
-}
-
-.olControlAttribution{
- color: gray;
- bottom: .5em;
- left: .4em;
- right: 220px;
- font-size: smaller;
-}
-
-.olControlScaleLineTop,
-.olControlScaleLineBottom {
- font-size:10px;
-}
-
-/* Pan- and Zoom- Panel Styles*/
-
-.olControlPanPanel div {
- background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
- height:15px;
- width:15px;
- /* workaround for button height in IE */
- font-size:0px;
-}
-
-.olControlPanPanel .olControlPanNorthItemInactive {
- background-position:15px -60px;
- left:16px
-}
-.olControlPanPanel .olControlPanEastItemInactive {
- background-position:15px -120px;
- left: 30px;
- top: 16px;
-}
-.olControlPanPanel .olControlPanSouthItemInactive {
- background-position:15px -75px;
- left: 16px;
- top: 32px;
-}
-.olControlPanPanel .olControlPanWestItemInactive {
- background-position:15px -105px;
- left: 2px;
- top: 16px;
-}
-
-.olControlZoomPanel {
- left:21px;
-}
-
-.olControlZoomPanel div {
- background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
- height:15px;
- width:15px;
- /* workaround for button height in IE */
- font-size:0px;
-}
-
-.olControlZoomPanel .olControlZoomInItemInactive {
- background-position:15px -240px;
-}
-
-.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
- display: none;
-}
-
-.olControlZoomPanel .olControlZoomOutItemInactive {
- background-position:15px -255px;
- top: 123px;
-}
-
-.olControlScaleLine {
- line-height: 10px;
- display: block;
- position: relative;
- font-family: tahoma,arial,helvetica,sans-serif;
-}
-
-/* position the zoom slider within map panel */
-.gx-zoomslider {
- top: 90px;
- left: 17px
-}
-
-
-.gx-layer-menu {
- background: #F0F0F0;
-}
-
-.gx-field-label {
- font-weight: bold;
- margin: 4px;
- vertical-align: baseline;
-}
-
-.gx-snippet-area textarea {
- color: black;
- opacity: 1;
-}
-
-.gx-info-panel {
- margin: 1em;
-}
-
-.gx-info-panel h2 {
- margin-top: 1em;
-}
-
-.gx-wizard-description p {
- margin: 4px auto;
- background: none;
-}
-
-.gx-wizard-pane {
- padding: 4px;
-}
-
-.gx-grid-true {
- background: red;
-}
-
-.gx-grid-false {
- background: blue;
-}
-
-.gx-wizard-active button {
- font-weight: bold;
-}
-
-.gx-wizard-pane .x-panel-body {
- background: none;
-}
-
-.gx-wizard-pane .x-grid3-dirty-cell {
- background-image: none;
-}
-
-.gx-layer-visibility {
- background-image: url(img/silk/eye.png);
- width: 16px;
- height: 16px;
- display: block;
-}
-
-.error-details {
- font: 8pt courier,courier new,monospace;
- padding: 5px;
-}
-
-.user_item button {
- width: 16px;
- height: 16px;
- margin: 4px;
-}
-
-#more-info{
- float:right;
-}
-
-/* gxp overrides for different folder structure */
-.olControlZoomPanel div {
- background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
-}
-.x-tree-node img.gxp-folder, .x-tree-node-collapsed img.gxp-folder{
- background: url(../../externals/ext/resources/images/white/tree/folder.gif);
-}
-.x-tree-node-expanded img.gxp-folder {
- background: url(../../externals/ext/resources/images/white/tree/folder-open.gif);
-}
-
-.olLayerGoogleV3.olLayerGoogleCopyright {
- bottom: 1em !important;
-}
-.olLayerGoogleV3.olLayerGooglePoweredBy {
- bottom: 2em !important;
-}
-
-/* WorldMap additions/modifications */
-
-.x-btn-noicon .x-btn-small .x-btn-text {
- height: 21px;
-}
-
-.ext-gecko .x-btn button, .ext-webkit .x-btn button {
- color: #0d0d0d;
- border: 1px solid #bbb;
- border-radius: 5px;
-}
-
-.ext-gecko .x-btn button:hover {
- color:#fff;
- background-color: #2657A8;
- border: 1px solid #2657A8;
-}
-
-.x-btn .user_item .icon-removeuser .remove-button {
- border: 1px solid #fff;
-}
-
-.x-btn-text {
- font-size: 8pt;
- /*color: #18469C;*/
- padding:0px;
- border-radius: 5px;
- /*border: 1px solid #000;*/
- border:none;
- text-transform: capitalize;
-}
-
-.x-btn-text button {
- font-size: 8pt;
- text-decoration: none;
-}
-
-.x-btn-link-medium {
- text-decoration:underline;
- float:right;
- text-align:right;
-}
-
-
-.x-btn .icon-add, .x-menu-item .icon-add {
- background-image: url(../../externals/ext/resources/images/white/silk/add.png);
-}
-
-
-.x-span-font-eight {
- font-size: 8pt;
-}
-
-.x-form-field-inline {
- display:inline;
- padding:0 0 30px 0;
- margin:0px;
-}
-
-.transparent-panel {
- background:transparent;
-}
-
-cga-logo-overlay {
- z-index: 10000;
- position: absolute;
- left: 100px;
- bottom: 10px;
- width:151px;
- height:39px;
- background: transparent;
-}
-
-.more-overlay-element {
- float: left;
- z-index: 4000;
- position: absolute;
- right: 150px;
- top: 10px;
- height:25px;
- width:50px;
- background: #FFF;
- text-decoration: none;
- /*border: 1px solid #000;*/
-}
-
-.more-overlay-element .x-btn-small td {background-image: none; text-decoration:none;}
-.more-overlay-element .x-btn-small td button {text-decoration:none;}
-
-.language-overlay-element {
- float: left;
- z-index: 4000;
- position: absolute;
- right: 10px;
- bottom: 70px;
- height:25px;
- text-decoration: none;
-}
-
-div.cga-link {
- margin:3px;
- font-size:8pt;
- clear: both;
-}
-
-.featureDetailList {
-}
-.featureDetailList li {
- margin:4px 5px;
- min-height:16px;
- position:relative;
-}
-* html .featureDetailList li {
- height:16px;
-}
-.featureDetailList li label {
- font-weight:bold;
- left:0;
- position:absolute;
- top:0;
- width:150px;
-}
-.featureDetailList li span {
- margin-left:160px;
-}
-
-.nicEdit-selected {
- border: 2px solid #0000ff !important;
-}
-
-.nicEdit-panel {
- background-color: #fff !important;
-}
-
-.nicEdit-button {
- background-color: #fff !important;
-}
-
-.wtf {
- padding: 0px 10px 0px 10px;
- border-right: 1px solid #000;
-}
-
-div.cql-overlay {
- z-index: 10000;
- position: absolute;
- margin: 0 15%;
- background:#FFF;
- opacity: 0.9
-}
-
-div.chart-overlay {
- z-index: 10000;
- position: absolute;
- //left: 10px;
- bottom: 10px;
- margin: 0 15%;
- background:#FFF;
- opacity: 1.0
-}
-
-.icon-picasa {
- background-image: url('img/picasa.png');
-}
-
-.icon-youtube {
- background-image: url('img/youtube.png');
-}
-
-
-.icon-harvard {
- background-image: url('img/harvard.png');
-}
-
-.icon-flickr {
- background-image: url('img/flickr.png');
-}
-
-
-/** WHITE **/
-
-
-.x-toolbar{
- background-color: #fff;
- background-image: none;
-}
-.x-tab-panel-header{
- background-color: #fff;
- background-image: none;
- }
-ul.x-tab-strip-top {
- background-color: #fff;
- background-image: none;
-}
-
-.x-panel{
- border-color: #fff;
-}
-
-.x-panel-tbar{
- border-color: #fff;
-
-}
-.x-toolbar{
- border-color: #fff;
-
-}
-.x-small-editor{
- border-color: #fff;
-
-}
-.x-toolbar-layout-ct{
- border-color: #fff;
-}
-
-
-.x-tab-panel-header, .x-tab-panel-footer {
- border-color: #fff;
-
-}
-
-.x-panel-noborder .x-panel-tbar-noborder .x-toolbar {
- border-color: #fff;
-}
-
-.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar {
- border-color: #fff;
-}
-
-.x-border-layout-ct {
- border-top: 0px solid #dbdbdb;
-}
-
-
-.x-panel-tbar {
- border-top: 0px solid;
- border-bottom: 1px solid;
- border-color: #dbdbdb;
-}
-
-.x-panel-tbar-noborder {
- border-top: 0px solid;
- border-bottom: 0px solid;
- border-color: #dbdbdb;
-}
-
-.x-panel-body-noheader {
- border-top: 0px solid;
- border-bottom: 0px solid;
- border-color: #fff;
- /*border-color: #dbdbdb;*/
-}
-
-
-
-.x-tab-panel-body {
- border-color: #fff;
-}
-
-.x-layout-collapsed {
- background-color: #fff;
- border-color: #fff;
-}
-
-.x-window-tc {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-ml {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-mr {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-bc {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-bl {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-br {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-tl {
- background-image: none;
- background-color: #fff;
-}
-
-.x-window-tr {
- background-image: none;
- background-color: #fff;
-}
-
-.x-layout-split {
- height: 5px;
- line-height: 1px;
- font-size: 1px;
- z-index: 3;
- background-color: #fff;
- width: 5px;
- position: absolute;
-}
-
-.x-btn-tl, .x-btn-tr, .x-btn-tc, .x-btn-ml, .x-btn-mr, .x-btn-mc, .x-btn-bl, .x-btn-br, .x-btn-bc {
- background-image: none;
- background-color: #fff;
-}
-.x-btn-focus, .x-btn-pressed{
- background-image: none;
- background-color: #fff;
-}
-
-.x-btn-tl:hover, .x-btn-tr:hover, .x-btn-tc:hover, .x-btn-ml:hover, .x-btn-mr:hover, .x-btn-mc:hover, .x-btn-bl:hover, .x-btn-br:hover, .x-btn-bc:hover {
- background-image: none;
- background-color: #fff;
-}
-
-.x-toolbar .x-btn-click .x-btn-bc, .x-toolbar .x-btn-menu-active .x-btn-bc, .x-toolbar .x-btn-pressed .x-btn-bc, .x-toolbar .x-btn-over .x-btn-bc {
- background-image: none;
- height: 1px;
-/* background-color: #287AB0;*/
-}
-
-.x-btn .gxp-icon-note {
- background-image: url("../../externals/ext/resources/images/white/tree/note.png");
- background-size: 17%;
-}
-
-.x-btn-text-icon .x-btn-icon-small-left .x-btn-text {
- background-position: 0px center;
- background-repeat: no-repeat;
- padding-left: 19px;
- height: 21px;
-}
-
-.x-btn-icon .x-btn-small .x-btn-text {
- border: 1px solid #fff;
- /* height: 25px;*/
-}
-
-.x-tree-node .x-tree-selected {
- background-color: #d3d3d3;
-}
-
-.x-tip .x-tip-tc, .x-tip .x-tip-tl, .x-tip .x-tip-tr, .x-tip .x-tip-bc, .x-tip .x-tip-bl, .x-tip .x-tip-br, .x-tip .x-tip-ml, .x-tip .x-tip-mr {
- background-image: none;
- background-color: #fff;
-}
-
-.x-menu-item-active {
- background-image: none;
- background-color: #fff;
- border-color: #fff;
-}
-
-.x-menu-list {
- background-color: #fff;
-}
-
-.x-menu-item-active a.x-menu-item {
- border-color: #fff;
-}
-
-.x-menu-floating {
- border-color: #fff;
-}
-
-.x-toolbar .x-btn-mc em.x-btn-split {
- background-image: url("../../externals/ext/resources/images/white/button/s-arrow-noline.gif");
-}
-
-.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split {
- background-image: url("../../externals/ext/resources/images/white/button/s-arrow-noline.gif");
-}
-
-.x-slider-vert .x-slider-inner {
- background-image: none;
- background-color: rgba(100, 100, 100, .5);
- border-radius: 5px;
- width: 10px;
- margin-left: 6px;
-}
-
-.x-slider-vert .x-slider-thumb {
- background-image: none;
- background-color: #737373;
- border-bottom: 0px solid #737373;
- border-top: 0px solid #737373;
- border-radius: 10px;
- height: 10px;
- width: 10px;
- margin-left: -3px;
-}
-
-.x-slider-vert, .x-slider-vert .x-slider-end, .x-slider-vert .x-slider-inner {
- background-image: none;
-}
-
-.x-form-field-wrap .x-form-trigger {
- background-image: url("../../externals/ext/resources/images/white/form/trigger.gif");
- border: 1px solid #fff;
- padding-top: 0px;
-}
-
-.x-form-field-wrap .x-form-trigger img {
- padding-top: 4px;
-}
-
-.x-small-editor .x-form-field-wrap .x-form-trigger {
- height: 19px;
-}
-
-.ext-gecko .x-btn button, .ext-webkit .x-btn button {
- padding-left: 5px;
- padding-right: 5px;
-}
-
-.x-tab-strip-active span.x-tab-strip-text {
- color: #1a1a1a;
- font-weight: bold;
- text-transform: uppercase;
- margin-left: 9px;
-}
-
-.x-toolbar .xtb-sep {
- background-image:none;
-}
-
-.x-grid3-header {
- background-color: #FFF;
- background-image: none;
-}
-
-.td.sort-asc .x-grid3-hd-inner {
- background-color: #FFF;
- background-image: none;
-}
-
-.gxp-crumb span.x-tab-strip-text {
- margin: 4px 4px 4px 9px;
- color: #1a1a1a;
- font-weight: bold;
- text-transform: uppercase;
-}
-
-.gxp-crumb .x-tab-strip-text a {
- cursor: pointer;
- color: #1a1a1a;
- text-transform: uppercase;
-}
-
-td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner {
- background-color: #fff;
- background-image: none;
-}
-
-a.x-grid3-hd-btn {
- background-image: url("../../externals/ext/resources/images/white/grid/grid3-hd-btn.gif");
- background-color: #FFF;
-}
-
-.x-form-text, textarea.x-form-field {
- color: #1a1a1a;
- background-color: #FFF;
- background-image: none;
- border-color: #d3d3d3;
- margin-bottom: 5px;
- margin-right: 5px;
- margin-left: 5px;
- border-radius: 3px;
-}
-
-.x-grid3-scroller {
- border-radius: 1px;
- border: 1px solid #d3d3d3;
-}
-
-.x-form-field-wrap .x-form-field-trigger-wrap {
- border: 1px solid #1a1a1a;
-}
-
-.x-combo-list {
- border-color: #dbdbdb;
- background-color: #FFF;
- font: 12px tahoma,arial,helvetica,sans-serif;
-}
-
-.x-combo-list .x-combo-selected {
- border-color: #737373 !important;
- background-color: #dbdbdb;
-}
-
-.x-grid3-hd-row td {
- border-left-color: #FFF;
- border-right-color: #FFF;
-}
-
-.x-grid3-body .x-grid3-row-selected .x-grid3-td-expander {
- background-image: none;
- background-color: #fff;
-}
-
-.x-grid3-row-selected {
- background-color: #18469c !important;
- background-image: none;
- border-color: #18469c;
-}
-
-.x-grid3-row-selected .x-grid3-cell-inner{
- color: #fff;
-
-}
-
-.x-grid3-col .x-grid3-cell .x-grid3-td-expander .x-grid3-cell-first {
- background-image:none;
- background-color: #dbdbdb;
-}
-
- .x-grid3-row-first .x-grid3-row-last {
- background-color: #fff;
-}
-
-.x-grid3-row-over {
- border-color:#18469c ;
- background-color: #18469c;
- background-image:none;
-}
-
-.x-grid3-row-over .x-grid3-cell-inner{
- color: #fff;
-
-}
-
-.x-grid3-row .x-grid3-row-collapsed .x-grid3-row-over {
- background-color: #fff !important;
- background-image: none;
- border-color: #1a1a1a;
-}
-
-.x-grid3-body .x-grid3-td-expander {
- background-image: none;
-}
-
-td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner {
- background: transparent none repeat-x scroll left bottom;
-}
-
-.olImageLoadError {
- opacity: 0 !important;
- filter: alpha(opacity=0) !important;
-}
-
-.x-btn .prominent-btn, .prominent-btn, .prominent-button button, ext-gecko .x-btn .prominent-button button {
- background-color: #18469c !important;
- border-color: #18469c !important;
- border-radius: 5px !important;
- color: #fff !important;
- font-size: 14px !important;
- font-weight: bold;
- height: 25px !important;
- padding-left: 10px !important;
- padding-right: 10px !important;
- margin-top: -2px;
-}
-
-.x-btn .not-prominent-btn, .not-prominent-btn, .not-prominent-button button, ext-gecko .x-btn .not-prominent-button button {
- border-radius: 5px !important;
- font-size: 14px !important;
- height: 25px !important;
- padding-left: 10px !important;
- padding-right: 10px !important;
- margin-top: -2px;
-}
-
-.search-bar{
- float: left;
-}
-
-.data-type{
- /*float:left;*/
- /*width: 140px;*/
- height: 25px;
-}
-
-.x-form-field-wrap, .x-form-field-trigger-wrap, .x-trigger-wrap-focus {
- margin-left: 0px;
- float: left;
-}
-
-.x-panel-body .x-panel-body-noheader .x-panel-body-noborder {
- max-width: 100%;
- max-height: 100%;
- /*max-width: 884px;
- max-height: 520px;*/
-}
-
-#search_controls{
- margin-left: 20px;
+ /* do wrap lines on any tooltips */
+.x-tip {
+}
+
+/* get images on buttons with text to line up with those with no text */
+.x-btn-text-icon .x-btn-center .x-btn-text {
+ background-position: 0 3px;
+}
+
+/* apply some margin when using the row expander */
+.x-grid3-row-body p {
+ margin: 5px !important;
+}
+
+/* workaround for semi-alpha pixels in IE7: background needs to be the same
+ * as the toolbar's background color */
+.ext-ie .x-item-disabled .x-btn-text {
+ background-color: #EAEAEA;
+}
+
+.x-tree-node-leaf .gx-tree-layer-icon {
+ background-image: url(img/geosilk/vector.png);
+}
+
+.x-tree-node-leaf .gx-tree-rasterlayer-icon {
+ background-image: url(img/geosilk/raster.png);
+}
+
+.x-menu-group-item .x-menu-item-icon {
+ background: transparent url(../../externals/ext/resources/images/white/form/radio.gif) no-repeat 0 0;
+ height: 13px;
+ width: 13px;
+ margin: 2px;
+}
+
+.x-menu-item-checked .x-menu-group-item .x-menu-item-icon {
+ background: transparent url(../../externals/ext/resources/images/white/form/radio.gif) no-repeat -13px -13px;
+ height: 13px;
+ width: 13px;
+ margin: 2px;
+}
+
+.x-btn .icon-geoexplorer {
+ background-image: url(img/geoexplorer.png);
+}
+
+.x-btn .icon-addlayers {
+ background-image: url(img/silk/add.png);
+}
+
+.x-btn .icon-removelayers, .x-menu-item .icon-removelayers {
+ background-image: url(img/silk/delete.png);
+}
+
+.x-btn .icon-layerproperties, .x-menu-item .icon-layerproperties {
+ background-image: url(img/silk/wrench.png);
+}
+
+.x-btn .icon-layerstyles, .x-menu-item .icon-layerstyles {
+ background-image: url(img/silk/palette.png);
+}
+
+.x-btn .icon-getfeatureinfo {
+ background-image: url(img/silk/information.png);
+}
+
+.x-btn .icon-3D {
+ background-image: url(img/geosilk/google_earth.png);
+}
+
+.x-btn .icon-save {
+ background-image: url(img/geosilk/map_save.png);
+}
+
+/* Really for CAPRA, watch out! */
+
+.x-menu-group-item .icon-point,
+.x-btn .icon-point {
+ background: transparent url(img/geosilk/bullet_orange.png) no-repeat center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-menu-group-item .icon-line,
+.x-btn .icon-line {
+ background: transparent url(img/geosilk/line_orange.png) no-repeat center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-menu-group-item .icon-polygon,
+.x-btn .icon-polygon {
+ background: transparent url(img/geosilk/shape_square_orange.png) center center !important;
+ margin: 0px;
+ height: 16px;
+ width: 16px;
+}
+
+.x-btn .icon-visibility {
+ background-image: url(img/silk/eye.png);
+}
+
+.x-btn .icon-pdf {
+ background-image: url(img/silk/page_white_acrobat.png);
+}
+
+div.report {
+ background-color: white;
+ height: 100%;
+}
+
+div.report table, div.report td, div.report th {
+ padding: .4em;
+}
+
+div.report th {
+ background-color: #CCC;
+}
+
+div.report tr.odd {
+ background-color: #EEF;
+}
+
+.report td.corner{
+ background-color:white;
+}
+
+
+/* ------------ */
+
+.x-btn .icon-export {
+ background-image: url(img/silk/map_go.png);
+}
+.x-btn .icon-measure {
+ background-image: url(img/geosilk/measure.png);
+}
+
+.icon-measure-length {
+ background-image: url(img/geosilk/ruler.png) !important;
+}
+
+.icon-measure-area {
+ background: url(img/geosilk/ruler_square.png) no-repeat 0 0 !important;
+ margin: 0 !important;
+ width: 16px !important;
+ height: 16px !important;
+}
+
+.x-btn .icon-layer-switcher {
+ background-image: url(img/silk/layers.png);
+}
+
+.x-btn .icon-zoom-in {
+ background-image: url(img/silk/magnifier_zoom_in.png);
+}
+
+.x-btn .icon-zoom-out {
+ background-image: url(img/silk/magnifier_zoom_out.png);
+}
+
+.x-btn .icon-zoom-previous {
+ background-image: url(img/silk/arrow_left.png);
+}
+
+.x-btn .icon-zoom-next {
+ background-image: url(img/silk/arrow_right.png);
+}
+
+.x-btn .icon-zoom-visible, .x-menu-item .icon-zoom-visible {
+ background-image: url(img/silk/arrow_out.png);
+}
+
+.x-btn .icon-zoom-to, .x-menu-item .icon-zoom-to {
+ background-image: url(img/silk/magnifier.png);
+}
+
+.x-btn .icon-pan {
+ background-image: url(img/geosilk/pan.png);
+}
+
+.legend-item {
+ margin: 0.5em 10px;
+}
+
+div.map-overlay {
+ z-index: 4000;
+ position: absolute;
+ right: 10px;
+ bottom: 10px;
+ background:transparent;
+}
+
+div.map-overlay div.overlay-element {
+ display:inline;
+ float: left;
+ margin: 5px;
+ background:transparent;
+}
+
+div.overlay-scaleline {
+ bottom: 0px;
+ left: 0px;
+ margin-top: 0px;
+ z-index: 10000;
+}
+
+.olControlAttribution{
+ color: gray;
+ bottom: .5em;
+ left: .4em;
+ right: 220px;
+ font-size: smaller;
+}
+
+.olControlScaleLineTop,
+.olControlScaleLineBottom {
+ font-size:10px;
+}
+
+/* Pan- and Zoom- Panel Styles*/
+
+.olControlPanPanel div {
+ background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
+ height:15px;
+ width:15px;
+ /* workaround for button height in IE */
+ font-size:0px;
+}
+
+.olControlPanPanel .olControlPanNorthItemInactive {
+ background-position:15px -60px;
+ left:16px
+}
+.olControlPanPanel .olControlPanEastItemInactive {
+ background-position:15px -120px;
+ left: 30px;
+ top: 16px;
+}
+.olControlPanPanel .olControlPanSouthItemInactive {
+ background-position:15px -75px;
+ left: 16px;
+ top: 32px;
+}
+.olControlPanPanel .olControlPanWestItemInactive {
+ background-position:15px -105px;
+ left: 2px;
+ top: 16px;
+}
+
+.olControlZoomPanel {
+ left:21px;
+}
+
+.olControlZoomPanel div {
+ background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
+ height:15px;
+ width:15px;
+ /* workaround for button height in IE */
+ font-size:0px;
+}
+
+.olControlZoomPanel .olControlZoomInItemInactive {
+ background-position:15px -240px;
+}
+
+.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
+ display: none;
+}
+
+.olControlZoomPanel .olControlZoomOutItemInactive {
+ background-position:15px -255px;
+ top: 123px;
+}
+
+.olControlScaleLine {
+ line-height: 10px;
+ display: block;
+ position: relative;
+ font-family: tahoma,arial,helvetica,sans-serif;
+}
+
+/* position the zoom slider within map panel */
+.gx-zoomslider {
+ top: 90px;
+ left: 17px
+}
+
+
+.gx-layer-menu {
+ background: #F0F0F0;
+}
+
+.gx-field-label {
+ font-weight: bold;
+ margin: 4px;
+ vertical-align: baseline;
+}
+
+.gx-snippet-area textarea {
+ color: black;
+ opacity: 1;
+}
+
+.gx-info-panel {
+ margin: 1em;
+}
+
+.gx-info-panel h2 {
+ margin-top: 1em;
+}
+
+.gx-wizard-description p {
+ margin: 4px auto;
+ background: none;
+}
+
+.gx-wizard-pane {
+ padding: 4px;
+}
+
+.gx-grid-true {
+ background: red;
+}
+
+.gx-grid-false {
+ background: blue;
+}
+
+.gx-wizard-active button {
+ font-weight: bold;
+}
+
+.gx-wizard-pane .x-panel-body {
+ background: none;
+}
+
+.gx-wizard-pane .x-grid3-dirty-cell {
+ background-image: none;
+}
+
+.gx-layer-visibility {
+ background-image: url(img/silk/eye.png);
+ width: 16px;
+ height: 16px;
+ display: block;
+}
+
+.error-details {
+ font: 8pt courier,courier new,monospace;
+ padding: 5px;
+}
+
+.user_item button {
+ width: 16px;
+ height: 16px;
+ margin: 4px;
+}
+
+#more-info{
+ float:right;
+}
+
+/* gxp overrides for different folder structure */
+.olControlZoomPanel div {
+ background-image:url(../../externals/ext/resources/images/white/panel/tool-sprites.gif);
+}
+.x-tree-node img.gxp-folder, .x-tree-node-collapsed img.gxp-folder{
+ background: url(../../externals/ext/resources/images/white/tree/folder.gif);
+}
+.x-tree-node-expanded img.gxp-folder {
+ background: url(../../externals/ext/resources/images/white/tree/folder-open.gif);
+}
+
+.olLayerGoogleV3.olLayerGoogleCopyright {
+ bottom: 1em !important;
+}
+.olLayerGoogleV3.olLayerGooglePoweredBy {
+ bottom: 2em !important;
+}
+
+/* WorldMap additions/modifications */
+
+.x-btn-noicon .x-btn-small .x-btn-text {
+ height: 21px;
+}
+
+.ext-gecko .x-btn button, .ext-webkit .x-btn button {
+ color: #0d0d0d;
+ border: 1px solid #bbb;
+ border-radius: 5px;
+}
+
+.ext-gecko .x-btn button:hover {
+ color:#fff;
+ background-color: #2657A8;
+ border: 1px solid #2657A8;
+}
+
+.x-btn .user_item .icon-removeuser .remove-button {
+ border: 1px solid #fff;
+}
+
+.x-btn-text {
+ font-size: 8pt;
+ /*color: #18469C;*/
+ padding:0px;
+ border-radius: 5px;
+ /*border: 1px solid #000;*/
+ border:none;
+ text-transform: capitalize;
+}
+
+.x-btn-text button {
+ font-size: 8pt;
+ text-decoration: none;
+}
+
+.x-btn-link-medium {
+ text-decoration:underline;
+ float:right;
+ text-align:right;
+}
+
+
+.x-btn .icon-add, .x-menu-item .icon-add {
+ background-image: url(../../externals/ext/resources/images/white/silk/add.png);
+}
+
+
+.x-span-font-eight {
+ font-size: 8pt;
+}
+
+.x-form-field-inline {
+ display:inline;
+ padding:0 0 30px 0;
+ margin:0px;
+}
+
+.transparent-panel {
+ background:transparent;
+}
+
+cga-logo-overlay {
+ z-index: 10000;
+ position: absolute;
+ left: 100px;
+ bottom: 10px;
+ width:151px;
+ height:39px;
+ background: transparent;
+}
+
+.more-overlay-element {
+ float: left;
+ z-index: 4000;
+ position: absolute;
+ right: 150px;
+ top: 10px;
+ height:25px;
+ width:50px;
+ background: #FFF;
+ text-decoration: none;
+ /*border: 1px solid #000;*/
+}
+
+.more-overlay-element .x-btn-small td {background-image: none; text-decoration:none;}
+.more-overlay-element .x-btn-small td button {text-decoration:none;}
+
+.language-overlay-element {
+ float: left;
+ z-index: 4000;
+ position: absolute;
+ right: 10px;
+ bottom: 70px;
+ height:25px;
+ text-decoration: none;
+}
+
+div.cga-link {
+ margin:3px;
+ font-size:8pt;
+ clear: both;
+}
+
+.featureDetailList {
+}
+.featureDetailList li {
+ margin:4px 5px;
+ min-height:16px;
+ position:relative;
+}
+* html .featureDetailList li {
+ height:16px;
+}
+.featureDetailList li label {
+ font-weight:bold;
+ left:0;
+ position:absolute;
+ top:0;
+ width:150px;
+}
+.featureDetailList li span {
+ margin-left:160px;
+}
+
+.nicEdit-selected {
+ border: 2px solid #0000ff !important;
+}
+
+.nicEdit-panel {
+ background-color: #fff !important;
+}
+
+.nicEdit-button {
+ background-color: #fff !important;
+}
+
+.wtf {
+ padding: 0px 10px 0px 10px;
+ border-right: 1px solid #000;
+}
+
+div.cql-overlay {
+ z-index: 10000;
+ position: absolute;
+ margin: 0 15%;
+ background:#FFF;
+ opacity: 0.9
+}
+
+div.chart-overlay {
+ z-index: 10000;
+ position: absolute;
+ //left: 10px;
+ bottom: 10px;
+ margin: 0 15%;
+ background:#FFF;
+ opacity: 1.0
+}
+
+.icon-picasa {
+ background-image: url('img/picasa.png');
+}
+
+.icon-youtube {
+ background-image: url('img/youtube.png');
+}
+
+
+.icon-harvard {
+ background-image: url('img/harvard.png');
+}
+
+.icon-flickr {
+ background-image: url('img/flickr.png');
+}
+
+
+/** WHITE **/
+
+
+.x-toolbar{
+ background-color: #fff;
+ background-image: none;
+}
+.x-tab-panel-header{
+ background-color: #fff;
+ background-image: none;
+ }
+ul.x-tab-strip-top {
+ background-color: #fff;
+ background-image: none;
+}
+
+.x-panel{
+ border-color: #fff;
+}
+
+.x-panel-tbar{
+ border-color: #fff;
+
+}
+.x-toolbar{
+ border-color: #fff;
+
+}
+.x-small-editor{
+ border-color: #fff;
+
+}
+.x-toolbar-layout-ct{
+ border-color: #fff;
+}
+
+
+.x-tab-panel-header, .x-tab-panel-footer {
+ border-color: #fff;
+
+}
+
+.x-panel-noborder .x-panel-tbar-noborder .x-toolbar {
+ border-color: #fff;
+}
+
+.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar {
+ border-color: #fff;
+}
+
+.x-border-layout-ct {
+ border-top: 0px solid #dbdbdb;
+}
+
+
+.x-panel-tbar {
+ border-top: 0px solid;
+ border-bottom: 1px solid;
+ border-color: #dbdbdb;
+}
+
+.x-panel-tbar-noborder {
+ border-top: 0px solid;
+ border-bottom: 0px solid;
+ border-color: #dbdbdb;
+}
+
+.x-panel-body-noheader {
+ border-top: 0px solid;
+ border-bottom: 0px solid;
+ border-color: #fff;
+ /*border-color: #dbdbdb;*/
+}
+
+
+
+.x-tab-panel-body {
+ border-color: #fff;
+}
+
+.x-layout-collapsed {
+ background-color: #fff;
+ border-color: #fff;
+}
+
+.x-window-tc {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-ml {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-mr {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-bc {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-bl {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-br {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-tl {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-window-tr {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-layout-split {
+ height: 5px;
+ line-height: 1px;
+ font-size: 1px;
+ z-index: 3;
+ background-color: #fff;
+ width: 5px;
+ position: absolute;
+}
+
+.x-btn-tl, .x-btn-tr, .x-btn-tc, .x-btn-ml, .x-btn-mr, .x-btn-mc, .x-btn-bl, .x-btn-br, .x-btn-bc {
+ background-image: none;
+ background-color: #fff;
+}
+.x-btn-focus, .x-btn-pressed{
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-btn-tl:hover, .x-btn-tr:hover, .x-btn-tc:hover, .x-btn-ml:hover, .x-btn-mr:hover, .x-btn-mc:hover, .x-btn-bl:hover, .x-btn-br:hover, .x-btn-bc:hover {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-toolbar .x-btn-click .x-btn-bc, .x-toolbar .x-btn-menu-active .x-btn-bc, .x-toolbar .x-btn-pressed .x-btn-bc, .x-toolbar .x-btn-over .x-btn-bc {
+ background-image: none;
+ height: 1px;
+/* background-color: #287AB0;*/
+}
+
+.x-btn .gxp-icon-note {
+ background-image: url("../../externals/ext/resources/images/white/tree/note.png");
+ background-size: 17%;
+}
+
+.x-btn-text-icon .x-btn-icon-small-left .x-btn-text {
+ background-position: 0px center;
+ background-repeat: no-repeat;
+ padding-left: 19px;
+ height: 21px;
+}
+
+.x-btn-icon .x-btn-small .x-btn-text {
+ border: 1px solid #fff;
+ /* height: 25px;*/
+}
+
+.x-tree-node .x-tree-selected {
+ background-color: #d3d3d3;
+}
+
+.x-tip .x-tip-tc, .x-tip .x-tip-tl, .x-tip .x-tip-tr, .x-tip .x-tip-bc, .x-tip .x-tip-bl, .x-tip .x-tip-br, .x-tip .x-tip-ml, .x-tip .x-tip-mr {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-menu-item-active {
+ background-image: none;
+ background-color: #fff;
+ border-color: #fff;
+}
+
+.x-menu-list {
+ background-color: #fff;
+}
+
+.x-menu-item-active a.x-menu-item {
+ border-color: #fff;
+}
+
+.x-menu-floating {
+ border-color: #fff;
+}
+
+.x-toolbar .x-btn-mc em.x-btn-split {
+ background-image: url("../../externals/ext/resources/images/white/button/s-arrow-noline.gif");
+}
+
+.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split {
+ background-image: url("../../externals/ext/resources/images/white/button/s-arrow-noline.gif");
+}
+
+.x-slider-vert .x-slider-inner {
+ background-image: none;
+ background-color: rgba(100, 100, 100, .5);
+ border-radius: 5px;
+ width: 10px;
+ margin-left: 6px;
+}
+
+.x-slider-vert .x-slider-thumb {
+ background-image: none;
+ background-color: #737373;
+ border-bottom: 0px solid #737373;
+ border-top: 0px solid #737373;
+ border-radius: 10px;
+ height: 10px;
+ width: 10px;
+ margin-left: -3px;
+}
+
+.x-slider-vert, .x-slider-vert .x-slider-end, .x-slider-vert .x-slider-inner {
+ background-image: none;
+}
+
+.x-form-field-wrap .x-form-trigger {
+ background-image: url("../../externals/ext/resources/images/white/form/trigger.gif");
+ border: 1px solid #fff;
+ padding-top: 0px;
+}
+
+.x-form-field-wrap .x-form-trigger img {
+ padding-top: 4px;
+}
+
+.x-small-editor .x-form-field-wrap .x-form-trigger {
+ height: 19px;
+}
+
+.ext-gecko .x-btn button, .ext-webkit .x-btn button {
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.x-tab-strip-active span.x-tab-strip-text {
+ color: #1a1a1a;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin-left: 9px;
+}
+
+.x-toolbar .xtb-sep {
+ background-image:none;
+}
+
+.x-grid3-header {
+ background-color: #FFF;
+ background-image: none;
+}
+
+.td.sort-asc .x-grid3-hd-inner {
+ background-color: #FFF;
+ background-image: none;
+}
+
+.gxp-crumb span.x-tab-strip-text {
+ margin: 4px 4px 4px 9px;
+ color: #1a1a1a;
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+.gxp-crumb .x-tab-strip-text a {
+ cursor: pointer;
+ color: #1a1a1a;
+ text-transform: uppercase;
+}
+
+td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner {
+ background-color: #fff;
+ background-image: none;
+}
+
+a.x-grid3-hd-btn {
+ background-image: url("../../externals/ext/resources/images/white/grid/grid3-hd-btn.gif");
+ background-color: #FFF;
+}
+
+.x-form-text, textarea.x-form-field {
+ color: #1a1a1a;
+ background-color: #FFF;
+ background-image: none;
+ border-color: #d3d3d3;
+ margin-bottom: 5px;
+ margin-right: 5px;
+ margin-left: 5px;
+ border-radius: 3px;
+}
+
+.x-grid3-scroller {
+ border-radius: 1px;
+ border: 1px solid #d3d3d3;
+}
+
+.x-form-field-wrap .x-form-field-trigger-wrap {
+ border: 1px solid #1a1a1a;
+}
+
+.x-combo-list {
+ border-color: #dbdbdb;
+ background-color: #FFF;
+ font: 12px tahoma,arial,helvetica,sans-serif;
+}
+
+.x-combo-list .x-combo-selected {
+ border-color: #737373 !important;
+ background-color: #dbdbdb;
+}
+
+.x-grid3-hd-row td {
+ border-left-color: #FFF;
+ border-right-color: #FFF;
+}
+
+.x-grid3-body .x-grid3-row-selected .x-grid3-td-expander {
+ background-image: none;
+ background-color: #fff;
+}
+
+.x-grid3-row-selected {
+ background-color: #18469c !important;
+ background-image: none;
+ border-color: #18469c;
+}
+
+.x-grid3-row-selected .x-grid3-cell-inner{
+ color: #fff;
+
+}
+
+.x-grid3-col .x-grid3-cell .x-grid3-td-expander .x-grid3-cell-first {
+ background-image:none;
+ background-color: #dbdbdb;
+}
+
+ .x-grid3-row-first .x-grid3-row-last {
+ background-color: #fff;
+}
+
+.x-grid3-row-over {
+ border-color:#18469c ;
+ background-color: #18469c;
+ background-image:none;
+}
+
+.x-grid3-row-over .x-grid3-cell-inner{
+ color: #fff;
+
+}
+
+.x-grid3-row .x-grid3-row-collapsed .x-grid3-row-over {
+ background-color: #fff !important;
+ background-image: none;
+ border-color: #1a1a1a;
+}
+
+.x-grid3-body .x-grid3-td-expander {
+ background-image: none;
+}
+
+td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner {
+ background: transparent none repeat-x scroll left bottom;
+}
+
+.olImageLoadError {
+ opacity: 0 !important;
+ filter: alpha(opacity=0) !important;
+}
+
+.x-btn .prominent-btn, .prominent-btn, .prominent-button button, ext-gecko .x-btn .prominent-button button {
+ background-color: #18469c !important;
+ border-color: #18469c !important;
+ border-radius: 5px !important;
+ color: #fff !important;
+ font-size: 14px !important;
+ font-weight: bold;
+ height: 25px !important;
+ padding-left: 10px !important;
+ padding-right: 10px !important;
+ margin-top: -2px;
+}
+
+.x-btn .not-prominent-btn, .not-prominent-btn, .not-prominent-button button, ext-gecko .x-btn .not-prominent-button button {
+ border-radius: 5px !important;
+ font-size: 14px !important;
+ height: 25px !important;
+ padding-left: 10px !important;
+ padding-right: 10px !important;
+ margin-top: -2px;
+}
+
+.search-bar{
+ float: left;
+}
+
+.data-type{
+ /*float:left;*/
+ /*width: 140px;*/
+ height: 25px;
+}
+
+.x-form-field-wrap, .x-form-field-trigger-wrap, .x-trigger-wrap-focus {
+ margin-left: 0px;
+ float: left;
+}
+
+.x-panel-body .x-panel-body-noheader .x-panel-body-noborder {
+ max-width: 100%;
+ max-height: 100%;
+ /*max-width: 884px;
+ max-height: 520px;*/
+}
+
+#search_controls{
+ margin-left: 20px;
}
.search-button {
+ float:right;
margin-top:-29px;
margin-left: 336px;
}
diff --git a/src/geonode-client/buildjs.cfg b/src/geonode-client/buildjs.cfg
index f4047b3..e516aa8 100755
--- a/src/geonode-client/buildjs.cfg
+++ b/src/geonode-client/buildjs.cfg
@@ -162,6 +162,7 @@ include =
plugins/WMSCSource.js
plugins/BingSource.js
plugins/GoogleSource.js
+ plugins/TiandituSource.js
plugins/MapBoxSource.js
plugins/MapQuestSource.js
plugins/OLSource.js
@@ -201,8 +202,17 @@ include =
widgets/CatalogueSearchPanel.js
widgets/ScaleOverlay.js
menu/LayerMenu.js
+ locale/ca.js
+ locale/de.js
+ locale/el.js
+ locale/en.js
locale/es.js
locale/fr.js
+ locale/id.js
+ locale/nl.js
+ locale/pl.js
+ locale/zh.js
+ locale/zh-cn.js
plugins/AddCategory.js
plugins/RenameCategory.js
plugins/RemoveCategory.js
diff --git a/wm_extra/accounts/forms.py b/wm_extra/accounts/forms.py
index 362c721..51fa0ef 100644
--- a/wm_extra/accounts/forms.py
+++ b/wm_extra/accounts/forms.py
@@ -56,10 +56,13 @@ class SignupForm(forms.Form):
is_org_member = forms.TypedChoiceField(coerce=lambda x: bool(int(x)),
choices=((1, _(u'Yes')), (0, _(u'No'))),
widget=forms.RadioSelect,
- initial=0, label=settings.CUSTOM_ORG_AUTH_TEXT
+ #initial=0, label=_("Are you affiliated with Zhejiang University?")
+ initial=0,
+ label=_("Are you affiliated with Zhejiang University?")
)
agree_tos = forms.BooleanField(
- label=mark_safe("I agree to the Terms and Conditions ")
+ #label=mark_safe(_("I agree to the Terms and Conditions "))
+ label=_("I agree to the Terms and Conditions ")
)
def clean_username(self):
diff --git a/wm_extra/api/resources.py b/wm_extra/api/resources.py
index f55286a..c776f89 100644
--- a/wm_extra/api/resources.py
+++ b/wm_extra/api/resources.py
@@ -3,8 +3,9 @@
from taggit.models import Tag
from geonode.maps.models import Layer
-from geonode.base.models import TopicCategory
+from geonode.base.models import TopicCategory, ResourceBase
+from actstream.models import Action
class TopicCategoryResource(ModelResource):
"""
@@ -67,3 +68,15 @@ class Meta:
'name', 'owner_username', 'srs', 'temporal_extent_end',
'temporal_extent_start', 'title', 'topic_category', 'typename', 'uuid',
]
+
+
+class ActionLayerDeleteResource(ModelResource):
+
+ class Meta:
+ queryidarr = Action.objects.filter(data__contains={'raw_action': 'created'}, action_object_content_type_id=53).order_by('-timestamp').values_list('action_object_object_id', flat=True)
+ queryidarrint = []
+ for queryid in queryidarr:
+ queryidarrint.append(int(queryid))
+ queryset = ResourceBase.objects.filter(id__in=queryidarrint)
+ allowed_methods = ['get', ]
+ fields = ['uuid',]
\ No newline at end of file
diff --git a/wm_extra/views.py b/wm_extra/views.py
index adf9684..56822b2 100644
--- a/wm_extra/views.py
+++ b/wm_extra/views.py
@@ -15,7 +15,7 @@
from django.template import RequestContext
from django.views.decorators.csrf import csrf_exempt
-from geonode.base.models import TopicCategory
+from geonode.base.models import TopicCategory, ResourceBase
from geonode.geoserver.helpers import ogc_server_settings
from geonode.layers.models import Layer
from geonode.maps.models import Map, MapLayer
@@ -27,7 +27,7 @@
from geonode.utils import DEFAULT_TITLE
from geonode.utils import DEFAULT_ABSTRACT
-from .models import LayerStats
+from .models import LayerStats, MapStats
from .forms import EndpointForm
@@ -550,3 +550,90 @@ def official_site(request, site):
"""
map_obj = get_object_or_404(Map,urlsuffix=site)
return map_view_wm(request, str(map_obj.id))
+
+
+
+# TODO get the category list
+def get_categorys(request):
+ """
+ return the category
+ :param request: language
+ :return:
+ """
+ if request.POST.has_key('language'):
+ language = request.POST['language']
+ key = 'gn_description'
+ categorys = TopicCategory.objects.all().values('id',key)
+ category_dict ={}
+ for category in categorys:
+ category_dict[category['id']] = [category[key]]
+ categoryjson = json.dumps(category_dict)
+ # from django.utils import simplejson
+ # return HttpResponse(simplejson.dumps(category, ensure_ascii=False))
+ return HttpResponse(categoryjson)
+
+
+# TODO get the major maps created by admin, or get the hotest and latest layer/map
+def get_most_maps(request):
+ """
+ return the six admin's/hottest/latest maps
+ :param request: category[0:all the category 1-20: appointed category], type['hottest','latest']
+ :return: json of resourcebase
+ """
+ resourcebase_dict = {}
+ count = 0
+ if request.POST.has_key('type'):
+ type = request.POST['type']
+ # if type==admin key='owner_id' elseif type==hottest key=popular_count else type==latest key =date
+ # order_by('-key'): the same with order by(key) asce
+ if type == 'admin':
+ key = 'owner_id'
+ else:
+ key = '-popular_count' if type == 'hottest' else '-date'
+ if request.POST['category'] != '0':
+ categoryid = int(request.POST['category'])
+ resourcebase_queryset = ResourceBase.objects.instance_of(Map).filter(category_id=categoryid).order_by(key)[0:5]
+ else:
+ resourcebase_queryset = ResourceBase.objects.instance_of(Map).all().order_by(key,'-date')[0:5]
+ count = 0
+ for resourcebase in resourcebase_queryset:
+ resourcebase_dict[count] = [resourcebase.title, resourcebase.thumbnail_url, resourcebase.detail_url]
+ count = count + 1
+ resourcebase_json = json.dumps(resourcebase_dict)
+ return HttpResponse(resourcebase_json)
+
+# def get_hottest_maps(request):
+# """
+# return the six hottest maps of the appointed cateory
+# :param request:
+# :return:
+# """
+# hottestmapstats = MapStats.objects.order_by('-visits').values('map_id')
+# resourcebase_dict = {}
+# count = 0
+# if request.POST.has_key('category'):
+# categoryid = int(request.POST['category'])
+# for mapstats in hottestmapstats:
+# if(count > 5):
+# break
+# try:
+# resourcebase = ResourceBase.objects.get(id=mapstats['map_id'], category_id=categoryid)
+# except:
+# count =count
+# else:
+# resourcebase_dict[count] = [resourcebase.title, resourcebase.thumbnail_url, resourcebase.detail_url]
+# count = count +1
+# else:
+# for mapstats in hottestmapstats:
+# if(count > 5):
+# break
+# try:
+# resourcebase = ResourceBase.objects.get(id=mapstats['map_id'])
+# except:
+# count = count
+# else:
+# resourcebase_dict[count] = [resourcebase.title, resourcebase.thumbnail_url, resourcebase.detail_url]
+# count = count + 1
+# # return HttpResponse(simplejson.dumps(hottestresourcebase, ensure_ascii=False))
+# resourcebasejson = json.dumps(resourcebase_dict)
+# return HttpResponse(resourcebasejson)
\ No newline at end of file
diff --git a/worldmap-migration/README.md b/worldmap-migration/README.md
index fe81c41..eb84d39 100644
--- a/worldmap-migration/README.md
+++ b/worldmap-migration/README.md
@@ -4,87 +4,25 @@ Worldmap Database migrations....written in pure shell
Usage
=====
-The code is made in bash for the migration of an old version of worldmap to the current version. In order for the migration process to be done correctly, please follow the instructions below.
-1. Make sure to load the sql dump from old worldmap database. It is necessary to make a copy, wr don't recommend to use the original db because we dont want to lose information To clarify, `$OLD_DB` corresponds to the name that we will assign to the database that is the copy of the old worldmap database. And `$SQL_DUMP_PATH` is the path from dump file of old worldmap database which we should generate before to do this process.
-
- sudo -u $DB_USER psql -c "CREATE DATABASE $OLD_DB"
+1. Make sure to load the sql dump.
- sudo -u $DB_USER psql -d $OLD_DB < $SQL_DUMP_PATH
+ sudo -u $DB_USER psql -c "CREATE DATABASE $OLD_DB"
-2. Getting styles for Geoserver.
+ sudo -u $DB_USER psql -d $OLD_DB < $SQL_DUMP_PATH
- 2.1. Copy styles_migration.sh to GEOSERVER DATA DIRECTORY
-
- cp styles_migration.sh /path/to/data/dir/geoserver
-
- 2.2. Edit GEOSERVER_URL and STYLES_FOLDER. Make sure `GEOSERVER_URL` corresponds to public location and `STYLES_FOLDER` is the directory where geoserver saves the styles.
-
- vim styles_migration.sh
- 2.3. Generate `styles.csv`.
-
- ./styles_migration.sh
-3. Configurate some env variables. Please edit config.sh file.
+2. Run migration scripts
-
-```
-
- export USER=postgres
- export OLD_DB=Name_for_backup_database_of_old_worldmap
- export DB_USER=worldmap #DATABASE OWNER
- export DB_PW=password #OWNER USER PASSWORD
- export PGPASSWORD=$DB_PW
- export DB_HOST=localhost #database host location
- export NEW_DB=new_one_database_name
- export GEONODE_PATH=/home/paolo/worldmap #Worldmap location, if you will do the migration locally
- export GEOSERVER_URL=http://128.31.22.83:8080/geoserver/ #GEOSERVER LOCATION
- export ENV_PATH=/path/to/env
- export DATABASE_URL=postgis://$DB_USER:$DB_PW@$DB_HOST:5432/$NEW_DB
- export STYLES_PATH=/path/to/styles/csv/file #you can find this file inside geoserver directory
-
-```
+ chmod +x main.sh
+ source main.sh -d $OLD_DB
-4. Run migration scripts
+If you wanna migrate geoserver styles
+ source main.sh --database $OLD_DB --styles
- chmod +x main.sh
- chmod -R +x scripts/
- 4.1 If you want to run django migration using the django server. Dont forget to edit `/home/ubuntu/wm.sh` file in your djando server and add new `DATABASE_URL`.
-
- source main.sh --database $OLD_DB
- For example:
- source main.sh --database worldmaplegacy
- 4.2 If you wan to run django migration locally. Remind to set correctly `GEONODE_PATH` and `ENV_PATH`.
-
- source main.sh --database worldmaplegacy --local
-
- 4.3 Migration with geoserver styles:
-
- - Remote mode
- source main.sh --database $OLD_DB --styles
-
- -Locally mode
- source main.sh --database $OLD_DB --styles --local
**Notes**
- Make sure you have loaded your database dump.
- Make sure you have the geoserver styles tables within files.
-
-
-Other things to do during migration
-===================================
-
-* install GDAL GeoServer plugin
-* run django find_geoserver_broken_layers to check if some layers was not imported
-* truncate styles and links table
-* run django fix_migrated_layers (regenerate styles, links and thumbnails)
-* run django sync_geofence command
-
-GeoServer data Directory
-========================
-
-* security directory must be removed, and we need to use the one which comes with geoserver-2.12.x.war
-* add geofence directory (included in geoserver-2.12.x.war)
-* configure security (input oauth parameters)
diff --git a/worldmap-migration/main.sh b/worldmap-migration/main.sh
index 663c9ac..ff255d6 100755
--- a/worldmap-migration/main.sh
+++ b/worldmap-migration/main.sh
@@ -65,16 +65,7 @@ sudo -u $USER PGPASSWORD=$DB_PW psql -c "CREATE DATABASE $NEW_DB;"
sudo -u $USER PGPASSWORD=$DB_PW \
psql -v ON_ERROR_STOP=1 -U $DB_USER -h $DB_HOST -d $NEW_DB -c \
"CREATE EXTENSION postgis;"
-do_hr
-echo "CREATE EXTENSION FOR UUID"
-sudo -u $USER PGPASSWORD=$DB_PW \
-psql -v ON_ERROR_STOP=1 -U $DB_USER -h $DB_HOST -d $OLD_DB -c \
- 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";'
-sudo -u $USER PGPASSWORD=$DB_PW \
-psql -v ON_ERROR_STOP=1 -U $DB_USER -h $DB_HOST -d $NEW_DB -c \
- 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";'
-do_hr
#############################################################################
if [ $LOCAL ]; then
@@ -83,7 +74,6 @@ echo "Generating tables locally"
do_hr
source $ENV_PATH/bin/activate
-#python $GEONODE_PATH/manage.py makemigrations --noinput
python $GEONODE_PATH/manage.py migrate
# python $GEONODE_PATH/manage.py loaddata $GEONODE_PATH/fixtures/default_oauth_apps.json
else
diff --git a/worldmap-migration/scripts/maps.sh b/worldmap-migration/scripts/maps.sh
index 904d06d..f8a400f 100755
--- a/worldmap-migration/scripts/maps.sh
+++ b/worldmap-migration/scripts/maps.sh
@@ -31,7 +31,7 @@ MAP_CT_ID=$(sudo -u $USER psql $NEW_DB -c \
echo "\nCopying elements into resourcebase table"; do_dash
sudo -u $USER PGPASSWORD=$DB_PW \
psql -v ON_ERROR_STOP=1 -U $DB_USER -h $DB_HOST $OLD_DB -c \
- "copy (select base_id, $MAP_CT_ID, uuid_generate_v5(uuid_ns_url(), 'base_id'), owner_id, title, last_modified, 'date_type', abstract, 'eng', 'supplemental_information', 'EPSG:4326', 'csw_typename', 'csw_schema', 'csw_mdsource', 'csw_type', 'csw_wkt_geometry', false, 0, 0, false, false, false, CONCAT('/maps/', base_id), false from augmented_maps_map) to stdout with csv" | \
+ "copy (select base_id, $MAP_CT_ID, 'uuid', owner_id, title, last_modified, 'date_type', abstract, 'eng', 'supplemental_information', 'EPSG:4326', 'csw_typename', 'csw_schema', 'csw_mdsource', 'csw_type', 'csw_wkt_geometry', false, 0, 0, false, false, false, CONCAT('/maps/', base_id), false from augmented_maps_map) to stdout with csv" | \
sudo -u $USER \
psql $NEW_DB -c 'copy base_resourcebase (id, polymorphic_ctype_id, uuid, owner_id, title, date, date_type, abstract, language, supplemental_information, srid, csw_typename, csw_schema, csw_mdsource, csw_type, csw_wkt_geometry, metadata_uploaded, popular_count, share_count, featured, is_published, metadata_uploaded_preserve, detail_url, is_approved) from stdin csv'
diff --git a/worldmap/context_processors.py b/worldmap/context_processors.py
index efbc120..2980a45 100644
--- a/worldmap/context_processors.py
+++ b/worldmap/context_processors.py
@@ -11,7 +11,5 @@ def worldmap(request):
'HYPERMAP_REGISTRY_URL': settings.HYPERMAP_REGISTRY_URL,
'MAPPROXY_URL': settings.MAPPROXY_URL,
'SOLR_URL': settings.SOLR_URL,
- 'USE_GAZETTEER': settings.USE_GAZETTEER,
- 'GOOGLE_API_KEY': settings.GOOGLE_API_KEY,
- 'GOOGLE_MAPS_API_KEY': settings.GOOGLE_MAPS_API_KEY
+ 'USE_GAZETTEER': settings.USE_GAZETTEER
}
diff --git a/worldmap/locale/zh/LC_MESSAGES/django.po b/worldmap/locale/zh/LC_MESSAGES/django.po
index 73e60a3..ea7b23b 100644
--- a/worldmap/locale/zh/LC_MESSAGES/django.po
+++ b/worldmap/locale/zh/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-11-06 09:01-0600\n"
+"POT-Creation-Date: 2017-11-14 05:10-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -20,83 +20,91 @@ msgstr ""
#: wm_extra/accounts/forms.py:32 worldmap/templates/base.html:155
#: worldmap/templates/base.html.py:156
msgid "Username"
-msgstr ""
+msgstr "用户名"
#: wm_extra/accounts/forms.py:38 worldmap/templates/base.html:159
#: worldmap/templates/base.html.py:160
msgid "Password"
-msgstr ""
+msgstr "密码"
#: wm_extra/accounts/forms.py:42
msgid "Password (again)"
-msgstr ""
+msgstr "确认密码"
#: wm_extra/accounts/forms.py:46
#: worldmap/templates/people/profile_detail.html:73
msgid "Email"
-msgstr ""
+msgstr "Email"
#: wm_extra/accounts/forms.py:57
msgid "Yes"
-msgstr ""
+msgstr "是的"
#: wm_extra/accounts/forms.py:57
msgid "No"
-msgstr ""
+msgstr "不是"
+
+#: wm_extra/accounts/forms.py:61
+msgid "Are you affiliated with Zhejiang University?"
+msgstr "是否从属于浙江大学?"
+
+#: wm_extra/accounts/forms.py:64
+msgid "I agree to the Terms and Conditions "
+msgstr "我已阅读并同意相关条款 "
#: wm_extra/accounts/forms.py:67
msgid "Usernames can only contain letters, numbers, dots and underscores."
-msgstr ""
+msgstr "用户名只能包含字母、数字、标点和下划线。"
#: wm_extra/accounts/forms.py:75
msgid "This username is already taken. Please choose another."
-msgstr ""
+msgstr "该用户名已存在,请使用其他用户名。"
#: wm_extra/accounts/forms.py:82
msgid "A user is registered with this email address."
-msgstr ""
+msgstr "该邮件地址已被其他用户注册。"
#: wm_extra/accounts/forms.py:87
msgid "You must type the same password each time."
-msgstr ""
+msgstr "密码和确认密码不一致。"
#: wm_extra/accounts/views.py:42
#, python-brace-format
msgid "Confirmation email sent to {email}."
-msgstr ""
+msgstr "确认邮件已经发送至{email}。"
#: wm_extra/accounts/views.py:46
#, python-brace-format
msgid "The code {code} is invalid."
-msgstr ""
+msgstr "该验证码{code}是无效的。"
#: wm_extra/models.py:11 wm_extra/models.py:21
msgid "Visits"
-msgstr ""
+msgstr "访问量"
#: wm_extra/models.py:12 wm_extra/models.py:22
msgid "Unique Visitors"
-msgstr ""
+msgstr "访客量"
#: wm_extra/models.py:23
msgid "Downloads"
-msgstr ""
+msgstr "下载"
#: wm_extra/models.py:34
msgid "Describe Map Service"
-msgstr ""
+msgstr "描述地图服务"
#: wm_extra/models.py:35
msgid "Map service URL"
-msgstr ""
+msgstr "地图服务地址"
#: wm_extra/templates/wm_extra/endpoint_add.html:6
msgid "Suggests an Endpoint"
-msgstr ""
+msgstr "建议一个端点"
#: wm_extra/templates/wm_extra/endpoint_add.html:13
msgid "Submit Map Service URL"
-msgstr ""
+msgstr "提交地图服务地址"
#: wm_extra/templates/wm_extra/endpoint_add.html:16
msgid ""
@@ -105,12 +113,16 @@ msgid ""
"organization hosting the map service, the source of the data, and the year "
"or year range the data represents."
msgstr ""
+"请描述地图服务的制图类型(比如道路、河流要素、历史地图、卫星影像等等),管理地图服务的机构,"
+"数据的来源,数据代表的年份或者年份范围。"
+
#: wm_extra/templates/wm_extra/endpoint_add.html:17
msgid ""
"Service harvesting and loading to WorldMap is currently a manual process so "
"it may take some time for your map service layers to appear in search."
-msgstr ""
+msgstr "服务获取并加载至世界地图,目前还是一个手动操作的过程。"
+"所以地图服务图层搜索结果的呈现可能会花费一段时间"
#: wm_extra/templates/wm_extra/endpoint_add.html:18
msgid ""
@@ -118,264 +130,274 @@ msgid ""
"service endpoint types. If you are not sure what you have, feel free to "
"submit it and we will attempt to load it."
msgstr ""
-
+"该系统现在支持OGC、WMS、CSW和Esri Image和 Map "
+"service endpoint types。如果不确定你的系统是什么,你"
+"可以提交它,随后我们将会尝试加载它。"
#: wm_extra/templates/wm_extra/endpoint_add.html:19
msgid ""
"Write us at worldmap@harvard.edu if you have any questions. Thank you for "
"your contribution."
msgstr ""
+"如果你有任何问题,请写邮件给我们worldmap@harvard.edu。非常感谢你的贡献。"
#: wm_extra/templates/wm_extra/endpoint_add.html:23
msgid "Submit map service URL"
-msgstr ""
+msgstr "提交地图服务地址"
#: wm_extra/templates/wm_extra/endpoint_added.html:6
#: wm_extra/templates/wm_extra/endpoint_added.html:13
msgid "Endpoint Suggested"
-msgstr ""
+msgstr "端点建议"
#: wm_extra/templates/wm_extra/endpoint_added.html:16
msgid "Thanks"
-msgstr ""
+msgstr "谢谢"
#: wm_extra/templates/wm_extra/endpoint_added.html:16
msgid "for suggesting the endpoint"
-msgstr ""
+msgstr "对于建议端点"
#: worldmap/certification/templates/certification/certification_add.html:13
msgid "Are you sure you want to certify"
-msgstr ""
+msgstr "你确定你想要认证"
#: worldmap/certification/templates/certification/certification_add.html:16
msgid "Yes, certify"
-msgstr ""
+msgstr "是的,认证"
#: worldmap/certification/templates/certification/certification_add.html:19
#: worldmap/certification/templates/certification/certification_remove.html:22
msgid "No, cancel"
-msgstr ""
+msgstr "不了,取消"
#: worldmap/certification/templates/certification/certification_add.html:30
msgid "Certify"
-msgstr ""
+msgstr "认证"
#: worldmap/certification/templates/certification/certification_remove.html:16
msgid "Are you sure you want to uncertify"
-msgstr ""
+msgstr "你确定你不想要认证"
#: worldmap/certification/templates/certification/certification_remove.html:19
msgid "Yes, uncertify"
-msgstr ""
+msgstr "是的,不认证"
#: worldmap/certification/templates/certification/certification_remove.html:33
msgid "Uncertify"
-msgstr ""
+msgstr "不认证"
#: worldmap/templates/base.html:53 worldmap/templates/site_index.html:54
msgid "Create Map"
-msgstr ""
+msgstr "创建地图"
#: worldmap/templates/base.html:54 worldmap/templates/maps/map_detail.html:163
#: worldmap/templates/site_index.html:55
msgid "View Map"
-msgstr ""
+msgstr "查看地图"
#: worldmap/templates/base.html:58
msgid "Profile"
-msgstr ""
+msgstr "个人简介"
#: worldmap/templates/base.html:59
msgid "Recent Activity"
-msgstr ""
+msgstr "最近活动"
#: worldmap/templates/base.html:60
msgid "Inbox"
-msgstr ""
+msgstr "收件箱"
#: worldmap/templates/base.html:65
msgid "Help"
-msgstr ""
+msgstr "帮助"
#: worldmap/templates/base.html:71 worldmap/templates/base.html.py:146
#: worldmap/templates/base.html:167
msgid "Sign in"
-msgstr ""
+msgstr "登录"
#: worldmap/templates/base.html:111
msgid "Need Help?"
-msgstr ""
+msgstr "需要帮助?"
#: worldmap/templates/base.html:112
msgid "Contact Us"
-msgstr ""
+msgstr "联系我们"
#: worldmap/templates/base.html:113
msgid "Source Code"
-msgstr ""
+msgstr "源代码"
#: worldmap/templates/base.html:114
msgid "Report Copyright Infringement"
-msgstr ""
+msgstr "报告侵权"
#: worldmap/templates/base.html:115
msgid "Copyright 2017 © The President and Fellows of Harvard College"
-msgstr ""
+msgstr "版权 2017 © 哈佛大学的主席和他的同事"
#: worldmap/templates/base.html:118
msgid "Language"
-msgstr ""
+msgstr "语言"
#: worldmap/templates/base.html:151
msgid "Register"
-msgstr ""
+msgstr "注册"
#: worldmap/templates/base.html:163
msgid "Remember Me"
-msgstr ""
+msgstr "记住我"
#: worldmap/templates/base.html:204
msgid "Type your search here ..."
-msgstr ""
+msgstr "在这输入关键词......"
+#: worldmap/templates/base.html:140
+msgid "Worldmap Help "
+msgstr "Worldmap帮助文档 "
+
+#: worldmap/templates/base.html:142
+msgid "GeoNode Help"
+msgstr "GeoNode简介"
#: worldmap/templates/base/_resourcebase_snippet.html:44
#: worldmap/templates/layers/layer_detail.html:453
msgid "Create a Map"
-msgstr ""
+msgstr "创建地图"
#: worldmap/templates/createlayer/layer_create.html:7
#: worldmap/templates/site_index.html:58
msgid "Create Layer"
-msgstr ""
+msgstr "创建图层"
#: worldmap/templates/createlayer/layer_create.html:20
msgid "Create an empty layer"
-msgstr ""
+msgstr "创建空的图层"
#: worldmap/templates/createlayer/layer_create.html:38
msgid "Add Attribute"
-msgstr ""
+msgstr "添加属性"
#: worldmap/templates/createlayer/layer_create.html:45
msgid "Create"
-msgstr ""
+msgstr "创建"
#: worldmap/templates/createlayer/layer_create.html:54
#: worldmap/templates/layers/layer_detail.html:511
#: worldmap/templates/maps/map_detail.html:202
#: worldmap/templates/upload/layer_upload.html:118
msgid "Permissions"
-msgstr ""
+msgstr "许可"
#: worldmap/templates/fullscreen.html:5
msgid "WorldMap"
-msgstr ""
+msgstr "世界地图"
#: worldmap/templates/layers/layer_detail.html:67
msgid "Filter Granules"
-msgstr ""
+msgstr "过滤颗粒"
#: worldmap/templates/layers/layer_detail.html:70
msgid "Active Filter:"
-msgstr ""
+msgstr "激活过滤器"
#: worldmap/templates/layers/layer_detail.html:76
msgid "Granule ID"
-msgstr ""
+msgstr "颗粒ID"
#: worldmap/templates/layers/layer_detail.html:77
msgid "Bounding Box"
-msgstr ""
+msgstr "包围盒"
#: worldmap/templates/layers/layer_detail.html:78
msgid "Time"
-msgstr ""
+msgstr "时间"
#: worldmap/templates/layers/layer_detail.html:79
msgid "Elevation"
-msgstr ""
+msgstr "高程"
#: worldmap/templates/layers/layer_detail.html:80
msgid "Actions"
-msgstr ""
+msgstr "操作"
#: worldmap/templates/layers/layer_detail.html:142
msgid "Dimension"
-msgstr ""
+msgstr "维度"
#: worldmap/templates/layers/layer_detail.html:143
msgid "Enabled"
-msgstr ""
+msgstr "可用的"
#: worldmap/templates/layers/layer_detail.html:144
msgid "Regex"
-msgstr ""
+msgstr "正则表达式"
#: worldmap/templates/layers/layer_detail.html:149
msgid "TIME"
-msgstr ""
+msgstr "时间"
#: worldmap/templates/layers/layer_detail.html:150
#: worldmap/templates/layers/layer_detail.html:155
msgid "True"
-msgstr ""
+msgstr "正确"
#: worldmap/templates/layers/layer_detail.html:150
#: worldmap/templates/layers/layer_detail.html:155
msgid "False"
-msgstr ""
+msgstr "错误"
#: worldmap/templates/layers/layer_detail.html:154
msgid "ELEVATION"
-msgstr ""
+msgstr "高程"
#: worldmap/templates/layers/layer_detail.html:165
msgid "Attribute Name"
-msgstr ""
+msgstr "属性名"
#: worldmap/templates/layers/layer_detail.html:166
#: worldmap/templates/layers/layer_metadata_advanced.html:105
msgid "Label"
-msgstr ""
+msgstr "标签"
#: worldmap/templates/layers/layer_detail.html:167
#: worldmap/templates/layers/layer_metadata_advanced.html:106
#: worldmap/templates/people/profile_detail.html:107
msgid "Description"
-msgstr ""
+msgstr "描述"
#: worldmap/templates/layers/layer_detail.html:169
msgid "Range"
-msgstr ""
+msgstr "范围"
#: worldmap/templates/layers/layer_detail.html:170
msgid "Average"
-msgstr ""
+msgstr "平均值"
#: worldmap/templates/layers/layer_detail.html:171
msgid "Median"
-msgstr ""
+msgstr "中位数"
#: worldmap/templates/layers/layer_detail.html:172
msgid "Standard Deviation"
-msgstr ""
+msgstr "标准偏差"
#: worldmap/templates/layers/layer_detail.html:233
msgid "Rate this layer"
-msgstr ""
+msgstr "给该图层评分"
#: worldmap/templates/layers/layer_detail.html:237
#: worldmap/templates/maps/map_detail.html:74
msgid "Average Rating"
-msgstr ""
+msgstr "平均分"
#: worldmap/templates/layers/layer_detail.html:254
#: worldmap/templates/layers/layer_detail.html:267
msgid "Download Layer"
-msgstr ""
+msgstr "下载图层"
#: worldmap/templates/layers/layer_detail.html:257
msgid "Request Download"
-msgstr ""
+msgstr "请求下载"
#: worldmap/templates/layers/layer_detail.html:306
#: worldmap/templates/layers/layer_detail.html:370
@@ -383,177 +405,181 @@ msgstr ""
#: worldmap/templates/maps/map_detail.html:112
#: worldmap/templates/maps/map_detail.html:156
msgid "Close"
-msgstr ""
+msgstr "关闭"
#: worldmap/templates/layers/layer_detail.html:318
#: worldmap/templates/maps/map_detail.html:94
msgid "Metadata Detail"
-msgstr ""
+msgstr "元数据详细信息"
#: worldmap/templates/layers/layer_detail.html:324
#: worldmap/templates/layers/layer_detail.html:331
msgid "Edit Layer"
-msgstr ""
+msgstr "编辑图层"
#: worldmap/templates/layers/layer_detail.html:338
#: worldmap/templates/maps/map_detail.html:133
msgid "Metadata"
-msgstr ""
+msgstr "元数据"
#: worldmap/templates/layers/layer_detail.html:339
#: worldmap/templates/maps/map_detail.html:134
msgid "Wizard"
-msgstr ""
+msgstr "向导"
#: worldmap/templates/layers/layer_detail.html:340
#: worldmap/templates/maps/map_detail.html:135
msgid "Advanced Edit"
-msgstr ""
+msgstr "高级编辑"
#: worldmap/templates/layers/layer_detail.html:341
msgid "Upload Metadata"
-msgstr ""
+msgstr "上传元数据"
#: worldmap/templates/layers/layer_detail.html:348
#: worldmap/templates/maps/map_detail.html:141
msgid "Thumbnail"
-msgstr ""
+msgstr "缩略图"
#: worldmap/templates/layers/layer_detail.html:349
#: worldmap/templates/maps/map_detail.html:142
msgid "Set"
-msgstr ""
+msgstr "设置"
#: worldmap/templates/layers/layer_detail.html:355
msgid "Layer"
-msgstr ""
+msgstr "图层"
#: worldmap/templates/layers/layer_detail.html:357
msgid "Replace"
-msgstr ""
+msgstr "替换"
#: worldmap/templates/layers/layer_detail.html:360
msgid "Edit data"
-msgstr ""
+msgstr "编辑数据"
#: worldmap/templates/layers/layer_detail.html:363
#: worldmap/templates/maps/map_detail.html:150
msgid "Remove"
-msgstr ""
+msgstr "移除"
#: worldmap/templates/layers/layer_detail.html:378
#: worldmap/templates/layers/layer_detail.html:386
msgid "Download Metadata"
-msgstr ""
+msgstr "下载元数据"
#: worldmap/templates/layers/layer_detail.html:424
msgid "Legend"
-msgstr ""
+msgstr "比例尺"
#: worldmap/templates/layers/layer_detail.html:438
msgid "Maps using this layer"
-msgstr ""
+msgstr "使用该图层的地图"
#: worldmap/templates/layers/layer_detail.html:440
msgid "List of maps using this layer:"
-msgstr ""
+msgstr "使用该图层的地图列表:"
#: worldmap/templates/layers/layer_detail.html:446
msgid "This layer is not currently used in any maps."
-msgstr ""
+msgstr "该图层现在未被任何地图使用。"
#: worldmap/templates/layers/layer_detail.html:451
msgid "Create a map using this layer"
-msgstr ""
+msgstr "创建使用该图层的地图"
#: worldmap/templates/layers/layer_detail.html:452
msgid "Click the button below to generate a new map based on this layer."
-msgstr ""
+msgstr "点击下方按钮生成一个基于该图层的新地图。"
#: worldmap/templates/layers/layer_detail.html:457
msgid "Add the layer to an existing map"
-msgstr ""
+msgstr "给已存在的地图添加图层"
#: worldmap/templates/layers/layer_detail.html:465
msgid "Click the button below to add the layer to the selected map."
-msgstr ""
+msgstr "点击下方按钮添加图层到选中地图。"
#: worldmap/templates/layers/layer_detail.html:467
msgid "Add to Map"
-msgstr ""
+msgstr "添加到地图"
#: worldmap/templates/layers/layer_detail.html:474
msgid "Documents related to this layer"
-msgstr ""
+msgstr "关于该图层的文档"
#: worldmap/templates/layers/layer_detail.html:475
msgid "List of documents related to this layer:"
-msgstr ""
+msgstr "关于该图层的文档列表:"
#: worldmap/templates/layers/layer_detail.html:488
msgid "Styles"
-msgstr ""
+msgstr "样式"
#: worldmap/templates/layers/layer_detail.html:489
msgid ""
"The following styles are associated with this layer. Choose a style to view "
"it in the preview map."
msgstr ""
-
+"下列样式与该图层有关。选择一种样式在预览地图中浏览。"
#: worldmap/templates/layers/layer_detail.html:502
msgid "No styles associated with this layer"
-msgstr ""
+msgstr "没有该图层相关的样式"
+
+#: worldmap/templates/layers/layer_detail.html:505
+msgid "(default style)"
+msgstr "(默认样式)"
#: worldmap/templates/layers/layer_detail.html:512
msgid "Click the button below to change the permissions of this layer."
-msgstr ""
+msgstr "点击下方按钮改变该图层的许可"
#: worldmap/templates/layers/layer_detail.html:513
msgid "Change Layer Permissions"
-msgstr ""
+msgstr "改变图层许可"
#: worldmap/templates/layers/layer_detail.html:522
#: worldmap/templates/maps/map_detail.html:232
msgid "Certifications"
-msgstr ""
+msgstr "认证"
#: worldmap/templates/layers/layer_detail.html:529
msgid "This layer has not been certified by any users."
-msgstr ""
+msgstr "该图层还未被任何用户认证"
#: worldmap/templates/layers/layer_detail.html:537
msgid "Uncertify this layer."
-msgstr ""
+msgstr "该图层未认证"
#: worldmap/templates/layers/layer_detail.html:541
msgid "Certify this layer."
-msgstr ""
+msgstr "认证该图层"
#: worldmap/templates/layers/layer_detail.html:551
msgid "External service layer"
-msgstr ""
+msgstr "该图层的外部服务"
#: worldmap/templates/layers/layer_detail.html:552
msgid "Source"
-msgstr ""
+msgstr "来源"
#: worldmap/templates/layers/layer_detail.html:553
msgid "Type"
-msgstr ""
+msgstr "类型"
#: worldmap/templates/layers/layer_list.html:6
#: worldmap/templates/layers/layer_list.html:13
msgid "Explore Layers"
-msgstr ""
+msgstr "浏览图层"
#: worldmap/templates/layers/layer_list.html:12
#: worldmap/templates/upload/layer_upload.html:17
msgid "Upload Layers"
-msgstr ""
+msgstr "上传图层"
#: worldmap/templates/layers/layer_metadata_advanced.html:16
msgid "Edit Metadata"
-msgstr ""
+msgstr "编辑元数据"
#: worldmap/templates/layers/layer_metadata_advanced.html:21
#, python-format
@@ -562,6 +588,9 @@ msgid ""
" Editing details for %(layer_title)s\n"
" "
msgstr ""
+"\n"
+" 为%(layer_title)s编辑详细信息\n"
+" "
#: worldmap/templates/layers/layer_metadata_advanced.html:27
msgid ""
@@ -569,6 +598,8 @@ msgid ""
"a metadata XML file.\n"
" This metadata cannot be edited."
msgstr ""
+"注意:该图层的原始元数据通过导入一个元数据XML文件来保存的。\n"
+" 该元数据不可被编辑。"
#: worldmap/templates/layers/layer_metadata_advanced.html:30
msgid ""
@@ -578,165 +609,168 @@ msgid ""
"Dublin Core metadata elements.\n"
" Some of your original metadata may have been lost."
msgstr ""
+"注:此图的原单的元数据被填充通过导入元数据的XML文件。"
+" GeoNode的元数据导入支持ISO,FGDC和都柏林核心元数据元素的一个子集。"
+" 一些你原来的元数据可能已经丢失。"
#: worldmap/templates/layers/layer_metadata_advanced.html:36
msgid "Error updating metadata. Please check the following fields: "
-msgstr ""
+msgstr "更新元数据时发生错误。请检查下列区域:"
#: worldmap/templates/layers/layer_metadata_advanced.html:39
msgid "Metadata Author"
-msgstr ""
+msgstr "元数据作者"
#: worldmap/templates/layers/layer_metadata_advanced.html:43
#: worldmap/templates/layers/layer_metadata_advanced.html:122
msgid "Point of Contact"
-msgstr ""
+msgstr "联系点"
#: worldmap/templates/layers/layer_metadata_advanced.html:52
#: worldmap/templates/layers/layer_metadata_advanced.html:100
msgid "Attributes"
-msgstr ""
+msgstr "属性"
#: worldmap/templates/layers/layer_metadata_advanced.html:67
#: worldmap/templates/layers/layer_metadata_advanced.html:134
msgid "Update"
-msgstr ""
+msgstr "更新"
#: worldmap/templates/layers/layer_metadata_advanced.html:77
msgid "Category"
-msgstr ""
+msgstr "分类"
#: worldmap/templates/layers/layer_metadata_advanced.html:104
msgid "Attribute"
-msgstr ""
+msgstr "属性"
#: worldmap/templates/layers/layer_metadata_advanced.html:107
msgid "Display Order"
-msgstr ""
+msgstr "显示顺序"
#: worldmap/templates/layers/layer_metadata_advanced.html:127
msgid "Metadata Provider"
-msgstr ""
+msgstr "元数据提供者"
#: worldmap/templates/maps/map_detail.html:70
msgid "Rate this Map"
-msgstr ""
+msgstr "给该地图评分"
#: worldmap/templates/maps/map_detail.html:88
#: worldmap/templates/maps/map_detail.html:103
msgid "Download Map"
-msgstr ""
+msgstr "下载地图"
#: worldmap/templates/maps/map_detail.html:107
msgid "Download Data Layers"
-msgstr ""
+msgstr "下载数据图层"
#: worldmap/templates/maps/map_detail.html:108
msgid "Download Web Map Context"
-msgstr ""
+msgstr "下载网络地图环境"
#: worldmap/templates/maps/map_detail.html:119
#: worldmap/templates/maps/map_detail.html:126
msgid "Edit Map"
-msgstr ""
+msgstr "编辑地图"
#: worldmap/templates/maps/map_detail.html:148
#: worldmap/templates/maps/map_view.html:6
msgid "Map"
-msgstr ""
+msgstr "地图"
#: worldmap/templates/maps/map_detail.html:149
msgid "Edit"
-msgstr ""
+msgstr "编辑"
#: worldmap/templates/maps/map_detail.html:173
msgid "Map Layers"
-msgstr ""
+msgstr "地图图层"
#: worldmap/templates/maps/map_detail.html:174
msgid "This map uses the following layers:"
-msgstr ""
+msgstr "该地图使用了下列图层:"
#: worldmap/templates/maps/map_detail.html:190
msgid "Documents related to this map"
-msgstr ""
+msgstr "该地图有关的文档"
#: worldmap/templates/maps/map_detail.html:191
msgid "List of documents related to this map:"
-msgstr ""
+msgstr "该地图有关的文档表"
#: worldmap/templates/maps/map_detail.html:203
msgid "Specify which users can view or modify this map"
-msgstr ""
+msgstr "指定哪个用户可以查看或者修改该地图"
#: worldmap/templates/maps/map_detail.html:204
msgid "Change Permissions of this Map"
-msgstr ""
+msgstr "更改该地图的许可"
#: worldmap/templates/maps/map_detail.html:210
msgid "Copy this map"
-msgstr ""
+msgstr "复制该地图"
#: worldmap/templates/maps/map_detail.html:211
msgid "Duplicate this map and modify it for your own purposes"
-msgstr ""
+msgstr "复制该地图,按照你的意愿修改它"
#: worldmap/templates/maps/map_detail.html:212
#: worldmap/templates/maps/map_list.html:16
msgid "Create a New Map"
-msgstr ""
+msgstr "创建新地图"
#: worldmap/templates/maps/map_detail.html:217
msgid "Map WMS"
-msgstr ""
+msgstr "地图WMS"
#: worldmap/templates/maps/map_detail.html:219
msgid "WMS layer group for local map layers"
-msgstr ""
+msgstr "给本地地图图层的WMS图层组"
#: worldmap/templates/maps/map_detail.html:220
msgid "on"
-msgstr ""
+msgstr "在"
#: worldmap/templates/maps/map_detail.html:220
msgid "local OWS"
-msgstr ""
+msgstr "本地OWS"
#: worldmap/templates/maps/map_detail.html:223
msgid "Publish local map layers as WMS layer group"
-msgstr ""
+msgstr "以WMS图层组形式发布本地地图图层"
#: worldmap/templates/maps/map_detail.html:224
msgid "Publish Map WMS"
-msgstr ""
+msgstr "发布地图WMS"
#: worldmap/templates/maps/map_detail.html:239
msgid "This map has not been certified by any users"
-msgstr ""
+msgstr "该地图还未被任何用户认证"
#: worldmap/templates/maps/map_detail.html:247
msgid "Uncertify this map"
-msgstr ""
+msgstr "该地图未认证"
#: worldmap/templates/maps/map_detail.html:251
msgid "Certify this map"
-msgstr ""
+msgstr "认证该地图"
#: worldmap/templates/maps/map_list.html:13
msgid "Search for maps"
-msgstr ""
+msgstr "搜索地图"
#: worldmap/templates/maps/map_list.html:22
msgid "Search by text"
-msgstr ""
+msgstr "通过文本搜索"
#: worldmap/templates/maps/map_new.html:6
msgid "New Map"
-msgstr ""
+msgstr "新地图"
#: worldmap/templates/people/profile_detail.html:12
msgid "Profile of "
-msgstr ""
+msgstr "简介-"
#: worldmap/templates/people/profile_detail.html:77
#: worldmap/templates/people/profile_detail.html:83
@@ -745,266 +779,414 @@ msgstr ""
#: worldmap/templates/people/profile_detail.html:104
#: worldmap/templates/people/profile_detail.html:108
msgid "Not provided."
-msgstr ""
+msgstr "未提供。"
#: worldmap/templates/people/profile_detail.html:82
msgid "Position"
-msgstr ""
+msgstr "职位"
#: worldmap/templates/people/profile_detail.html:86
msgid "Organization"
-msgstr ""
+msgstr "组织"
#: worldmap/templates/people/profile_detail.html:91
msgid "Location"
-msgstr ""
+msgstr "位置"
#: worldmap/templates/people/profile_detail.html:95
msgid "Voice"
-msgstr ""
+msgstr "声音"
#: worldmap/templates/people/profile_detail.html:103
msgid "Fax"
-msgstr ""
+msgstr "传真"
#: worldmap/templates/people/profile_detail.html:112
msgid "Keywords"
-msgstr ""
+msgstr "关键词"
#: worldmap/templates/people/profile_detail.html:119
msgid "Not provided"
-msgstr ""
+msgstr "未提供"
#: worldmap/templates/people/profile_detail.html:129
msgid "Message User"
-msgstr ""
+msgstr "消息用户"
#: worldmap/templates/people/profile_detail.html:133
#: worldmap/templates/people/profile_detail.html:167
msgid "Edit profile"
-msgstr ""
+msgstr "编辑简介"
#: worldmap/templates/people/profile_detail.html:134
msgid "Change password"
-msgstr ""
+msgstr "更改密码"
#: worldmap/templates/people/profile_detail.html:137
msgid "Upload new layers"
-msgstr ""
+msgstr "上传新图层"
#: worldmap/templates/people/profile_detail.html:139
msgid "Create a new layer"
-msgstr ""
+msgstr "创建新图层"
#: worldmap/templates/people/profile_detail.html:141
msgid "Create a new map"
-msgstr ""
+msgstr "创建新地图"
#: worldmap/templates/people/profile_detail.html:142
msgid "My Activities"
-msgstr ""
+msgstr "我的活动"
#: worldmap/templates/people/profile_detail.html:146
msgid "Notifications"
-msgstr ""
+msgstr "通知"
#: worldmap/templates/people/profile_detail.html:149
msgid "Announcements"
-msgstr ""
+msgstr "公告"
#: worldmap/templates/people/profile_detail.html:154
msgid "Remote Services"
-msgstr ""
+msgstr "遥感服务"
#: worldmap/templates/people/profile_detail.html:155
msgid "GeoServer"
-msgstr ""
+msgstr "GeoServer"
+#: worldmap/templates/base.html:73
#: worldmap/templates/people/profile_detail.html:158
msgid "Admin"
-msgstr ""
+msgstr "管理员"
#: worldmap/templates/people/profile_detail.html:171
msgid "User Activities"
-msgstr ""
+msgstr "用户活动"
#: worldmap/templates/people/profile_detail.html:184
msgid "Resources"
-msgstr ""
+msgstr "资源"
#: worldmap/templates/people/profile_detail.html:200
msgid "Certified Resources"
-msgstr ""
+msgstr "认证资源"
#: worldmap/templates/site_index.html:56
msgid "My Layers"
-msgstr ""
+msgstr "我的图层"
#: worldmap/templates/site_index.html:57
#: worldmap/templates/upload/layer_upload.html:5
msgid "Upload Layer"
-msgstr ""
+msgstr "上传图层"
#: worldmap/templates/site_index.html:59
msgid "About"
-msgstr ""
+msgstr "关于"
#: worldmap/templates/site_index.html:68
msgid ""
"Build your own mapping portal and publish it to the world or to just a few "
"collaborators. WorldMap is open source software."
msgstr ""
+"搭建你自己的制图门户网站,发布给世界或者一些合作者。WorldMap是一个开源软件。"
#: worldmap/templates/site_index.html:70
msgid "WorldMap is being developed by the "
-msgstr ""
+msgstr "开发WorldMap的是"
#: worldmap/templates/site_index.html:70
-msgid "Center for Geographic Analysis"
-msgstr ""
+msgid "Center for Geographic Analysis at Zhejiang University"
+msgstr "哈佛大学地理分析中心"
+
+#: worldmap/templates/site_index.html:70
+msgid "Bigdata and Chinese AMAP Innovation Team of Zhejiang University"
+msgstr "浙江大学大数据与中国学术地图创新团队"
#: worldmap/templates/site_index.html:70
msgid "at"
-msgstr ""
+msgstr "在"
#: worldmap/templates/upload/layer_upload.html:39
msgid "Incomplete Uploads"
-msgstr ""
+msgstr "不完整的上传"
#: worldmap/templates/upload/layer_upload.html:40
msgid "You have the following incomplete uploads"
-msgstr ""
+msgstr "你有下列不完整的上传文件"
#: worldmap/templates/upload/layer_upload.html:43
msgid "last updated on"
-msgstr ""
+msgstr "上一次更新在"
#: worldmap/templates/upload/layer_upload.html:45
msgid "Resume"
-msgstr ""
+msgstr "重新开始"
#: worldmap/templates/upload/layer_upload.html:46
#: worldmap/templates/upload/layer_upload.html:53
msgid "Delete"
-msgstr ""
+msgstr "删除"
#: worldmap/templates/upload/layer_upload.html:52
msgid "Are you sure you want to delete this upload?"
-msgstr ""
+msgstr "你确定你想要删除这次上传?"
#: worldmap/templates/upload/layer_upload.html:54
msgid "Cancel"
-msgstr ""
+msgstr "取消"
#: worldmap/templates/upload/layer_upload.html:55
msgid "Delete, and don't ask me again."
-msgstr ""
+msgstr "删除,并不再提醒。"
#: worldmap/templates/upload/layer_upload.html:72
msgid "Drop files here"
-msgstr ""
+msgstr "把文件拖至此处"
#: worldmap/templates/upload/layer_upload.html:75
msgid " or select them one by one:"
-msgstr ""
+msgstr "或者逐一选中它们:"
+
+#: worldmap/templates/upload/layer_upload.html:80
+msgid "Choose Files"
+msgstr "选择文件"
#: worldmap/templates/upload/layer_upload.html:85
msgid "Files to be uploaded"
-msgstr ""
+msgstr "将被上传的文件"
#: worldmap/templates/upload/layer_upload.html:93
msgid "Select the charset or leave default"
-msgstr ""
+msgstr "选中字符集或者保持默认"
#: worldmap/templates/upload/layer_upload.html:111
msgid "Clear"
-msgstr ""
+msgstr "清空"
#: worldmap/templates/upload/layer_upload.html:112
msgid "Upload files"
-msgstr ""
+msgstr "上传文件"
#: worldmap/templates/worldmap_client/worldmap.html:53
msgid "Identify"
-msgstr ""
+msgstr "识别"
#: worldmap/templates/worldmap_client/worldmap.html:62
msgid "Map Coordinates - longitude, latitude"
-msgstr ""
+msgstr "地图坐标-经度,纬度"
#: worldmap/templates/worldmap_client/worldmap.html:69
msgid "Print"
-msgstr ""
+msgstr "打印"
#: worldmap/templates/worldmap_client/worldmap.html:81
msgid "Google Earth"
-msgstr ""
+msgstr "谷歌地球"
#: worldmap/templates/worldmap_client/worldmap.html:93
msgid "Measure"
-msgstr ""
+msgstr "测量"
#: worldmap/templates/worldmap_client/worldmap.html:100
msgid "Share Map"
-msgstr ""
+msgstr "分享地图"
#: worldmap/templates/worldmap_client/worldmap.html:107
msgid "Find Place"
-msgstr ""
+msgstr "找到地点"
#: worldmap/templates/worldmap_client/worldmap.html:134
msgid "Create Feature"
-msgstr ""
+msgstr "创建要素"
#: worldmap/templates/worldmap_client/worldmap.html:135
msgid "Edit Feature"
-msgstr ""
+msgstr "编辑要素"
#: worldmap/templates/worldmap_client/worldmap.html:220
msgid "Upload a Layer"
-msgstr ""
+msgstr "上传图层"
#: worldmap/templates/worldmap_client/worldmap.html:222
msgid "Click here to upload a layer."
-msgstr ""
+msgstr "点击这里上传图层"
#: worldmap/templates/worldmap_client/worldmap.html:223
#: worldmap/templates/worldmap_client/worldmap.html:235
msgid "Remember to save the map before."
-msgstr ""
+msgstr "记得先进行地图保存"
#: worldmap/templates/worldmap_client/worldmap.html:232
msgid "Create a new Layer"
-msgstr ""
+msgstr "创建新图层"
#: worldmap/templates/worldmap_client/worldmap.html:234
msgid "Click here to create a new layer."
-msgstr ""
+msgstr "点击这里创建新图层。"
#: worldmap/templates/worldmap_client/worldmap.html:247
msgid "Rectify Images"
-msgstr ""
+msgstr "校正影像"
#: worldmap/templates/worldmap_client/worldmap.html:248
msgid ""
"Use WorldMap "
"WARP to upload and rectify scanned maps for use in WorldMap."
msgstr ""
+"使用 WorldMap "
+"WARP 上传并校正扫描地图,以便于在WorldMap中使用。"
#: worldmap/templates/worldmap_client/worldmap.html:248
msgid ""
-"Maps rectified using this tool can be brought into WorldMap by following the "
-"instructions under Section 4.5 in WorldMap Help ."
+"Maps rectified using this tool can be brought into WorldMap by following the instructions under Section 4.7 in WorldMap Help ."
msgstr ""
+"使用该工具进行校正的地图可以导入WorldMap中,具体流程请查看 WorldMap帮助文档中的4.7章节 。"
#: worldmap/templates/worldmap_client/worldmap.html:261
#: worldmap/templates/worldmap_client/worldmap.html:277
msgid "Submit a Map Service URL"
-msgstr ""
+msgstr "提交地图服务地址"
#: worldmap/templates/worldmap_client/worldmap.html:264
#: worldmap/templates/worldmap_client/worldmap.html:280
msgid ""
"Submit a Map Service URL "
msgstr ""
+"提交地图服务地址 "
+
+#: worldmap/templates/site_index.html:hottest
+msgid "Hottest Maps"
+msgstr "最热地图"
+
+#: worldmap/templates/site_index.html:latest
+msgid "Latest Maps"
+msgstr "最新地图"
+
+#: worldmap/templates/site_index.html:categories
+msgid "All the categories"
+msgstr "所有学科"
+msgid "Geoscientific Information"
+msgstr "地学信息"
+msgid "Farming"
+msgstr "农学"
+#msgid "Elevation"
+#msgstr "高程"
+msgid "Utilities Communication"
+msgstr "公用通信"
+msgid "Oceans"
+msgstr "海洋"
+msgid "Boundaries"
+msgstr "边界"
+msgid "Inland Waters"
+msgstr "内陆水域"
+msgid "Intelligence Military"
+msgstr "军事情报"
+msgid "Environment"
+msgstr "环境"
+#msgid "Location"
+#msgstr "位置"
+msgid "Economy"
+msgstr "经济"
+msgid "Planning Cadastre"
+msgstr "规划地籍"
+msgid "Biota"
+msgstr "生物群"
+msgid "Health"
+msgstr "健康"
+msgid "Imagery Base Maps Earth Cover"
+msgstr "植被影像基础地图"
+msgid "Transportation"
+msgstr "交通"
+msgid "Society"
+msgstr "社会科学"
+msgid "Structure"
+msgstr "建筑物"
+msgid "Climatology Meteorology Atmosphere"
+msgstr "气候气象"
+msgid "Humanity History"
+msgstr "人文历史"
+
+#: worldmap/templates/base.html:155
+msgid "Don't have an account yet?"
+msgstr "未创建账户?"
+#: worldmap/templates/base.html:61
+msgid "Academic Map Publishing Platform"
+msgstr "学术地图发布平台"
+
+#: worldmap/templates/base.html:133
+msgid "Zhejiang University"
+msgstr "浙江大学"
+msgid "CGA Harvard"
+msgstr "哈佛大学CGA"
+msgid "Copyright Notice"
+msgstr "版权声明"
+msgid "All rights reserved"
+msgstr "版权所有"
+msgid "Choose Language"
+msgstr "语言选择"
+
+#: worldmap/templates/site_index.html:88
+msgid "About Us"
+msgstr "关于我们"
+msgid "About GeoNode"
+msgstr "关于GeoNode"
+
+#: worldmap/templates/aboutus.html:23
+msgid "Disclaimer"
+msgstr "免责声明"
+
+#: worldmap/templates/aboutus.html:23
+msgid "A large amount of geographical information which is closely related to human activities exists in the brilliant human civilization, numerous documents since ancient times, as well as the vast land and ocean. For example, the geographical distribution of individuals, the traces and the social relations for a single person, the migration of a group, as well as the existence, distribution and change of a region and trajectory for non-living things; as for a place, it also contains the people, events, things and other geographical information in previous time."
+msgstr "灿烂辉煌的人类文明、浩如烟海的古今文献以及广袤无垠的陆地海洋,存在着海量的与人类活动息息相关的地理信息。就单个人物来说,包括人物的籍贯、行迹、社会关系的地理分布;就群体来说,包括一个群体的地理分布和迁徙轨迹;就非生命的物体来说,也有其存在、分布和变化的地理区域;就一个地方来说,则又包含了既往时间里人、事、物等地理信息的总汇。"
+
+ #: worldmap/templates/aboutus.html:23
+msgid "The Academic Map Publishing Platform, established by Zhejiang University and Harvard University together, is not only an integrated database providing multi-functional query services, but also a display platform ready for users to present their research productions about geographic information and visualize analysis and select. The big data formed by the platform, will greatly contribute to future scientific research, government decision-making and social services."
+msgstr "由浙江大学与哈佛大学共建的学术地图发布平台愿为广大用户提供地理信息研究成果的发布、可视化分析及多功能查询服务,平台所形成的大数据,可以为未来科学研究、政府决策及社会服务提供重要的参考。 "
+
+#: worldmap/templates/aboutus.html:23
+msgid "The big data and Chinese academic map innovation team of Zhejiang University"
+msgstr "浙江大学大数据与中国学术地图创新团队"
+
+#: worldmap/templates/aboutus.html:23
+msgid "The Center for Geographic Analysis of Harvard University"
+msgstr "哈佛大学地理分析中心"
+
+#: worldmap/templates/aboutus.html:23
+msgid "Dec 18, 2017"
+msgstr "2017年12月18日"
+
+#: worldmap/templates/aboutus.html:23
+msgid "The copyright of the Academic Map Publishing Platform belongs to both the big data and Chinese academic map innovation team of Zhejiang University and the Center for Geographic Analysis of Harvard University. All copyrights of data and maps uploaded by users are held by their respective owners and the Platform."
+msgstr "“学术地图发布平台”的版权归“浙江大学大数据与中国学术地图创新团队”和“哈佛大学地理分析中心”共同所有。学者上传的地理信息数据与呈现的地图,版权归发布者和平台方共同所有。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "The data and information (including texts, pictures, audio and video files) must comply with national laws, regulations and academic norms. The legal liability caused by the content should be undertaken by the author, and this site has no joint liability."
+msgstr "发布者发布的数据和信息(包括文字、图片、影音文件),必须符合国家的法律法规和学术规范,若因发布的内容而引起的法律责任,由发布者自负。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "The authors have to back up files by themselves. This site does not assume responsibility for data loss due to hacker attacks, viruses or any other reasons. "
+msgstr "发布者发布的数据和信息,务必自己备份,本网站不承担因黑客攻击或病毒侵入造成的发布者数据损失的责任。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "This site and its employees are not required to take responsibility for any errors, inaccuracies or faults during information transmission or delivery in any way. "
+msgstr "本网站及其雇员一概毋须以任何方式就任何信息传递或传送的失误、不准确或错误对用户或任何其他人士负任何直接或间接的责任。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "If the information provided on this site that is used by any person or distributed to any person in any jurisdiction violates the laws or regulations of that jurisdiction, or makes this website or its third-party agents subject to any regulatory requirement in that jurisdiction, such information should not be used or distributed to any person in such jurisdiction. Users have to make sure that their materials will not be subject to any local restrictions that restrict or prohibit users from using or distributing such kind of information provided on this site."
+msgstr "本网站所提供的信息,若在任何司法管辖地区供任何人士使用或分发给任何人士时会违反该司法管辖地区的法律或条例的规定或会导致本网站或其第三方代理人受限于该司法管辖地区内的任何监管规定时,则该等信息不宜在该司法管辖地区供该等任何人士使用或分发给该等任何人士。用户须自行保证不会受限于任何限制或禁止用户使用或分发本网站所提供信息的当地的规定。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "Because this site is open to any registered user to upload pictures or text, and the site cannot identify the copyright of the uploaded pictures or text. Please inform us immediately once you find any possible infringement of yours, and we will delete it promptly."
+msgstr "本网站图片,文字之类版权申明,因为网站可以由注册用户自行上传图片或文字,本网站无法鉴别所上传图片或文字的知识版权,如果侵犯,请及时通知我们,本网站将在第一时间及时删除。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "We accept no liability for any loss or damage arising by force majeure that influences the normal operation of this website, such as hacker attacks, computer virus invasion or attack, the temporary closure caused by government regulation and so on. If other websites linked to this site cause the disclosure of personal information and relevant legal disputes or consequences, this site needn't undertake responsibility for this situation."
+msgstr "任何由于黑客攻击、计算机病毒侵入或发作、因政府管制而造成的暂时性关闭等影响网络正常经营的不可抗力而造成的损失,本网站均得免责(不可抗力因素不需要网站负责)。因和本网站链接的其它网站所造成的个人资料泄露及由此而导致的任何法律争议和后果,本网站均得免责。"
+
+#: worldmap/templates/aboutus.html:23
+msgid "We regard that those who get access to this site or use the data of this site in any way have accepted the constraints of this disclaimer voluntarily."
+msgstr "凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。"
+
+
+
diff --git a/worldmap/settings.py b/worldmap/settings.py
index 2d451d0..75cc438 100644
--- a/worldmap/settings.py
+++ b/worldmap/settings.py
@@ -79,7 +79,7 @@ def str2bool(v):
# This is needed for integration tests, they require
# geonode to be listening for GeoServer auth requests.
-os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = 'localhost:8000'
+os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = 'amap.zju.edu.cn:8000'
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split(',')
@@ -129,14 +129,14 @@ def str2bool(v):
MANAGERS = ADMINS = os.getenv('ADMINS', [])
USE_CUSTOM_ORG_AUTHORIZATION = True
-CUSTOM_ORG_AUTH_TEXT = 'Are you affiliated with Harvard University?'
+#CUSTOM_ORG_AUTH_TEXT = 'Are you affiliated with Harvard University?'
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
-TIME_ZONE = os.getenv('TIME_ZONE', "America/Chicago")
+TIME_ZONE = os.getenv('TIME_ZONE', "Asia/Shanghai")
SITE_ID = int(os.getenv('SITE_ID', '1'))
@@ -145,7 +145,7 @@ def str2bool(v):
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
-LANGUAGE_CODE = os.getenv('LANGUAGE_CODE', "en-us")
+LANGUAGE_CODE = os.getenv('LANGUAGE_CODE', "zh-cn")
# Underscore at the beginning added to represent a private variable.
# should not be used in the application.
_DEFAULT_LANGUAGES = (
@@ -212,9 +212,9 @@ def str2bool(v):
AUTH_USER_MODEL = os.getenv('AUTH_USER_MODEL', 'people.Profile')
-MODELTRANSLATION_LANGUAGES = ['en', ]
-MODELTRANSLATION_DEFAULT_LANGUAGE = 'en'
-MODELTRANSLATION_FALLBACK_LANGUAGES = ('en',)
+MODELTRANSLATION_LANGUAGES = ['zh-cn',]
+MODELTRANSLATION_DEFAULT_LANGUAGE = 'zh-cn'
+MODELTRANSLATION_FALLBACK_LANGUAGES = ('zh-cn',)
# Absolute path to the directory that holds media.
@@ -285,7 +285,6 @@ def str2bool(v):
WORLDMAP_APPS = (
# WorldMap applications
- 'worldmap',
'wm_extra',
'worldmap.certification',
)
@@ -575,16 +574,16 @@ def str2bool(v):
ACTSTREAM_SETTINGS = os.getenv('ACTSTREAM_SETTINGS',_DEFAULT_ACTSTREAM_SETTINGS)
# Email settings
-EMAIL_ENABLE = False
+EMAIL_ENABLE = True
if EMAIL_ENABLE:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
- EMAIL_HOST = 'localhost'
+ DEFAULT_FROM_EMAIL = 'camp2018@zju.edu.cn'
+ EMAIL_USE_TLS = True
+ EMAIL_HOST = 'smtp.zju.edu.cn'
+ EMAIL_HOST_USER = DEFAULT_FROM_EMAIL
+ EMAIL_HOST_PASSWORD = 'zjuworldmap120!'
EMAIL_PORT = 25
- EMAIL_HOST_USER = ''
- EMAIL_HOST_PASSWORD = ''
- EMAIL_USE_TLS = False
- DEFAULT_FROM_EMAIL = 'GeoNode '
# Settings for Social Apps
REGISTRATION_OPEN = str2bool(os.getenv('REGISTRATION_OPEN', 'False'))
@@ -628,13 +627,6 @@ def str2bool(v):
]
NOSE_ARGS = os.getenv('NOSE_ARGS',_DEFAULT_NOSE_ARGS)
-# this is for the gazetteer
-GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY',"gme-harvarduniversity1")
-# this is for the basemaps
-GOOGLE_MAPS_API_KEY = os.getenv('GOOGLE_MAPS_API_KEY', None)
-
-# GOOGLE_SECRET_KEY = None
-
GEONAMES_USER = ''
#
# GeoNode specific settings
@@ -700,7 +692,7 @@ def str2bool(v):
'BACKEND_WRITE_ENABLED': True,
'WPS_ENABLED': False,
'LOG_FILE': '%s/geoserver/data/logs/geoserver.log'
- % os.path.abspath(os.path.join(PROJECT_ROOT, os.pardir)),
+ % os.path.abspath(os.path.join(GEONODE_ROOT, os.pardir)),
# Set to name of database in DATABASES dictionary to enable
'DATASTORE': 'datastore',
'PG_GEOGIG': False,
@@ -733,7 +725,7 @@ def str2bool(v):
# 'ENGINE': 'geonode.catalogue.backends.generic',
# The FULLY QUALIFIED base url to the CSW instance for this GeoNode
- 'URL': '%scatalogue/csw' % SITEURL,
+ 'URL': '%s/catalogue/csw' % SITEURL,
# 'URL': 'http://localhost:8080/geonetwork/srv/en/csw',
# 'URL': 'http://localhost:8080/deegree-csw-demo-3.0.4/services',
@@ -801,9 +793,10 @@ def str2bool(v):
DEFAULT_MAP_CRS = os.getenv('DEFAULT_MAP_CRS',"EPSG:900913")
#GeoNode Client
-GEONODE_CLIENT_LOCATION = os.getenv('GEONODE_CLIENT_LOCATION',
- '/static/worldmap_client/')
-#GEONODE_CLIENT_LOCATION = "http://localhost:9090/"
+#GEONODE_CLIENT_LOCATION = os.getenv('GEONODE_CLIENT_LOCATION',
+# '/static/worldmap_client/')
+GEONODE_CLIENT_LOCATION = "http://amap.zju.edu.cn:9090/"
+
# Where should newly created maps be focused?
DEFAULT_MAP_CENTER = (0, 0)
@@ -927,38 +920,37 @@ def str2bool(v):
},
{
"source": {
- "ptype": "gxp_googlesource"
+ "ptype": "gxp_tianditusource"
},
"group": "background",
- "name": "SATELLITE",
- "visibility": False,
+ "name": "TIANDITUROAD",
+ "visibility": True,
"fixed": True,
},
{
"source": {
- "ptype": "gxp_googlesource",
+ "ptype": "gxp_tianditusource",
},
"group": "background",
- "name": "TERRAIN",
- "visibility": True,
+ "name": "TIANDITUIMAGE",
+ "visibility": False,
"fixed": True,
}, {
"source": {
- "ptype": "gxp_googlesource"
+ "ptype": "gxp_tianditusource"
},
"group": "background",
- "name": "HYBRID",
+ "name": "TIANDITUTERRAIN",
"visibility": False,
"fixed": True,
}, {
"source": {
- "ptype": "gxp_googlesource"
+ "ptype": "gxp_tianditusource"
},
"group": "background",
- "name": "ROADMAP",
- "visibility": False,
+ "name": "TIANDITUANNOTATION",
+ "visibility": True,
"fixed": True,
- "group": "background"
}
]
@@ -1064,7 +1056,7 @@ def str2bool(v):
]
DOWNLOAD_FORMATS_VECTOR = [
'JPEG', 'PDF', 'PNG', 'Zipped Shapefile', 'GML 2.0', 'GML 3.1.1', 'CSV',
- 'Excel', 'GeoJSON', 'KML', 'View in Google Earth', 'Tiles',
+ 'Excel', 'GeoJSON', 'KML', 'Tiles',
]
DOWNLOAD_FORMATS_RASTER = [
'JPEG',
@@ -1075,7 +1067,6 @@ def str2bool(v):
'Gtopo30',
'ImageMosaic',
'KML',
- 'View in Google Earth',
'Tiles',
'GML',
'GZIP'
diff --git a/worldmap/static/css/autocomplete.css b/worldmap/static/css/autocomplete.css
new file mode 100644
index 0000000..09ed6b9
--- /dev/null
+++ b/worldmap/static/css/autocomplete.css
@@ -0,0 +1,13 @@
+@CHARSET "UTF-8";
+.auto_hidden{
+ display:none
+}
+.auto_onmouseover{
+ background-color:#e7e2fc
+}
+.auto_onmouseout{
+ background-color:#d7cde4
+}
+.auto_show{
+ display:inline
+}
\ No newline at end of file
diff --git a/worldmap/static/css/blackstyle.css b/worldmap/static/css/blackstyle.css
new file mode 100644
index 0000000..3fc056c
--- /dev/null
+++ b/worldmap/static/css/blackstyle.css
@@ -0,0 +1,18 @@
+html, body{background-color: #000000}
+footer{
+ background-color: #000000;
+ text-align: center;
+ color: #EEEEEE;
+}
+.navbar{
+ background-color: rgba(0, 0, 0, 0.7);
+}
+.navbar-inverse .navbar-nav>li>a {
+ color: #EEEEEE;
+}
+.navbar-inverse .navbar-nav>li>ul>li>a {
+ color: #000000;
+}
+#usermenu{
+ background-color: rgba(255,255, 255, 0.7);
+}
\ No newline at end of file
diff --git a/worldmap/static/css/footer.css b/worldmap/static/css/footer.css
new file mode 100644
index 0000000..86ffece
--- /dev/null
+++ b/worldmap/static/css/footer.css
@@ -0,0 +1,9 @@
+.footerDiv{
+ width: 800px;
+ margin-top: 50px;
+ margin-bottom: 100px;
+}
+
+.footerContent{
+ text-align: left;
+}
diff --git a/worldmap/static/css/index.css b/worldmap/static/css/index.css
new file mode 100644
index 0000000..e1e5f7c
--- /dev/null
+++ b/worldmap/static/css/index.css
@@ -0,0 +1,130 @@
+body {
+ width: 100%;
+ height: 100%;
+ margin: 0px;
+ padding: 0
+}
+
+ul, ol {
+ padding: 0;
+}
+
+#headInterval {
+ height: 50px;
+ background-color: rgba(0, 0, 0, 0);
+}
+
+footer {
+ text-align: center;
+}
+
+#indexTop {
+ width: 100%;
+ padding-top: 2%;
+ padding-bottom: 2%;
+}
+
+#topleft {
+ width: 36%;
+ margin-right: 2%;
+ margin-left: 2%;
+ padding: 0px;
+ display: inline-block;
+}
+
+#topRight {
+ width: 54%;
+ margin-right: 2%;
+ margin-left: 2%;
+ border-radius: 20px;
+ /* background:#ffffff; */
+ display: inline-block;
+}
+
+.carousel-inner {
+ border-radius: 20px;
+}
+
+.topRightDiv {
+ width: 31%;
+ margin-left: 1%;
+ margin-right: 1%;
+ margin-top: 1%;
+ margin-bottom: 0.5%;
+ float: left;
+ position: relative;
+}
+
+.thematicMapList {
+ width: 100%;
+ padding-left: 2%;
+ padding-right: 4%;
+ padding-bottom: 2%;
+ font-size: 16px;
+}
+
+.thematicDiv {
+ width: 22%;
+ display: inline-block;
+ margin: 1%;
+ position: relative;
+}
+
+.subMapList {
+ width: 100%;
+ padding: 1%;
+ overflow: auto;
+ white-space: nowrap;
+}
+
+.MapListTitle {
+ font-size: 300%;
+}
+
+.subMapListTitle {
+ font-size: 200%;
+}
+
+.picItem {
+ width: 100%;
+ border-radius: 5px;
+}
+
+.imgTitle {
+ position: absolute;
+ text-align: center;
+ width: 100%;
+ z-index: 1;
+ bottom: 0px;
+ color: #ffffff;
+ opacity: 0.8;
+ font-size: 180%;
+ background: linear-gradient(to top, rgba(0, 0, 0, 1.0), rgba(0, 0, 0, 0));
+ border-radius: 5px;
+ margin: 0 0 0 0px;
+}
+
+/*
+ * Author: zbn
+ */
+body {
+ background: url(../img/body.png);
+ background-repeat: repeat;
+}
+
+.headBackgroud {
+ background: url(../img/background.jpg);
+ height: 200px;
+ width: 100%;
+ text-align: center;
+}
+
+.headTitle {
+ height: 100px;
+ width: 794px;
+ margin-top: 15px;
+}
+
+.topRightDiv .picItem {
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/worldmap/static/css/main.css b/worldmap/static/css/main.css
new file mode 100644
index 0000000..5366d28
--- /dev/null
+++ b/worldmap/static/css/main.css
@@ -0,0 +1,127 @@
+.maplayerTree {
+ background: rgba(220, 220, 220, 0.8);
+ max-height: 40%;
+ overflow: auto;
+}
+
+.headerCls {
+
+}
+
+.bodyCls {
+ background: rgba(255, 255, 255, 0.9);
+}
+
+#toolPanel {
+ position: absolute;
+ left: 50px;
+ top: 60px;
+ background: rgba(255, 255, 255, 0.5);
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ user-select: none;
+}
+
+#sharePanel {
+ position: absolute;
+ display: none;
+ padding: 5px;
+ opacity: 0.9;
+ background: #EEEEEE;
+ top: 90px;
+ left: 140px;
+ border-radius: 5px
+}
+
+#mapPanel {
+ position: absolute;
+ display: none;
+ padding: 5px;
+ opacity: 0.9;
+ background: #EEEEEE;
+ top: 90px;
+ left: 80px;
+ border-radius: 5px
+}
+
+#searchBox {
+ position: absolute;
+ display: none;
+ padding: 5px;
+ opacity: 0.9;
+ background: #EEEEEE;
+ top: 90px;
+ left: 230px;
+ border-radius: 5px
+}
+
+#mylegend {
+ position: absolute;
+ display: none;
+ padding: 5px;
+ background: rgba(220, 220, 220, 0.7);
+ bottom: 60px;
+ right: 10px;
+ border-radius: 5px;
+ cursor: move;
+ max-height: 80%;
+ overflow: auto;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ user-select: none;
+}
+
+#mytooltip {
+ position: absolute;
+ display: none;
+ padding: 5px;
+ background: rgba(220, 220, 220, 0.7);
+ top: 50%;
+ left: 50%;
+ border-radius: 5px;
+}
+
+#MarkBoard {
+ display: none;
+ height: 170px;
+}
+
+/* .changeMapWrapper {
+ position: absolute;
+ right: 5px;
+ top: 100px;
+}
+
+.hoverType {
+ width: 56px;
+ height: 58px;
+ background-color: rgba(255, 255, 255, 0.5);
+ float: left;
+ margin: 5px;
+ text-align: center;
+ cursor: pointer;
+} */
+
+#myMapMap {
+ background-color: rgba(181, 218, 255, 0.5);
+}
+
+#map {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+#resultPanel {
+ max-height:500px;
+ overflow:auto;
+}
+#QueryBoard {
+ max-height:500px;
+ overflow:auto;
+}
+#DeatailInfoPanel{
+ max-height:500px;
+ overflow:auto;
+}
\ No newline at end of file
diff --git a/worldmap/static/css/navbar.css b/worldmap/static/css/navbar.css
new file mode 100644
index 0000000..29166c4
--- /dev/null
+++ b/worldmap/static/css/navbar.css
@@ -0,0 +1,12 @@
+.navbar{
+ background-color: rgba(0, 0, 0, 0.7);
+}
+.navbar-inverse .navbar-nav>li>a {
+ color: #EEEEEE;
+}
+.navbar-inverse .navbar-nav>li>ul>li>a {
+ color: #EEEEEE;
+}
+#usermenu{
+ background-color: rgba(0,0, 0, 0.7);
+}
diff --git a/worldmap/static/css/privacy.css b/worldmap/static/css/privacy.css
new file mode 100644
index 0000000..ebbd3d1
--- /dev/null
+++ b/worldmap/static/css/privacy.css
@@ -0,0 +1,69 @@
+*{margin:0;padding:0}
+body{font:12px "","Arial Narrow",HELVETICA;background:#fff;-webkit-text-size-adjust:100%}
+.layout{width:1000px;margin:0 auto;border-bottom:1px solid #d1d1d1;padding-bottom:20px;}
+.layout h1{font-size:20px;line-height:80px;text-indent:62px;font-family:"ź";color:#0c0c0c;}
+.layout h2{font-size:18px;font-family:"ź";height:38px;line-height:38px;margin:38px 0 10px;border-left:3px solid #187ac7;background:#eaf1fa;text-indent:16px;color:#187ac7;}
+.layout h3{font-size:14px;line-height:18px;margin:20px 0 10px;color:#355a77;font-weight:bold;}
+.layout p{font-size:14px;line-height:32px;margin:20px 0 10px}
+.layout ul{margin:10px 10px 10px 30px}
+.layout li{padding-left:17px;font-size:14px;line-height:32px;background:url(http://mat1.gtimg.com/www/images/qq2012/privacyIcon.png) no-repeat left 12px;}
+.layout .inner{margin:10px 10px 10px 0;}
+.layout .inner li{background:url(http://mat1.gtimg.com/www/images/qq2012/privacyIcon.png) no-repeat left -482px;}
+.layout strong{color:#355a77;}
+.clear{clear:both;}
+.layout .ysNav{width:1000px;height:266px;background:#f8f8f8;}
+.layout .ysNav ul{width:500px;float:left;margin:13px 0 0;padding:0;}
+.layout .ysNav li{width:500px;font-size:14px;line-height:30px;float:left;margin:0;padding:0;color:#187ac7;text-indent:66px;background:none;}
+.layout .ysNav li a{color:#187ac7;}
+.layout .ysNav li a:hover{color:#105a94;}
+#tcopyright{color:#333!important;padding-top:15px;}
+#tcopyright a{color:#333!important;}
+
+.footer{display:none;padding:10px 45px 12px 0;overflow:hidden;position:relative;background: #404a54;}
+.footer .foot_user{display: none;}
+.footer .links{height:25px;line-height:25px;color:#565e61;font-size:13px;text-align:left}
+.footer .links a{color:#95a0ac;margin:0 0 0 8px;display:inline;float:left}
+.footer .links a:before{content:'';background:#565e61;width:1px;height:12px;display:inline-block;vertical-align:-1px;font-size:1em;color:#565e61;margin-right:8px}
+.footer .links a:first-child:before{display:none}
+.footer .copyright{font-size:13px;color:#707982;text-align:left;text-indent:8px;white-space:nowrap}
+
+@media screen and (max-width: 750px){
+ body{width: 100%; position: relative;font-family: Helvetica,STHeiti,Droid Sans Fallback!important; }
+ .layout, .logo{width: 100%;}
+ .logoLayout, .logo{height: 62px;}
+ .logo{background-size: 50%;}
+ .nav{display: none;}
+ .layout{position: relative;overflow: hidden;}
+ .layout h1{text-indent: 18px;}
+ .layout .ysNav{height: auto; width: 100%;}
+ .layout .ysNav ul, .layout .ysNav li{float: none;}
+ .layout .ysNav ul{margin: 0;}
+ .layout .ysNav li{width: auto; text-indent: 18px;}
+ .tcopyright{display: none;}
+ .layout h2, .layout h3, .layout h4, .layout p{padding: 0 10px;}
+ .footer{display: block;}
+}
+
+.tcopyright {width:960px;margin:0 auto;padding:8px 0;font-size:12px;line-height:28px;color:#333; text-align:center; overflow:hidden;clear:both;}
+.tcopyright .en{font-family:Arial;}
+.tcopyright a{color:#333;text-decoration: none;}
+.tcopyright a:hover{color:#bd0a01;text-decoration: underline;}
+
+a:visited {
+ color: #000;
+ text-decoration: none;
+}
+
+a:link {
+ outline: none;
+ color: #000;
+ text-decoration: none;
+}
+
+ul, ol {
+ list-style: none;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+}
\ No newline at end of file
diff --git a/worldmap/static/css/public.css b/worldmap/static/css/public.css
new file mode 100644
index 0000000..203fd78
--- /dev/null
+++ b/worldmap/static/css/public.css
@@ -0,0 +1,11 @@
+html,body {width:100%;height:100%;margin: 0px;padding:0}
+ul, ol { padding: 0;}
+
+#headInterval{
+ height: 50px;
+ background-color: rgba(0,0,0,0);
+}
+
+footer{
+ text-align:center;
+}
\ No newline at end of file
diff --git a/worldmap/static/css/publicstyle.css b/worldmap/static/css/publicstyle.css
new file mode 100644
index 0000000..203fd78
--- /dev/null
+++ b/worldmap/static/css/publicstyle.css
@@ -0,0 +1,11 @@
+html,body {width:100%;height:100%;margin: 0px;padding:0}
+ul, ol { padding: 0;}
+
+#headInterval{
+ height: 50px;
+ background-color: rgba(0,0,0,0);
+}
+
+footer{
+ text-align:center;
+}
\ No newline at end of file
diff --git a/worldmap/static/css/scroll.css b/worldmap/static/css/scroll.css
new file mode 100644
index 0000000..cbda5fd
--- /dev/null
+++ b/worldmap/static/css/scroll.css
@@ -0,0 +1,45 @@
+/*chromeʽ*/
+.custom-scrollbar::-webkit-scrollbar {
+ /*岿֣еwidth,height,background,borderͺһ鼶Ԫһȡ*/
+ width: 10px;
+ height: 10px;
+}
+.custom-scrollbar::-webkit-scrollbar-button {
+ /*˵İťdisplay:none䲻ʾҲӱͼƬɫıʾЧ*/
+ display: none;
+}
+.custom-scrollbar::-webkit-scrollbar-track {
+ /*display:none䲻ʾҲӱͼƬɫıʾЧ*/
+ display: none;
+}
+.custom-scrollbar::-webkit-scrollbar-track-piece {
+ /*ڲм䲿֣ȥ*/
+ background: #ccc;
+}
+.custom-scrollbar::-webkit-scrollbar-track-piece:increment {
+ /*ڲм䲿֣ȥ*/
+}
+.custom-scrollbar::-webkit-scrollbar-track-piece:decrement {
+ /*ڲм䲿֣ȥ*/
+}
+.custom-scrollbar::-webkit-scrollbar-track-piece:start {
+ /*ڲм䲿֣ȥ*/
+}
+.custom-scrollbar::-webkit-scrollbar-track-piece:end {
+ /*ڲм䲿֣ȥ*/
+}
+.custom-scrollbar::-webkit-scrollbar-thumb {
+ /*϶Dz*/
+ background: #dcedef;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+}
+.custom-scrollbar::-webkit-scrollbar-thumb:hover {
+ /*϶Dz*/
+}
+.custom-scrollbar::-webkit-scrollbar-corner {
+ /*߽*/
+}
+.custom-scrollbar::-webkit-scrollbar-resizer {
+ /*½϶ʽ*/
+}
\ No newline at end of file
diff --git a/worldmap/static/css/site_base.css b/worldmap/static/css/site_base.css
index 17243cc..21a223c 100644
--- a/worldmap/static/css/site_base.css
+++ b/worldmap/static/css/site_base.css
@@ -115,15 +115,17 @@
footer {
text-align: center;
- background-color: #2c689c;
+ background-color: #f5f5f5;
+ font-family: Helvetica, Microsoft YaHei, Tohoma, Arial;
}
footer a {
- color: #bfbfbf;
+ color: #2c689c;
+ font-size: 17px;
}
footer a:hover {
- color: #fff;
+ color: #000FE8;
}
#permissions-body .panel .radio{
diff --git a/worldmap/static/css/whitestyle.css b/worldmap/static/css/whitestyle.css
new file mode 100644
index 0000000..1a80163
--- /dev/null
+++ b/worldmap/static/css/whitestyle.css
@@ -0,0 +1,12 @@
+html, body{background-color: #FFFFFF}
+footer{
+ background-color: #FFFFFF;
+ text-align: center;
+ color: #000000;
+}
+.navbar{
+ background-color: rgba(1.0, 1.0, 1.0, 0.7);
+}
+#usermenu{
+ background-color: rgba(1.0, 1.0, 1.0, 0.7);
+}
diff --git a/worldmap/static/docs/WorldMap_Help_zh.pdf b/worldmap/static/docs/WorldMap_Help_zh.pdf
new file mode 100644
index 0000000..42d7e47
Binary files /dev/null and b/worldmap/static/docs/WorldMap_Help_zh.pdf differ
diff --git a/worldmap/static/img/01.jpg b/worldmap/static/img/01.jpg
new file mode 100644
index 0000000..adbb6df
Binary files /dev/null and b/worldmap/static/img/01.jpg differ
diff --git a/worldmap/static/img/05.jpg b/worldmap/static/img/05.jpg
new file mode 100644
index 0000000..4a3979e
Binary files /dev/null and b/worldmap/static/img/05.jpg differ
diff --git a/worldmap/static/img/1.jpg b/worldmap/static/img/1.jpg
new file mode 100644
index 0000000..ad3d2c6
Binary files /dev/null and b/worldmap/static/img/1.jpg differ
diff --git a/worldmap/static/img/11.jpg b/worldmap/static/img/11.jpg
new file mode 100644
index 0000000..2e18191
Binary files /dev/null and b/worldmap/static/img/11.jpg differ
diff --git a/worldmap/static/img/12.jpg b/worldmap/static/img/12.jpg
new file mode 100644
index 0000000..14ba66b
Binary files /dev/null and b/worldmap/static/img/12.jpg differ
diff --git a/worldmap/static/img/13.jpg b/worldmap/static/img/13.jpg
new file mode 100644
index 0000000..db7941f
Binary files /dev/null and b/worldmap/static/img/13.jpg differ
diff --git a/worldmap/static/img/14.jpg b/worldmap/static/img/14.jpg
new file mode 100644
index 0000000..da668ce
Binary files /dev/null and b/worldmap/static/img/14.jpg differ
diff --git a/worldmap/static/img/22.jpg b/worldmap/static/img/22.jpg
new file mode 100644
index 0000000..29d39bd
Binary files /dev/null and b/worldmap/static/img/22.jpg differ
diff --git a/worldmap/static/img/3_blue_blue.png b/worldmap/static/img/3_blue_blue.png
new file mode 100644
index 0000000..112a400
Binary files /dev/null and b/worldmap/static/img/3_blue_blue.png differ
diff --git a/worldmap/static/img/3_blue_gray.png b/worldmap/static/img/3_blue_gray.png
new file mode 100644
index 0000000..41bb435
Binary files /dev/null and b/worldmap/static/img/3_blue_gray.png differ
diff --git a/worldmap/static/img/3_gray_gray.png b/worldmap/static/img/3_gray_gray.png
new file mode 100644
index 0000000..0d523ee
Binary files /dev/null and b/worldmap/static/img/3_gray_gray.png differ
diff --git a/worldmap/static/img/3_ok.png b/worldmap/static/img/3_ok.png
new file mode 100644
index 0000000..5b0f6a6
Binary files /dev/null and b/worldmap/static/img/3_ok.png differ
diff --git a/worldmap/static/img/background.jpg b/worldmap/static/img/background.jpg
new file mode 100644
index 0000000..963346e
Binary files /dev/null and b/worldmap/static/img/background.jpg differ
diff --git a/worldmap/static/img/blue_gray.png b/worldmap/static/img/blue_gray.png
new file mode 100644
index 0000000..41bb435
Binary files /dev/null and b/worldmap/static/img/blue_gray.png differ
diff --git a/worldmap/static/img/body.png b/worldmap/static/img/body.png
new file mode 100644
index 0000000..c8126e8
Binary files /dev/null and b/worldmap/static/img/body.png differ
diff --git a/worldmap/static/img/body2.png b/worldmap/static/img/body2.png
new file mode 100644
index 0000000..7d92025
Binary files /dev/null and b/worldmap/static/img/body2.png differ
diff --git a/worldmap/static/img/body3.png b/worldmap/static/img/body3.png
new file mode 100644
index 0000000..cbcf0ae
Binary files /dev/null and b/worldmap/static/img/body3.png differ
diff --git a/worldmap/static/img/book.png b/worldmap/static/img/book.png
new file mode 100644
index 0000000..cf1dd2f
Binary files /dev/null and b/worldmap/static/img/book.png differ
diff --git a/worldmap/static/img/dufu.gif b/worldmap/static/img/dufu.gif
new file mode 100644
index 0000000..4b533b4
Binary files /dev/null and b/worldmap/static/img/dufu.gif differ
diff --git a/worldmap/static/img/gis.png b/worldmap/static/img/gis.png
new file mode 100644
index 0000000..3185352
Binary files /dev/null and b/worldmap/static/img/gis.png differ
diff --git a/worldmap/static/img/gray_gray.png b/worldmap/static/img/gray_gray.png
new file mode 100644
index 0000000..0d523ee
Binary files /dev/null and b/worldmap/static/img/gray_gray.png differ
diff --git a/worldmap/static/img/icon.ico b/worldmap/static/img/icon.ico
new file mode 100644
index 0000000..41467a9
Binary files /dev/null and b/worldmap/static/img/icon.ico differ
diff --git a/worldmap/static/img/icon1.png b/worldmap/static/img/icon1.png
new file mode 100644
index 0000000..57f8137
Binary files /dev/null and b/worldmap/static/img/icon1.png differ
diff --git a/worldmap/static/img/image.jpg b/worldmap/static/img/image.jpg
new file mode 100644
index 0000000..29162ab
Binary files /dev/null and b/worldmap/static/img/image.jpg differ
diff --git a/worldmap/static/img/layerIcon.jpg b/worldmap/static/img/layerIcon.jpg
new file mode 100644
index 0000000..8ae2ef8
Binary files /dev/null and b/worldmap/static/img/layerIcon.jpg differ
diff --git a/worldmap/static/img/libai.gif b/worldmap/static/img/libai.gif
new file mode 100644
index 0000000..04d8bf3
Binary files /dev/null and b/worldmap/static/img/libai.gif differ
diff --git a/worldmap/static/img/logo.jpg b/worldmap/static/img/logo.jpg
new file mode 100644
index 0000000..01fc224
Binary files /dev/null and b/worldmap/static/img/logo.jpg differ
diff --git a/worldmap/static/img/logo.png b/worldmap/static/img/logo.png
new file mode 100644
index 0000000..9f83878
Binary files /dev/null and b/worldmap/static/img/logo.png differ
diff --git a/worldmap/static/img/map/100.jpg b/worldmap/static/img/map/100.jpg
new file mode 100644
index 0000000..6c3c9a4
Binary files /dev/null and b/worldmap/static/img/map/100.jpg differ
diff --git a/worldmap/static/img/map/101.jpg b/worldmap/static/img/map/101.jpg
new file mode 100644
index 0000000..3f0b377
Binary files /dev/null and b/worldmap/static/img/map/101.jpg differ
diff --git a/worldmap/static/img/map/14.jpg b/worldmap/static/img/map/14.jpg
new file mode 100644
index 0000000..f3b965d
Binary files /dev/null and b/worldmap/static/img/map/14.jpg differ
diff --git a/worldmap/static/img/map/noData.jpg b/worldmap/static/img/map/noData.jpg
new file mode 100644
index 0000000..176531a
Binary files /dev/null and b/worldmap/static/img/map/noData.jpg differ
diff --git a/worldmap/static/img/map/noData1.jpg b/worldmap/static/img/map/noData1.jpg
new file mode 100644
index 0000000..f325678
Binary files /dev/null and b/worldmap/static/img/map/noData1.jpg differ
diff --git a/worldmap/static/img/map_image.jpg b/worldmap/static/img/map_image.jpg
new file mode 100644
index 0000000..6f8cb0d
Binary files /dev/null and b/worldmap/static/img/map_image.jpg differ
diff --git a/worldmap/static/img/map_logo.jpg b/worldmap/static/img/map_logo.jpg
new file mode 100644
index 0000000..282b37d
Binary files /dev/null and b/worldmap/static/img/map_logo.jpg differ
diff --git a/worldmap/static/img/map_map.jpg b/worldmap/static/img/map_map.jpg
new file mode 100644
index 0000000..63a68a0
Binary files /dev/null and b/worldmap/static/img/map_map.jpg differ
diff --git a/worldmap/static/img/mapicon.jpg b/worldmap/static/img/mapicon.jpg
new file mode 100644
index 0000000..14247dc
Binary files /dev/null and b/worldmap/static/img/mapicon.jpg differ
diff --git a/worldmap/static/img/qingdaifunv.gif b/worldmap/static/img/qingdaifunv.gif
new file mode 100644
index 0000000..60dd101
Binary files /dev/null and b/worldmap/static/img/qingdaifunv.gif differ
diff --git a/worldmap/static/img/quansongwen.gif b/worldmap/static/img/quansongwen.gif
new file mode 100644
index 0000000..86bbad7
Binary files /dev/null and b/worldmap/static/img/quansongwen.gif differ
diff --git a/worldmap/static/img/right.png b/worldmap/static/img/right.png
new file mode 100644
index 0000000..e8ec274
Binary files /dev/null and b/worldmap/static/img/right.png differ
diff --git a/worldmap/static/img/safe.png b/worldmap/static/img/safe.png
new file mode 100644
index 0000000..66c79d7
Binary files /dev/null and b/worldmap/static/img/safe.png differ
diff --git a/worldmap/static/img/slide-africa.jpg b/worldmap/static/img/slide-africa.jpg
index b29b7c1..f55d80b 100644
Binary files a/worldmap/static/img/slide-africa.jpg and b/worldmap/static/img/slide-africa.jpg differ
diff --git a/worldmap/static/img/slide-boston.jpg b/worldmap/static/img/slide-boston.jpg
index af97727..571765f 100644
Binary files a/worldmap/static/img/slide-boston.jpg and b/worldmap/static/img/slide-boston.jpg differ
diff --git a/worldmap/static/img/slide-china.jpg b/worldmap/static/img/slide-china.jpg
index 330a6d6..382e27c 100644
Binary files a/worldmap/static/img/slide-china.jpg and b/worldmap/static/img/slide-china.jpg differ
diff --git a/worldmap/static/img/slide-dufu.gif b/worldmap/static/img/slide-dufu.gif
new file mode 100644
index 0000000..2f343ea
Binary files /dev/null and b/worldmap/static/img/slide-dufu.gif differ
diff --git a/worldmap/static/img/slide-giza.jpg b/worldmap/static/img/slide-giza.jpg
index 0eb2010..9c5e9df 100644
Binary files a/worldmap/static/img/slide-giza.jpg and b/worldmap/static/img/slide-giza.jpg differ
diff --git a/worldmap/static/img/slide-japan.jpg b/worldmap/static/img/slide-japan.jpg
index 237328c..0b4f839 100644
Binary files a/worldmap/static/img/slide-japan.jpg and b/worldmap/static/img/slide-japan.jpg differ
diff --git a/worldmap/static/img/slide-libai.gif b/worldmap/static/img/slide-libai.gif
new file mode 100644
index 0000000..1d40249
Binary files /dev/null and b/worldmap/static/img/slide-libai.gif differ
diff --git a/worldmap/static/img/slide-qingdaifunv.gif b/worldmap/static/img/slide-qingdaifunv.gif
new file mode 100644
index 0000000..ba0c3b7
Binary files /dev/null and b/worldmap/static/img/slide-qingdaifunv.gif differ
diff --git a/worldmap/static/img/slide-quansongwen.gif b/worldmap/static/img/slide-quansongwen.gif
new file mode 100644
index 0000000..83c59ca
Binary files /dev/null and b/worldmap/static/img/slide-quansongwen.gif differ
diff --git a/worldmap/static/img/slide-tangxianzu.gif b/worldmap/static/img/slide-tangxianzu.gif
new file mode 100644
index 0000000..d08a3ce
Binary files /dev/null and b/worldmap/static/img/slide-tangxianzu.gif differ
diff --git a/worldmap/static/img/slide2/slide-dufu.jpg b/worldmap/static/img/slide2/slide-dufu.jpg
new file mode 100644
index 0000000..b91fcd9
Binary files /dev/null and b/worldmap/static/img/slide2/slide-dufu.jpg differ
diff --git a/worldmap/static/img/slide2/slide-libai.jpg b/worldmap/static/img/slide2/slide-libai.jpg
new file mode 100644
index 0000000..a1be792
Binary files /dev/null and b/worldmap/static/img/slide2/slide-libai.jpg differ
diff --git a/worldmap/static/img/slide2/slide-qingdaifunv.jpg b/worldmap/static/img/slide2/slide-qingdaifunv.jpg
new file mode 100644
index 0000000..bd0b629
Binary files /dev/null and b/worldmap/static/img/slide2/slide-qingdaifunv.jpg differ
diff --git a/worldmap/static/img/slide2/slide-quansongwen.jpg b/worldmap/static/img/slide2/slide-quansongwen.jpg
new file mode 100644
index 0000000..945dc2b
Binary files /dev/null and b/worldmap/static/img/slide2/slide-quansongwen.jpg differ
diff --git a/worldmap/static/img/slide2/slide-tangxianzu.jpg b/worldmap/static/img/slide2/slide-tangxianzu.jpg
new file mode 100644
index 0000000..38b0828
Binary files /dev/null and b/worldmap/static/img/slide2/slide-tangxianzu.jpg differ
diff --git a/worldmap/static/img/tangxianzu.gif b/worldmap/static/img/tangxianzu.gif
new file mode 100644
index 0000000..ce45e35
Binary files /dev/null and b/worldmap/static/img/tangxianzu.gif differ
diff --git a/worldmap/static/img/template_bubble_china.png b/worldmap/static/img/template_bubble_china.png
new file mode 100644
index 0000000..19cf755
Binary files /dev/null and b/worldmap/static/img/template_bubble_china.png differ
diff --git a/worldmap/static/img/template_point.jpg b/worldmap/static/img/template_point.jpg
new file mode 100644
index 0000000..71d0064
Binary files /dev/null and b/worldmap/static/img/template_point.jpg differ
diff --git a/worldmap/static/img/template_polyline.jpg b/worldmap/static/img/template_polyline.jpg
new file mode 100644
index 0000000..8f72470
Binary files /dev/null and b/worldmap/static/img/template_polyline.jpg differ
diff --git a/worldmap/static/img/template_range_china.png b/worldmap/static/img/template_range_china.png
new file mode 100644
index 0000000..d20ff65
Binary files /dev/null and b/worldmap/static/img/template_range_china.png differ
diff --git a/worldmap/static/img/title.png b/worldmap/static/img/title.png
new file mode 100644
index 0000000..291c096
Binary files /dev/null and b/worldmap/static/img/title.png differ
diff --git a/worldmap/static/img/title2.png b/worldmap/static/img/title2.png
new file mode 100644
index 0000000..2f74b2b
Binary files /dev/null and b/worldmap/static/img/title2.png differ
diff --git a/worldmap/static/img/title_small.png b/worldmap/static/img/title_small.png
new file mode 100644
index 0000000..61d47a1
Binary files /dev/null and b/worldmap/static/img/title_small.png differ
diff --git a/worldmap/static/img/title_small2.png b/worldmap/static/img/title_small2.png
new file mode 100644
index 0000000..0fd66e2
Binary files /dev/null and b/worldmap/static/img/title_small2.png differ
diff --git a/worldmap/static/img/title_small3.png b/worldmap/static/img/title_small3.png
new file mode 100644
index 0000000..e0a560b
Binary files /dev/null and b/worldmap/static/img/title_small3.png differ
diff --git a/worldmap/static/img/warning.png b/worldmap/static/img/warning.png
new file mode 100644
index 0000000..c5db7fc
Binary files /dev/null and b/worldmap/static/img/warning.png differ
diff --git a/worldmap/static/js/AdminPanel.js b/worldmap/static/js/AdminPanel.js
new file mode 100644
index 0000000..8303db2
--- /dev/null
+++ b/worldmap/static/js/AdminPanel.js
@@ -0,0 +1,251 @@
+$(function () {
+
+ //1.初始化Table
+ var oTable = new TableInit();
+ oTable.Init();
+
+ //2.初始化Button的点击事件
+ var oButtonInit = new ButtonInit();
+ oButtonInit.Init();
+});
+
+
+
+var TableInit = function () {
+ var oTableInit = new Object();
+ //初始化Table
+ oTableInit.Init = function () {
+ $('#tb_users').bootstrapTable({
+ url: './getUserList.action', //请求后台的URL(*)
+ method: 'get', //请求方式(*)
+ //toolbar: '#toolbar', //工具按钮用哪个容器
+ striped: true, //是否显示行间隔色
+ cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
+ pagination: true, //是否显示分页(*)
+ sortable: false, //是否启用排序
+ sortOrder: "asc", //排序方式
+ queryParams: oTableInit.userQueryParams,//传递参数(*)
+ sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
+ pageNumber:1, //初始化加载第一页,默认第一页
+ pageSize: 10, //每页的记录行数(*)
+ pageList: [10, 25, 50, 100], //可供选择的每页的行数(*)
+ search: false, //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
+ strictSearch: true,
+ showColumns: true, //是否显示所有的列
+ showRefresh: true, //是否显示刷新按钮
+ minimumCountColumns: 2, //最少允许的列数
+ clickToSelect: false, //是否启用点击选中行
+ height: 500, //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度
+ uniqueId: "ID", //每一行的唯一标识,一般为主键列
+ showToggle:true, //是否显示详细视图和列表视图的切换按钮
+ cardView: false, //是否显示详细视图
+ detailView: false, //是否显示父子表
+ columns: [{
+ checkbox: true
+ }, {
+ field: 'id',
+ title: 'ID'
+ }, {
+ field: 'username',
+ title: '用户名'
+ }, {
+ field: 'email',
+ title: '邮箱'
+ }, {
+ field: 'realname',
+ title: '姓名'
+ }, {
+ field: 'comp',
+ title: '单位'
+ }, {
+ field: 'cretificate',
+ title: '证件号码'
+ }, {
+ field: 'cretifitype',
+ title: '证件类型'
+ },
+ {
+ field: 'authority',
+ title: '权限'
+ }]
+ });
+
+ $('#tb_maps').bootstrapTable({
+ url: './getMapList2.action', //请求后台的URL(*)
+ method: 'get', //请求方式(*)
+ //toolbar: '#toolbar', //工具按钮用哪个容器
+ striped: true, //是否显示行间隔色
+ cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
+ pagination: true, //是否显示分页(*)
+ sortable: false, //是否启用排序
+ sortOrder: "asc", //排序方式
+ queryParams: oTableInit.mapQueryParams,//传递参数(*)
+ sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
+ pageNumber:1, //初始化加载第一页,默认第一页
+ pageSize: 10, //每页的记录行数(*)
+ pageList: [10, 25, 50, 100], //可供选择的每页的行数(*)
+ search: false, //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
+ strictSearch: true,
+ showColumns: true, //是否显示所有的列
+ showRefresh: true, //是否显示刷新按钮
+ minimumCountColumns: 2, //最少允许的列数
+ clickToSelect: false, //是否启用点击选中行
+ height: 500, //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度
+ uniqueId: "ID", //每一行的唯一标识,一般为主键列
+ showToggle:true, //是否显示详细视图和列表视图的切换按钮
+ cardView: false, //是否显示详细视图
+ detailView: false, //是否显示父子表
+ columns: [{
+ checkbox: true
+ }, {
+ field: 'id',
+ title: 'ID'
+ }, {
+ field: 'mapname',
+ title: '地图名'
+ }, {
+ field: 'userid',
+ title: '建立地图用户id'
+ }, {
+ field: 'accessibility',
+ title: '地图公开性'
+ }, {
+ field: 'addable',
+ title: '审核状态'
+ }],
+ onClickRow: function (item, $element) {
+ window.open("./main.action?mapid="+item.id);
+ return false;
+ }
+ });
+ };
+
+ //得到查询的参数
+ oTableInit.userQueryParams = function (params) {
+ var temp = {
+ limit: params.limit, //页面大小
+ offset: params.offset, //页码
+ username: $("#user_txt_username").val().trim()
+ };
+ return temp;
+ };
+
+ oTableInit.mapQueryParams = function (params) {
+ var temp = {
+ limit: params.limit, //页面大小
+ offset: params.offset, //页码
+ mapname: $("#map_txt_mapname").val().trim()
+ };
+ return temp;
+ };
+
+ return oTableInit;
+};
+
+var ButtonInit = function () {
+ var oInit = new Object();
+ var postdata = {};
+
+ oInit.Init = function () {
+ $('#user_btn_query').click(
+ function(){
+ $('#tb_users').bootstrapTable('refresh');
+ });
+ $('#map_btn_query').click(
+ function(){
+ $('#tb_maps').bootstrapTable('refresh');
+ });
+ $('#map_btn_pass').click(
+ function(){
+ var mapList = getSelectMapIdList();
+ $.ajax({
+ url: "./passMap.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ mapList: JSON.stringify(mapList)
+ },
+ success: function (result) {
+ $('#tb_maps').bootstrapTable('refresh');
+ }
+ })
+
+ });
+ $('#map_btn_ban').click(
+ function(){
+ var mapList = getSelectMapIdList();
+ $.ajax({
+ url: "./banMap.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ mapList: JSON.stringify(mapList)
+ },
+ success: function (result) {
+ $('#tb_maps').bootstrapTable('refresh');
+ }
+ })
+
+ });
+ $('#user_btn_pass').click(
+ function(){
+ var userList = getSelectUserIdList();
+ $.ajax({
+ url: "./passUser.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ userList: JSON.stringify(userList)
+ },
+ success: function (result) {
+ $('#tb_users').bootstrapTable('refresh');
+ }
+ })
+
+ });
+ $('#user_btn_ban').click(
+ function(){
+ var userList = getSelectUserIdList();
+ $.ajax({
+ url: "./banUser.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ userList: JSON.stringify(userList)
+ },
+ success: function (result) {
+ $('#tb_users').bootstrapTable('refresh');
+ }
+ })
+
+ });
+ };
+
+ return oInit;
+};
+
+function getSelectMapIdList()
+{
+ var selections = $('#tb_maps').bootstrapTable('getSelections');
+ var mapList = new Array();
+ for (var i=0;i20) length=20;
+ //光标键"↓"
+ if (event.keyCode == 40) {
+ ++this.index;
+ if (this.index > length) {
+ this.index = 0;
+ } else if (this.index == length) {
+ this.obj.value = this.search_value;
+ }
+ this.changeClassname(length);
+ }
+ //光标键"↑"
+ else if (event.keyCode == 38) {
+ this.index--;
+ if (this.index < -1) {
+ this.index = length - 1;
+ } else if (this.index == -1) {
+ this.obj.value = this.search_value;
+ }
+ this.changeClassname(length);
+ }
+ //回车键
+ else if (event.keyCode == 13) {
+ this.autoObj.children[this.index].onclick();
+ this.autoObj.className = "auto_hidden";
+
+ this.index = -1;
+ } else {
+ this.index = -1;
+ }
+ },
+ //程序入口
+ start: function (event) {
+ if (event.keyCode != 13 && event.keyCode != 38 && event.keyCode != 40) {
+ this.init();
+ this.deleteDIV();
+ this.select = null;
+ this.count = 0;
+ this.search_value = this.obj.value;
+ var valueArr = this.value_arr;
+ valueArr.sort(
+ function (a, b) {
+ if (a.name > b.name) return 1;
+ else if (a.name < b.name) return -1;
+ else return 0;
+ }
+ );
+ if (this.obj.value.replace(/(^\s*)|(\s*$)/g, '') == "") { return; }//值为空,退出
+ try { var reg1 = new RegExp("^" + this.obj.value, "i"); }
+ catch (e) { return; }
+ try { var reg2 = new RegExp("(" + this.obj.value + ")", "i"); }
+ catch (e) { return; }
+ var div_index = 0;//记录创建的DIV的索引
+ var tempArr = new Array();
+ var deleteIndex = new Array();
+ var terminateFlag = true;
+ //这段需要函数化重构
+ for (var i = 0; i < valueArr.length; i++) {
+ if (reg1.test(valueArr[i].name)) {
+ if (tempArr.has(valueArr[i], resultEqual)) {
+ deleteIndex.push(i);
+ continue;
+ }
+ tempArr.push(valueArr[i]);
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = valueArr[i].name;
+ var tempobj = valueArr[i];
+ div.onclick = this.setValue(this, tempobj);
+ div.onmouseover = this.autoOnmouseover(this, div_index);
+ div.innerHTML = valueArr[i].name.replace(reg2, "$1 ") + ' ' + valueArr[i].type + ' ';//搜索到的字符粗体显示
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ this.count++;
+ if (this.count > 19) { terminateFlag = false; break; }
+ }
+ }
+ for (var i = 0; i < deleteIndex.length; i++) {
+ valueArr.splice(i, 1);
+ }
+ for (var i = 0; i < valueArr.length; i++) {
+ if (terminateFlag && !reg2.test(valueArr[i].name) && reg2.test(valueArr[i].name)) {
+ tempArr.push(valueArr[i]);
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = valueArr[i].name;
+ div.onclick = this.setValue(this, i);
+ div.onmouseover = this.autoOnmouseover(this, div_index);
+ div.innerHTML = valueArr[i].name.replace(reg2, "$1 ") + ' ' + valueArr[i].type + ' ';//搜索到的字符粗体显示
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ this.count++;
+ if (this.count > 19) { terminateFlag = false; break; }
+ }
+ }
+ if(!terminateFlag){
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = "";
+ div.onclick = null;
+ div.onmouseover = null;
+ div.innerHTML = "仅显示前20条记录..."
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ }
+
+ }
+ this.pressKey(event);
+ }
+}
\ No newline at end of file
diff --git a/worldmap/static/js/AttrSearch2.js b/worldmap/static/js/AttrSearch2.js
new file mode 100644
index 0000000..5e31b7c
--- /dev/null
+++ b/worldmap/static/js/AttrSearch2.js
@@ -0,0 +1,412 @@
+function bgsearch() {
+ autoComplete.deleteDIV();
+ if(has(autoComplete.select))
+ match(autoComplete.select);
+ else
+ match({name:autoComplete.obj.value,type:'all'});
+}
+function match(info) {//查询所需要的信息匹配 并且返回结果选框
+ var infoType = info.type;
+ var infoKey = info.name;
+ var resultSet = new Array();
+ try { var reg = new RegExp("(" + infoKey + ")", "i"); }
+ catch (e) { return; }
+ //————————————————————switchBegin
+ switch (infoType) {
+ case "图层":
+ {
+ var index = info.index;
+ var type = myMapMana.maplayerlist[index].type;
+ switch (type) {
+ case 0:
+ var data = myMapMana.maplayerlist[index].style.dataSet._data;
+ for (var i = 0; i < data.length; i++) {
+ var temp = {
+ layername: infoKey,
+ name: data[i].name,
+ count: data[i].count,
+ type: '面',
+ index: { layer: index, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ break;
+ case 1:
+ var data = myMapMana.maplayerlist[index].style.series.data;
+ case 2:
+ if (type == 2) {
+ var data = myMapMana.maplayerlist[index].style.series.data;
+ }
+ for (var i = 0; i < data.length; i++) {
+ var temp = {
+ layername: infoKey,
+ name: data[i].name,
+ count: data[i].value[2],
+ type: '点',
+ index: { layer: index, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ break;
+ case 3:
+ var data = myMapMana.maplayerlist[index].style.data;
+ for (var i = 0; i < data.length; i++) {
+ var temp = {
+ layername: infoKey,
+ name: data.ID,
+ count: data.coords,
+ type: '面',
+ index: { layer: index, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ break;
+ }
+ break;
+ }
+ case "all":
+ case "地名":
+ {
+ for (var j = 0; j < myMapMana.maplayerlist.length; j++) {
+ var type = myMapMana.maplayerlist[j].type;
+ var layername = myMapMana.maplayerlist[j].layername;
+ switch (type) {
+ case 0:
+ var data = myMapMana.maplayerlist[j].style.dataSet._data;
+ for (var i = 0; i < data.length; i++) {
+ if (reg.test(data[i].name)) {
+ var temp = {
+ layername: layername,
+ name: data[i].name,
+ count: data[i].count,
+ type: '面',
+ index: { layer: j, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ }
+ break;
+ case 1:
+ var data = myMapMana.maplayerlist[j].style.series.data;
+ case 2:
+ if (type == 2) {
+ var data = myMapMana.maplayerlist[j].style.series.data;
+ }
+ for (var i = 0; i < data.length; i++) {
+ if (reg.test(data[i].name)) {
+ var temp = {
+ layername: layername,
+ name: data[i].name,
+ count: data[i].value[2],
+ type: '点',
+ index: { layer: j, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ }
+ break;
+ case 3:
+ var data = myMapMana.maplayerlist[j].style.data;
+ for (var i = 0; i < data.length; i++) {
+ if (reg.test(data[i].ID)) {
+ var temp = {
+ layername: layername,
+ name: data[i].ID,
+ count: data[i].coords,
+ type: '线',
+ index: { layer: j, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ }
+ break;
+ }
+ }
+ if(!infoType=="all") break;
+ }
+ case "数据":
+ {
+
+ for (var j = 0; j < myMapMana.maplayerlist.length; j++) {
+ var type = myMapMana.maplayerlist[j].type;
+ var layername = myMapMana.maplayerlist[j].layername;
+ switch (type) {
+ case 2:
+ var data = myMapMana.maplayerlist[j].style.series.data;
+ for (var i = 0; i < data.length; i++) {
+ if (reg.test(data[i].value[2])) {
+ var temp = {
+ layername: layername,
+ name: data[i].name,
+ count: data[i].value[2],
+ type: '点',
+ index: { layer: j, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ }
+ break;
+ case 3:
+ if(infoType=="all") break;
+ var data = myMapMana.maplayerlist[j].style.data;
+ for (var i = 0; i < data.length; i++) {
+ if (reg.test(data[i].ID)) {
+ var temp = {
+ layername: layername,
+ name: data[i].ID,
+ count: data[i].coords,
+ type: '线',
+ index: { layer: j, feature: i }//遇事不决存索引 这里还在纠结平移缩放怎么弄
+ }
+ resultSet.push(temp);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ //————————————————————switchEnd
+ showResultPanel(resultSet);
+}
+
+var autoComplete;
+function getLayerStringDataArr() {
+ var resultArr = new Array();
+ for (var i = 0; i < myMapMana.maplayerlist.length; i++) {//获取地图的所有文字信息
+ var layer = myMapMana.maplayerlist[i];
+ if (!layer.state) continue;
+ resultArr.push({ name: layer.layername, type: "图层", index: i });
+ switch (layer.type) {
+ case 0:
+ {
+ var data = layer.style.dataSet._data;
+ for (var j = 0; j < data.length; j++) {
+ resultArr.push({ name: data[j].name, type: "地名" });
+ }
+ break;
+ }
+ case 1:
+ {
+ var data = layer.style.series.data;
+ for (var j = 0; j < data.length; j++) {
+ resultArr.push({ name: data[j].name, type: "地名" });
+ }
+ break;
+ }
+ case 2:
+ {
+ var data = layer.style.series.data;
+ for (var j = 0; j < data.length; j++) {
+ resultArr.push({ name: data[j].name, type: "地名" });
+ resultArr.push({ name: data[j].value[2], type: "数据" });
+ }
+ break;
+ }
+ case 3:
+ {
+ var data = layer.style.data;
+ for (var j = 0; j < data.length; j++) {
+ resultArr.push({ name: data[j].ID, type: "路径名" });
+ }
+ break;
+ }
+ }
+ }
+ return resultArr;
+}
+Array.prototype.has = function (obj, equalFunc) {
+ var myEqual = function (a, b) { if (a == b) return true; else return false; }
+ if (has(equalFunc)) myEqual = equalFunc;
+ for (var i = 0; i < this.length; i++) {
+ if (myEqual(this[i], obj)) return true;
+ }
+ return false;
+}
+function resultEqual(a, b) {
+ if (a.name == b.name && a.type == b.type) return true;
+ else return false;
+}
+function createAutoComplete() {
+ var inputValue = getLayerStringDataArr();
+ if (!autoComplete) {
+ autoComplete = new AutoComplete('p_apiName', 'auto', inputValue);//第一个参数是输入框id,第二个是下拉显示的id,第三个是获取的全部数据。
+ }
+}
+function AutoComplete(obj, autoObj, arr) {
+ this.obj = document.getElementById(obj); //输入框
+ this.autoObj = document.getElementById(autoObj);//DIV的根节点
+ this.value_arr = arr; //不要包含重复值
+ this.index = -1; //当前选中的DIV的索引
+ this.search_value = ""; //保存当前搜索的字符
+ this.select = null;
+ this.count = 0;
+}
+AutoComplete.prototype = {
+ setArr: function (newArr) {
+ this.value_arr = newArr;
+ },
+ init: function () {
+ this.autoObj.style.left = this.obj.offsetLeft + "px";
+ this.autoObj.style.top = this.obj.offsetTop + this.obj.offsetHeight + "px";
+ this.autoObj.style.width = this.obj.offsetWidth - 2 + "px";//减去边框的长度2px
+ },
+ //删除自动完成需要的所有DIV
+ deleteDIV: function () {
+ while (this.autoObj.hasChildNodes()) {
+ this.autoObj.removeChild(this.autoObj.firstChild);
+ }
+ this.autoObj.className = "auto_hidden";
+ },
+ //设置值
+ setValue: function (_this, result) {
+ return function () {
+ _this.select = result;
+ _this.obj.value = this.seq;
+ _this.autoObj.className = "auto_hidden";
+ }
+ },
+ //模拟鼠标移动至DIV时,DIV高亮
+ autoOnmouseover: function (_this, _div_index) {
+ return function () {
+ _this.index = _div_index;
+ var length = _this.autoObj.children.length;
+ for (var j = 0; j < length; j++) {
+ if (j != _this.index) {
+ _this.autoObj.childNodes[j].className = 'auto_onmouseout';
+ } else {
+ _this.autoObj.childNodes[j].className = 'auto_onmouseover';
+ _this.obj.value=this.seq;
+ }
+ }
+ }
+ },
+ //更改classname
+ changeClassname: function (length) {
+ for (var i = 0; i < length; i++) {
+ if (i != this.index) {
+ this.autoObj.childNodes[i].className = 'auto_onmouseout';
+ } else {
+ this.autoObj.childNodes[i].className = 'auto_onmouseover';
+ this.obj.value = this.autoObj.childNodes[i].seq;
+ }
+ }
+ }
+ ,
+ //响应键盘
+ pressKey: function (event) {
+ var length = this.autoObj.children.length;
+ if(length>20) length=20;
+ //光标键"↓"
+ if (event.keyCode == 40) {
+ ++this.index;
+ if (this.index > length) {
+ this.index = 0;
+ } else if (this.index == length) {
+ this.obj.value = this.search_value;
+ }
+ this.changeClassname(length);
+ }
+ //光标键"↑"
+ else if (event.keyCode == 38) {
+ this.index--;
+ if (this.index < -1) {
+ this.index = length - 1;
+ } else if (this.index == -1) {
+ this.obj.value = this.search_value;
+ }
+ this.changeClassname(length);
+ }
+ //回车键
+ else if (event.keyCode == 13) {
+ this.autoObj.children[this.index].onclick();
+ this.autoObj.className = "auto_hidden";
+
+ this.index = -1;
+ } else {
+ this.index = -1;
+ }
+ },
+ //程序入口
+ start: function (event) {
+ if (event.keyCode != 13 && event.keyCode != 38 && event.keyCode != 40) {
+ this.init();
+ this.deleteDIV();
+ this.select = null;
+ this.count = 0;
+ this.search_value = this.obj.value;
+ var valueArr = this.value_arr;
+ valueArr.sort(
+ function (a, b) {
+ if (a.name > b.name) return 1;
+ else if (a.name < b.name) return -1;
+ else return 0;
+ }
+ );
+ if (this.obj.value.replace(/(^\s*)|(\s*$)/g, '') == "") { return; }//值为空,退出
+ try { var reg1 = new RegExp("^" + this.obj.value, "i"); }
+ catch (e) { return; }
+ try { var reg2 = new RegExp("(" + this.obj.value + ")", "i"); }
+ catch (e) { return; }
+ var div_index = 0;//记录创建的DIV的索引
+ var tempArr = new Array();
+ var deleteIndex = new Array();
+ var terminateFlag = true;
+ //这段需要函数化重构
+ for (var i = 0; i < valueArr.length; i++) {
+ if (reg1.test(valueArr[i].name)) {
+ if (tempArr.has(valueArr[i], resultEqual)) {
+ deleteIndex.push(i);
+ continue;
+ }
+ tempArr.push(valueArr[i]);
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = valueArr[i].name;
+ var tempobj = valueArr[i];
+ div.onclick = this.setValue(this, tempobj);
+ div.onmouseover = this.autoOnmouseover(this, div_index);
+ div.innerHTML = valueArr[i].name.replace(reg2, "$1 ") + ' ' + valueArr[i].type + ' ';//搜索到的字符粗体显示
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ this.count++;
+ if (this.count > 19) { terminateFlag = false; break; }
+ }
+ }
+ for (var i = 0; i < deleteIndex.length; i++) {
+ valueArr.splice(i, 1);
+ }
+ for (var i = 0; i < valueArr.length; i++) {
+ if (terminateFlag && !reg2.test(valueArr[i].name) && reg2.test(valueArr[i].name)) {
+ tempArr.push(valueArr[i]);
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = valueArr[i].name;
+ div.onclick = this.setValue(this, i);
+ div.onmouseover = this.autoOnmouseover(this, div_index);
+ div.innerHTML = valueArr[i].name.replace(reg2, "$1 ") + ' ' + valueArr[i].type + ' ';//搜索到的字符粗体显示
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ this.count++;
+ if (this.count > 19) { terminateFlag = false; break; }
+ }
+ }
+ if(!terminateFlag){
+ var div = document.createElement("div");
+ div.className = "auto_onmouseout";
+ div.seq = "";
+ div.onclick = null;
+ div.onmouseover = null;
+ div.innerHTML = "仅显示前20条记录..."
+ this.autoObj.appendChild(div);
+ this.autoObj.className = "auto_show";
+ div_index++;
+ }
+
+ }
+ this.pressKey(event);
+ }
+}
\ No newline at end of file
diff --git a/worldmap/static/js/DistanceTool.js b/worldmap/static/js/DistanceTool.js
new file mode 100644
index 0000000..8ce770c
--- /dev/null
+++ b/worldmap/static/js/DistanceTool.js
@@ -0,0 +1,1791 @@
+/**
+ * @fileoverview 百度地图的测距工具类,对外开放。
+ * 允许用户在地图上点击完成距离的测量。
+ * 使用者可以自定义测距线段的相关样式,例如线宽、颜色、测距结果所用的单位制等等。
+ * 主入口类是DistanceTool ,
+ * 基于Baidu Map API 1.2。
+ *
+ * @author Baidu Map Api Group
+ * @version 1.2
+ */
+
+/**
+ * @namespace BMap的所有library类均放在BMapLib命名空间下
+ */
+var BMapLib = window.BMapLib = BMapLib || {};
+
+(function() {
+ /**
+ * 声明baidu包
+ */
+ var baidu = baidu || {guid : "$BAIDU$"};
+ (function() {
+ // 一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
+ window[baidu.guid] = {};
+
+ /**
+ * 将源对象的所有属性拷贝到目标对象中
+ * @name baidu.extend
+ * @function
+ * @grammar baidu.extend(target, source)
+ * @param {Object} target 目标对象
+ * @param {Object} source 源对象
+ * @returns {Object} 目标对象
+ */
+ baidu.extend = function (target, source) {
+ for (var p in source) {
+ if (source.hasOwnProperty(p)) {
+ target[p] = source[p];
+ }
+ }
+ return target;
+ };
+
+ /**
+ * @ignore
+ * @namespace
+ * @baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
+ * @property guid 对象的唯一标识
+ */
+ baidu.lang = baidu.lang || {};
+
+ /**
+ * 返回一个当前页面的唯一标识字符串。
+ * @function
+ * @grammar baidu.lang.guid()
+ * @returns {String} 当前页面的唯一标识字符串
+ */
+ baidu.lang.guid = function() {
+ return "TANGRAM__" + (window[baidu.guid]._counter ++).toString(36);
+ };
+
+ window[baidu.guid]._counter = window[baidu.guid]._counter || 1;
+
+ /**
+ * 所有类的实例的容器
+ * key为每个实例的guid
+ */
+ window[baidu.guid]._instances = window[baidu.guid]._instances || {};
+
+ /**
+ * Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
+ * @function
+ * @name baidu.lang.Class
+ * @grammar baidu.lang.Class(guid)
+ * @param {string} guid 对象的唯一标识
+ * @meta standard
+ * @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。
+ * guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。
+ * baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
+ */
+ baidu.lang.Class = function(guid) {
+ this.guid = guid || baidu.lang.guid();
+ window[baidu.guid]._instances[this.guid] = this;
+ };
+
+ window[baidu.guid]._instances = window[baidu.guid]._instances || {};
+
+ /**
+ * 判断目标参数是否string类型或String对象
+ * @name baidu.lang.isString
+ * @function
+ * @grammar baidu.lang.isString(source)
+ * @param {Any} source 目标参数
+ * @shortcut isString
+ * @meta standard
+ *
+ * @returns {boolean} 类型判断结果
+ */
+ baidu.lang.isString = function (source) {
+ return '[object String]' == Object.prototype.toString.call(source);
+ };
+
+ /**
+ * 判断目标参数是否为function或Function实例
+ * @name baidu.lang.isFunction
+ * @function
+ * @grammar baidu.lang.isFunction(source)
+ * @param {Any} source 目标参数
+ * @returns {boolean} 类型判断结果
+ */
+ baidu.lang.isFunction = function (source) {
+ return '[object Function]' == Object.prototype.toString.call(source);
+ };
+
+ /**
+ * 重载了默认的toString方法,使得返回信息更加准确一些。
+ * @return {string} 对象的String表示形式
+ */
+ baidu.lang.Class.prototype.toString = function(){
+ return "[object " + (this._className || "Object" ) + "]";
+ };
+
+ /**
+ * 释放对象所持有的资源,主要是自定义事件。
+ * @name dispose
+ * @grammar obj.dispose()
+ */
+ baidu.lang.Class.prototype.dispose = function(){
+ delete window[baidu.guid]._instances[this.guid];
+ for(var property in this){
+ if (!baidu.lang.isFunction(this[property])) {
+ delete this[property];
+ }
+ }
+ this.disposed = true;
+ };
+
+ /**
+ * 自定义的事件对象。
+ * @function
+ * @name baidu.lang.Event
+ * @grammar baidu.lang.Event(type[, target])
+ * @param {string} type 事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
+ * @param {Object} [target]触发事件的对象
+ * @meta standard
+ * @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
+ * @see baidu.lang.Class
+ */
+ baidu.lang.Event = function (type, target) {
+ this.type = type;
+ this.returnValue = true;
+ this.target = target || null;
+ this.currentTarget = null;
+ };
+
+ /**
+ * 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
+ * @grammar obj.addEventListener(type, handler[, key])
+ * @param {string} type 自定义事件的名称
+ * @param {Function} handler 自定义事件被触发时应该调用的回调函数
+ * @param {string} [key] 为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
+ * @remark 事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。
+ */
+ baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
+ if (!baidu.lang.isFunction(handler)) {
+ return;
+ }
+ !this.__listeners && (this.__listeners = {});
+ var t = this.__listeners, id;
+ if (typeof key == "string" && key) {
+ if (/[^\w\-]/.test(key)) {
+ throw("nonstandard key:" + key);
+ } else {
+ handler.hashCode = key;
+ id = key;
+ }
+ }
+ type.indexOf("on") != 0 && (type = "on" + type);
+ typeof t[type] != "object" && (t[type] = {});
+ id = id || baidu.lang.guid();
+ handler.hashCode = id;
+ t[type][id] = handler;
+ };
+
+ /**
+ * 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
+ * @grammar obj.removeEventListener(type, handler)
+ * @param {string} type 事件类型
+ * @param {Function|string} handler 要移除的事件监听函数或者监听函数的key
+ * @remark 如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
+ */
+ baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
+ if (baidu.lang.isFunction(handler)) {
+ handler = handler.hashCode;
+ } else if (!baidu.lang.isString(handler)) {
+ return;
+ }
+ !this.__listeners && (this.__listeners = {});
+ type.indexOf("on") != 0 && (type = "on" + type);
+ var t = this.__listeners;
+ if (!t[type]) {
+ return;
+ }
+ t[type][handler] && delete t[type][handler];
+ };
+
+ /**
+ * 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
+ * @grammar obj.dispatchEvent(event, options)
+ * @param {baidu.lang.Event|String} event Event对象,或事件名称(1.1.1起支持)
+ * @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
+ * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。
+ * 例如:
+ * myobj.onMyEvent = function(){}
+ * myobj.addEventListener("onMyEvent", function(){});
+ */
+ baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
+ if (baidu.lang.isString(event)) {
+ event = new baidu.lang.Event(event);
+ }
+ !this.__listeners && (this.__listeners = {});
+ options = options || {};
+ for (var i in options) {
+ event[i] = options[i];
+ }
+ var i, t = this.__listeners, p = event.type;
+ event.target = event.target || this;
+ event.currentTarget = this;
+ p.indexOf("on") != 0 && (p = "on" + p);
+ baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
+ if (typeof t[p] == "object") {
+ for (i in t[p]) {
+ t[p][i].apply(this, arguments);
+ }
+ }
+ return event.returnValue;
+ };
+
+ /**
+ * 为类型构造器建立继承关系
+ * @name baidu.lang.inherits
+ * @function
+ * @grammar baidu.lang.inherits(subClass, superClass[, className])
+ * @param {Function} subClass 子类构造器
+ * @param {Function} superClass 父类构造器
+ * @param {string} className 类名标识
+ * @remark 使subClass继承superClass的prototype,
+ * 因此subClass的实例能够使用superClass的prototype中定义的所有属性和方法。
+ * 这个函数实际上是建立了subClass和superClass的原型链集成,并对subClass进行了constructor修正。
+ * 注意:如果要继承构造函数,需要在subClass里面call一下,具体见下面的demo例子
+ * @shortcut inherits
+ * @meta standard
+ * @see baidu.lang.Class
+ */
+ baidu.lang.inherits = function (subClass, superClass, className) {
+ var key, proto,
+ selfProps = subClass.prototype,
+ clazz = new Function();
+ clazz.prototype = superClass.prototype;
+ proto = subClass.prototype = new clazz();
+ for (key in selfProps) {
+ proto[key] = selfProps[key];
+ }
+ subClass.prototype.constructor = subClass;
+ subClass.superClass = superClass.prototype;
+
+ if ("string" == typeof className) {
+ proto._className = className;
+ }
+ };
+
+ /**
+ * @ignore
+ * @namespace baidu.dom 操作dom的方法。
+ */
+ baidu.dom = baidu.dom || {};
+
+ /**
+ * 从文档中获取指定的DOM元素
+ *
+ * @param {string|HTMLElement} id 元素的id或DOM元素
+ * @meta standard
+ * @return {HTMLElement} DOM元素,如果不存在,返回null,如果参数不合法,直接返回参数
+ */
+ baidu._g = baidu.dom._g = function (id) {
+ if (baidu.lang.isString(id)) {
+ return document.getElementById(id);
+ }
+ return id;
+ };
+
+ /**
+ * 从文档中获取指定的DOM元素
+ * @name baidu.dom.g
+ * @function
+ * @grammar baidu.dom.g(id)
+ * @param {string|HTMLElement} id 元素的id或DOM元素
+ * @meta standard
+ *
+ * @returns {HTMLElement|null} 获取的元素,查找不到时返回null,如果参数不合法,直接返回参数
+ */
+ baidu.g = baidu.dom.g = function (id) {
+ if ('string' == typeof id || id instanceof String) {
+ return document.getElementById(id);
+ } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
+ return id;
+ }
+ return null;
+ };
+
+ /**
+ * 在目标元素的指定位置插入HTML代码
+ * @name baidu.dom.insertHTML
+ * @function
+ * @grammar baidu.dom.insertHTML(element, position, html)
+ * @param {HTMLElement|string} element 目标元素或目标元素的id
+ * @param {string} position 插入html的位置信息,取值为beforeBegin,afterBegin,beforeEnd,afterEnd
+ * @param {string} html 要插入的html
+ * @remark
+ *
+ * 对于position参数,大小写不敏感
+ * 参数的意思:beforeBegin<span>afterBegin this is span! beforeEnd</span> afterEnd
+ * 此外,如果使用本函数插入带有script标签的HTML字符串,script标签对应的脚本将不会被执行。
+ *
+ * @shortcut insertHTML
+ * @meta standard
+ *
+ * @returns {HTMLElement} 目标元素
+ */
+ baidu.insertHTML = baidu.dom.insertHTML = function (element, position, html) {
+ element = baidu.dom.g(element);
+ var range,begin;
+
+ if (element.insertAdjacentHTML) {
+ element.insertAdjacentHTML(position, html);
+ } else {
+ // 这里不做"undefined" != typeof(HTMLElement) && !window.opera判断,其它浏览器将出错?!
+ // 但是其实做了判断,其它浏览器下等于这个函数就不能执行了
+ range = element.ownerDocument.createRange();
+ // FF下range的位置设置错误可能导致创建出来的fragment在插入dom树之后html结构乱掉
+ // 改用range.insertNode来插入html, by wenyuxiang @ 2010-12-14.
+ position = position.toUpperCase();
+ if (position == 'AFTERBEGIN' || position == 'BEFOREEND') {
+ range.selectNodeContents(element);
+ range.collapse(position == 'AFTERBEGIN');
+ } else {
+ begin = position == 'BEFOREBEGIN';
+ range[begin ? 'setStartBefore' : 'setEndAfter'](element);
+ range.collapse(begin);
+ }
+ range.insertNode(range.createContextualFragment(html));
+ }
+ return element;
+ };
+
+ /**
+ * 为目标元素添加className
+ * @name baidu.dom.addClass
+ * @function
+ * @grammar baidu.dom.addClass(element, className)
+ * @param {HTMLElement|string} element 目标元素或目标元素的id
+ * @param {string} className 要添加的className,允许同时添加多个class,中间使用空白符分隔
+ * @remark
+ * 使用者应保证提供的className合法性,不应包含不合法字符,className合法字符参考:http://www.w3.org/TR/CSS2/syndata.html。
+ * @shortcut addClass
+ * @meta standard
+ *
+ * @returns {HTMLElement} 目标元素
+ */
+ baidu.ac = baidu.dom.addClass = function (element, className) {
+ element = baidu.dom.g(element);
+ var classArray = className.split(/\s+/),
+ result = element.className,
+ classMatch = " " + result + " ",
+ i = 0,
+ l = classArray.length;
+
+ for (; i < l; i++){
+ if ( classMatch.indexOf( " " + classArray[i] + " " ) < 0 ) {
+ result += (result ? ' ' : '') + classArray[i];
+ }
+ }
+
+ element.className = result;
+ return element;
+ };
+
+ /**
+ * @ignore
+ * @namespace baidu.event 屏蔽浏览器差异性的事件封装。
+ * @property target 事件的触发元素
+ * @property pageX 鼠标事件的鼠标x坐标
+ * @property pageY 鼠标事件的鼠标y坐标
+ * @property keyCode 键盘事件的键值
+ */
+ baidu.event = baidu.event || {};
+
+ /**
+ * 事件监听器的存储表
+ * @private
+ * @meta standard
+ */
+ baidu.event._listeners = baidu.event._listeners || [];
+
+ /**
+ * 为目标元素添加事件监听器
+ * @name baidu.event.on
+ * @function
+ * @grammar baidu.event.on(element, type, listener)
+ * @param {HTMLElement|string|window} element 目标元素或目标元素id
+ * @param {string} type 事件类型
+ * @param {Function} listener 需要添加的监听器
+ * @remark
+ * 1. 不支持跨浏览器的鼠标滚轮事件监听器添加
+ * 2. 改方法不为监听器灌入事件对象,以防止跨iframe事件挂载的事件对象获取失败
+ * @shortcut on
+ * @meta standard
+ * @see baidu.event.un
+ *
+ * @returns {HTMLElement|window} 目标元素
+ */
+ baidu.on = baidu.event.on = function (element, type, listener) {
+ type = type.replace(/^on/i, '');
+ element = baidu._g(element);
+ var realListener = function (ev) {
+ // 1. 这里不支持EventArgument, 原因是跨frame的事件挂载
+ // 2. element是为了修正this
+ listener.call(element, ev);
+ },
+ lis = baidu.event._listeners,
+ filter = baidu.event._eventFilter,
+ afterFilter,
+ realType = type;
+ type = type.toLowerCase();
+ // filter过滤
+ if(filter && filter[type]){
+ afterFilter = filter[type](element, type, realListener);
+ realType = afterFilter.type;
+ realListener = afterFilter.listener;
+ }
+ // 事件监听器挂载
+ if (element.addEventListener) {
+ element.addEventListener(realType, realListener, false);
+ } else if (element.attachEvent) {
+ element.attachEvent('on' + realType, realListener);
+ }
+
+ // 将监听器存储到数组中
+ lis[lis.length] = [element, type, listener, realListener, realType];
+ return element;
+ };
+
+ /**
+ * 为目标元素移除事件监听器
+ * @name baidu.event.un
+ * @function
+ * @grammar baidu.event.un(element, type, listener)
+ * @param {HTMLElement|string|window} element 目标元素或目标元素id
+ * @param {string} type 事件类型
+ * @param {Function} listener 需要移除的监听器
+ * @shortcut un
+ * @meta standard
+ *
+ * @returns {HTMLElement|window} 目标元素
+ */
+ baidu.un = baidu.event.un = function (element, type, listener) {
+ element = baidu._g(element);
+ type = type.replace(/^on/i, '').toLowerCase();
+
+ var lis = baidu.event._listeners,
+ len = lis.length,
+ isRemoveAll = !listener,
+ item,
+ realType, realListener;
+
+ //如果将listener的结构改成json
+ //可以节省掉这个循环,优化性能
+ //但是由于un的使用频率并不高,同时在listener不多的时候
+ //遍历数组的性能消耗不会对代码产生影响
+ //暂不考虑此优化
+ while (len--) {
+ item = lis[len];
+
+ // listener存在时,移除element的所有以listener监听的type类型事件
+ // listener不存在时,移除element的所有type类型事件
+ if (item[1] === type
+ && item[0] === element
+ && (isRemoveAll || item[2] === listener)) {
+ realType = item[4];
+ realListener = item[3];
+ if (element.removeEventListener) {
+ element.removeEventListener(realType, realListener, false);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + realType, realListener);
+ }
+ lis.splice(len, 1);
+ }
+ }
+ return element;
+ };
+
+ /**
+ * 阻止事件的默认行为
+ * @name baidu.event.preventDefault
+ * @function
+ * @grammar baidu.event.preventDefault(event)
+ * @param {Event} event 事件对象
+ * @meta standard
+ */
+ baidu.preventDefault = baidu.event.preventDefault = function (event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ };
+ })();
+
+ /**
+ * @exports DistanceTool as BMapLib.DistanceTool
+ */
+ var DistanceTool =
+ /**
+ * DistanceTool类的构造函数
+ * @class 距离测算类,实现测距效果的入口 。
+ * 实例化该类后,即可调用该类提供的open
+ * 方法开启测距状态。
+ *
+ * @constructor
+ * @param {Map} map Baidu map的实例对象
+ * @param {Json Object} opts 可选的输入参数,非必填项。可输入选项包括:
+ * {"followText " : {String} 测距过程中,提示框文字,
+ * "unit " : {String} 测距结果所用的单位制,可接受的属性为"metric"表示米制和"us"表示美国传统单位,
+ * "lineColor " : {String} 折线颜色,
+ * "lineStroke " : {Number} 折线宽度,
+ * "opacity " : {Number} 透明度,
+ * "lineStyle " : {String} 折线的样式,只可设置solid和dashed,
+ * "secIcon " : {BMap.Icon} 转折点的Icon,
+ * "closeIcon " : {BMap.Icon} 关闭按钮的Icon,
+ * "cursor " : {String} 跟随的鼠标样式}
+ *
+ * @example 参考示例:
+ * var map = new BMap.Map("container"); map.centerAndZoom(new BMap.Point(116.404, 39.915), 15); var myDistanceToolObject = new BMapLib.DistanceTool(map, {lineStroke : 2});
+ */
+ BMapLib.DistanceTool = function(map, opts){
+ if (!map) {
+ return;
+ }
+
+ /**
+ * map对象
+ * @private
+ * @type {Map}
+ */
+ this._map = map;
+
+ opts = opts || {};
+ /**
+ * _opts是默认参数赋值。
+ * 下面通过用户输入的opts,对默认参数赋值
+ * @private
+ * @type {Json}
+ */
+ this._opts = baidu.extend(
+ baidu.extend(this._opts || {}, {
+
+ /**
+ * 测距提示
+ * @private
+ * @type {String}
+ */
+ tips : "测距",
+
+ /**
+ * 测距过程中,提示框文字
+ * @private
+ * @type {String}
+ */
+ followText : "单击确定地点,双击结束",
+
+ /**
+ * 测距结果所用的单位制,可接受的属性为"metric"表示米制和"us"表示美国传统单位
+ * @private
+ * @type {String}
+ */
+ unit : "metric",
+
+ /**
+ * 折线颜色
+ * @private
+ * @type {String}
+ */
+ lineColor : "#ff6319",
+
+ /**
+ * 折线线宽
+ * @private
+ * @type {Number}
+ */
+ lineStroke : 2,
+
+ /**
+ * 折线透明度
+ * @private
+ * @type {Number}
+ */
+ opacity : 0.8,
+
+ /**
+ * 折线样式
+ * @private
+ * @type {String}
+ */
+ lineStyle : "solid",
+
+ /**
+ * 跟随鼠标样式
+ * @private
+ * @type {String}
+ */
+ cursor : "http://api.map.baidu.com/images/ruler.cur",
+
+ /**
+ * 转折点的ICON样式
+ * @private
+ * @type {BMap.Icon}
+ */
+ secIcon : null,
+
+ /**
+ * 转折点的ICON样式
+ * @private
+ * @type {BMap.Icon}
+ */
+ closeIcon : null
+ })
+ , opts);
+
+ /**
+ * 跟随的title覆盖物
+ * @private
+ * @type {BMap.Label}
+ */
+ this._followTitle = null;
+
+ /**
+ * 折线包含所有点的数组
+ * @private
+ * @type {Array}
+ */
+ this._points = [];
+
+ /**
+ * 折线所包含的所有path数组
+ * @private
+ * @type {Array}
+ */
+ this._paths = [];
+
+ /**
+ * 折线结点图片数组
+ * @private
+ * @type {Array}
+ */
+ this._dots = [];
+
+ /**
+ * 折线测距包含所有线段的距离
+ * @private
+ * @type {Array}
+ */
+ this._segDistance = [];
+
+ /**
+ * 覆盖物的数组
+ * @private
+ * @type {Array}
+ */
+ this._overlays = [];
+
+ /**
+ * 是否在调用map.clearOverlays清除画线需要建立的相关overlay元素
+ * @private
+ * @type {Boolean}
+ */
+ this._enableMassClear = true,
+
+ /**
+ * 单位制,存储语言包中定义的单位名称
+ * @private
+ * @type {Json}
+ */
+ this._units = {
+ // metric 表示米制
+ metric : {
+ /**
+ * 米制的名称
+ * @type {String}
+ */
+ name : "metric",
+
+ /**
+ * 和米制的换算关系
+ * @type {Number}
+ */
+ conv : 1,
+
+ /**
+ * 米制单位下两个单位制之间的换算关系
+ * @type {Number}
+ */
+ incon : 1000,
+
+ /**
+ * 米制单位下较小单位
+ * @type {String}
+ */
+ u1 : "米",
+
+ /**
+ * 米制单位下较大单位
+ * @type {String}
+ */
+ u2 : "公里"
+ },
+ // us 表示美国传统单位,各参数意义同上metric
+ us : {
+ name : "us",
+ conv : 3.2808,
+ incon : 5279.856,
+ u1 : "英尺",
+ u2 : "英里"
+ }
+ };
+
+ /**
+ * 是否已经开启了测距状态
+ * @private
+ * @type {Boolean}
+ */
+ this._isOpen = false;
+
+ /**
+ * 未点击任何一点时,鼠标移动时的跟随提示文字
+ * @private
+ * @type {String}
+ */
+ this._startFollowText = "单击确定起点";
+
+ /**
+ * 地图移动的计时器
+ * @private
+ * @type {Object}
+ */
+ this._movingTimerId = null;
+
+ /**
+ * 测距需要添加的CSS样式
+ * @private
+ * @type {Json}
+ */
+ this._styles = {
+ "BMapLib_diso" : "height:17px;width:5px;position:absolute;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat left top"
+ ,"BMapLib_disi" : "color:#7a7a7a;position:absolute;left:5px;padding:0 4px 1px 0;line-height:17px;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat right top"
+ ,"BMapLib_disBoxDis" : "color:#ff6319;font-weight:bold;"
+ };
+
+ if (this._opts.lineStroke <= 0) {
+ this._opts.lineStroke = 2;
+ }
+ if (this._opts.opacity > 1) {
+ this._opts.opacity = 1;
+ } else if (this._opts.opacity < 0) {
+ this._opts.opacity = 0;
+ }
+ if (this._opts.lineStyle != "solid" &&
+ this._opts.lineStyle != "dashed") {
+ this._opts.lineStyle = "solid";
+ }
+ if (!this._units[this._opts.unit]) {
+ this._opts.unit = "metric";
+ }
+
+ this.text = "测距";
+ }
+
+ // 通过baidu.lang下的inherits方法,让DistanceTool继承baidu.lang.Class
+ baidu.lang.inherits(DistanceTool, baidu.lang.Class, "DistanceTool");
+
+ /**
+ * 地图区域的移动事件绑定
+ * @return 无返回值
+ */
+ DistanceTool.prototype._bind = function(){
+ // 设置鼠标样式
+ this._setCursor(this._opts.cursor);
+ var me = this;
+ // 在装载地图的页面元素上,绑定鼠标移动事件
+ baidu.on(this._map.getContainer(), "mousemove", function(e){
+ if (!me._isOpen) {
+ return;
+ }
+ if (!me._followTitle) {
+ return;
+ }
+ e = window.event || e;
+ var t = e.target || e.srcElement;
+ // 如果触发该事件的页面元素不是遮盖效果层,则返回,无操作
+ if (t != OperationMask.getDom(me._map)) {
+ me._followTitle.hide();
+ return;
+ }
+ if (!me._mapMoving) {
+ me._followTitle.show();
+ }
+ // 设置鼠标移动过程中,跟随的文字提示框的位置
+ var pt = OperationMask.getDrawPoint(e, true);
+ me._followTitle.setPosition(pt);
+ });
+ // 创建鼠标跟随的文字提示框
+ if (this._startFollowText) {
+ var t = this._followTitle = new BMap.Label(this._startFollowText, {offset : new BMap.Size(14, 16)});
+ this._followTitle.setStyles({color : "#333", borderColor : "#ff0103"});
+ }
+ };
+
+ /**
+ * 开启地图的测距状态
+ * @return {Boolean},开启测距状态成功,返回true;否则返回false。
+ *
+ * @example 参考示例:
+ * myDistanceToolObject.open();
+ */
+ DistanceTool.prototype.open = function(){
+ // 判断测距状态是否已经开启
+ if (this._isOpen == true){
+ return true;
+ }
+ // 已有其他地图上的鼠标操作工具开启
+ if (!!BMapLib._toolInUse) {
+ return;
+ }
+ this._isOpen = true;
+ BMapLib._toolInUse = true;
+
+ // 判断是否是否在移动过程中
+ if (this._mapMoving){
+ delete this._mapMoving;
+ }
+
+ var me = this;
+ // 增加鼠标在地图区域移动的事件
+ // 通过binded参数,避免多次绑定
+ if (!this._binded) {
+ this._binded = true;
+ // 绑定控件项事件
+ this._bind();
+ // 地图的移动过程中,需要隐藏相关的提示框
+ this._map.addEventListener("moving", function(){
+ me._hideCurrent();
+ });
+ }
+
+ // 将文字提示框作为BMap.Label元素,提交给Map Api进行管理
+ if (this._followTitle) {
+ this._map.addOverlay(this._followTitle);
+ this._followTitle.hide();
+ }
+
+ /**
+ * 测距过程中,点击地图时,触发的操作
+ * @ignore
+ * @param {Object} e event对象
+ */
+ var distClick = function(e) {
+ var map = me._map;
+ if (!me._isOpen) {
+ return;
+ }
+ // 通过event对象,计算得出点击位置的物理坐标,poi为一个BMap.Point对象
+ e = window.event || e;
+ var poi = OperationMask.getDrawPoint(e, true);
+ // 验证计算得出的该点的位置合理性
+ if (!me._isPointValid(poi)) {
+ return;
+ }
+ // 记录当前点的屏幕位置
+ me._bind.initX = e.pageX || e.clientX || 0;
+ me._bind.initY = e.pageY || e.clientY || 0;
+
+ // 这个if循环内的计算是,判断当前这个点,与存储内的最后一个点的距离,
+ // 如果距离过小,比如小于5,可以认为是用户的误点,可以忽略掉
+ if (me._points.length > 0){
+ var lstPx = map.pointToPixel(me._points[me._points.length - 1]);
+ var thisPx = map.pointToPixel(poi);
+ var dis = Math.sqrt(Math.pow(lstPx.x - thisPx.x, 2) + Math.pow(lstPx.y - thisPx.y, 2));
+ if (dis < 5) {
+ return;
+ }
+ }
+
+ me._bind.x = e.layerX || e.offsetX || 0;
+ me._bind.y = e.layerY || e.offsetY || 0;
+ me._points.push(poi);
+ // 添加测距结点
+ me._addSecPoint(poi);
+
+ // 调整跟踪鼠标的标签
+ if (me._paths.length == 0) {
+ me._formatTitle(1, me._opts.followText, me._getTotalDistance());
+ }
+
+ // 修改确定线的颜色
+ if (me._paths.length > 0) {
+ me._paths[me._paths.length - 1].show();
+ me._paths[me._paths.length - 1].setStrokeOpacity(me._opts.opacity);
+ }
+
+ var path = new BMap.Polyline([poi, poi], {enableMassClear : me._enableMassClear});
+ me._map.addOverlay(path);
+ me._paths.push(path);
+ me._overlays.push(path);
+
+ // 测距模式下线样式固定
+ path.setStrokeWeight(me._opts.lineStroke);
+ path.setStrokeColor(me._opts.lineColor);
+ path.setStrokeOpacity(me._opts.opacity / 2);
+ path.setStrokeStyle(me._opts.lineStyle);
+
+ // 如果地图正在移动则隐藏掉
+ if (me._mapMoving){
+ path.hide();
+ }
+
+ if (me._points.length > 1) {
+ var siblingPath = me._paths[me._points.length - 2];
+ siblingPath.setPositionAt(1, poi);
+ }
+
+ // 生成节点旁边的距离显示框
+ var disText = "";
+ if (me._points.length > 1) {
+ // 非起点的节点,显示当前的距离
+ var segDis = me._setSegDistance(me._points[me._points.length - 2], me._points[me._points.length - 1]);
+ var meters = me._getTotalDistance();
+ disText = me._formatDisStr(meters);
+ } else {
+ disText = "起点";
+ }
+ var disLabel = new BMap.Label(disText, {offset : new BMap.Size(10, -5), enableMassClear : me._enableMassClear});
+ disLabel.setStyles({color : "#333", borderColor : "#ff0103"});
+ me._map.addOverlay(disLabel);
+ me._formatSegLabel(disLabel, disText);
+ me._overlays.push(disLabel);
+ poi.disLabel = disLabel;
+ disLabel.setPosition(poi);
+
+ /**
+ * 测距过程中,每次点击底图添加节点时,派发事件的接口
+ * @name DistanceTool#onaddpoint
+ * @event
+ * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
+ * {"point : {BMap.Point} 最新添加上的节点BMap.Point对象,
+ * "pixel :{BMap.pixel} 最新添加上的节点BMap.Pixel对象,
+ * "index :{Number} 最新添加的节点的索引,
+ * "distance :{Number} 截止最新添加的节点的总距离}
+ *
+ * @example 参考示例:
+ * myDistanceToolObject.addEventListener("addpoint", function(e) { alert(e.distance); });
+ */
+
+ // 生成名为onaddpoint的baidu.lang.Event对象
+ // 并给该event对象添加上point、pixel、index和distance等属性字段
+ // 然后在此刻,将绑定在onaddpoint上事件,全部赋予event参数,然后派发出去
+ var event = new baidu.lang.Event("onaddpoint");
+ event.point = poi;
+ event.pixel = me._map.pointToPixel(poi);
+ event.index = me._points.length - 1;
+ event.distance = me._getTotalDistance().toFixed(0);
+ me.dispatchEvent(event);
+ };
+
+ /**
+ * 测距过程中,鼠标在地图上移动时,触发的操作
+ * @ignore
+ * @param {Object} e event对象
+ */
+ var distMove = function(e) {
+ if (!me._isOpen){
+ return;
+ }
+ // 通过判断数组me._paths的长度,判断当前是否已经有测量节点
+ // 也就是,如果没有节点,则还没有开始测量
+ if (me._paths.length > 0) {
+ // 通过event参数,计算当前点的位置
+ e = window.event || e;
+ var curX = e.pageX || e.clientX || 0;
+ var curY = e.pageY || e.clientY || 0;
+ if (typeof me._bind.initX == "undefined") {
+ me._bind.x = e.layerX || e.offsetX || 0;
+ me._bind.y = e.layerY || e.offsetY || 0;
+ me._bind.initX = curX;
+ me._bind.initY = curY;
+ }
+ var x = me._bind.x + curX - me._bind.initX;
+ var y = me._bind.y + curY - me._bind.initY;
+
+ // 修改最后一条折线的终点位置,使之随着鼠标移动画线
+ var path = me._paths[me._paths.length - 1];
+ var poi = me._map.pixelToPoint(new BMap.Pixel(x, y));
+ path.setPositionAt(1, poi);
+
+ if (!me._mapMoving) {
+ path.show();
+ }
+ var dx = 0;
+ var dy = 0;
+ // 计算当前鼠标位置,是否靠近边界、或者已经出了边界
+ // 如果在边界位置,则需要向对应的方向移动地图,来进行测量
+ // 每次移动的距离,设定为8
+ if (x < 10) {
+ dx = 8;
+ } else if (x > me._map.getSize().width - 10){
+ dx = -8;
+ }
+ if (y < 10) {
+ dy = 8;
+ } else if (y > me._map.getSize().height - 10){
+ dy = -8;
+ }
+ // 如果dx和dy都等于0,表明不需要移动地图
+ if (dx != 0 || dy != 0){
+ // 此时需要向一个方向,平移地图
+ if (!distMove._movingTimerId){
+ me._mapMoving = true;
+ me._map.panBy(dx, dy, {noAnimation : true});
+ me._movingTimerId = distMove._movingTimerId = setInterval(function(){
+ me._map.panBy(dx, dy, {noAnimation : true});
+ }, 30);
+ // 地图移动过程中,隐藏线段和标签
+ path.hide();
+ me._followTitle && me._followTitle.hide();
+ }
+ } else {
+ if (distMove._movingTimerId) {
+ // 此时用户不在需要移动地图来测量,可以清除计时器
+ clearInterval(distMove._movingTimerId);
+ delete distMove._movingTimerId;
+ delete me._movingTimerId;
+
+ // 显示跟随提示框,并修改线路位置
+ var lstP = me._paths[me._paths.length - 1];
+ var poiN = me._map.pixelToPoint(new BMap.Pixel(x, y));
+ if (!lstP) {
+ return;
+ }
+ lstP.setPositionAt(1, poiN);
+ lstP.show();
+ if (me._followTitle) {
+ me._followTitle.setPosition(poiN);
+ me._followTitle.show();
+ }
+ me._bind.i = 0;
+ me._bind.j = 0;
+ delete me._mapMoving;
+ }
+ }
+ // 实时更新文字提示框中的距离
+ if (me._followTitle) {
+ var td = me._getTotalDistance();
+ var dis = me._map.getDistance(me._points[me._points.length - 1], poi);
+ me._updateInstDis(me._followTitle, td + dis);
+ }
+ } else {
+ // 此时用户还没有开始测量,只是鼠标随便在地图上移动
+ if (me._followTitle) {
+ me._followTitle.show();
+ e = window.event || e;
+ var t = e.target || e.srcElement;
+ if (t != OperationMask.getDom()) {
+ me._followTitle.hide();
+ }
+ }
+ }
+ };
+
+ /**
+ * 测距要结束时,双击地图,触发的操作
+ * @ignore
+ * @param {Object} e event对象
+ */
+ var distDblclick = function(e) {
+ if (!me._isOpen) {
+ return;
+ }
+ // 结束时,删除绑定的事件
+ baidu.un(OperationMask.getDom(me._map), "click", distClick);
+ baidu.un(document, "mousemove", distMove);
+ baidu.un(OperationMask.getDom(me._map), "dblclick", distDblclick);
+ baidu.un(document, "keydown", distKeyDown);
+ baidu.un(OperationMask.getDom(me._map), "mouseup", distMouseUp);
+
+ // 调用close()关闭测距状态
+ setTimeout(function(){
+ me.close();
+ }, 50);
+ };
+
+ /**
+ * 测距时的键盘操作
+ * @ignore
+ * @param {Object} e event对象
+ */
+ var distKeyDown = function(e){
+ e = window.event || e;
+ if (e.keyCode == 27){
+ // [ESC]退出本次测距
+ me._clearCurData();
+ setTimeout(function(){
+ me.close();
+ }, 50);
+ }
+ };
+
+ /**
+ * 测距过程中,鼠标弹起时,触发的操作
+ * @ignore
+ * @param {Object} e event对象
+ */
+ var distMouseUp = function(e) {
+ e = window.event || e;
+ var ieVersion = 0;
+ if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
+ ieVersion = document.documentMode || + RegExp['\x241'];
+ }
+ if (ieVersion &&
+ e.button != 1 ||
+ e.button == 2){
+ me.close();
+ }
+ };
+
+ // 初始化存储数据
+ me._initData();
+
+ // 调整title的内容
+ this._formatTitle();
+
+ // 创建透明覆盖层,并设置鼠标样式
+ OperationMask.show(this._map);
+ this._setCursor(this._opts.cursor);
+
+ // 绑定全部事件
+ baidu.on(OperationMask.getDom(this._map), "click", distClick);
+ baidu.on(document, "mousemove", distMove);
+ baidu.on(OperationMask.getDom(this._map), "dblclick", distDblclick);
+ baidu.on(document, "keydown", distKeyDown);
+ baidu.on(OperationMask.getDom(this._map), "mouseup", distMouseUp);
+
+ // 将绑定的事件、和对应的绑定对象,记录在数组中
+ this.bindFunc = [
+ {elem : OperationMask.getDom(this._map), type : "click", func : distClick},
+ {elem : OperationMask.getDom(this._map), type : "dblclick", func : distDblclick},
+ {elem : document, type : "mousemove", func : distMove},
+ {elem : document, type : "keydown", func : distKeyDown},
+ {elem : OperationMask.getDom(this._map), type : "mouseup", func : distMouseUp}];
+ return true;
+ };
+
+ /**
+ * 画线结束时,派发drawend事件
+ * @return 无返回值
+ */
+ DistanceTool.prototype._dispatchLastEvent = function() {
+ /**
+ * 测距时,每次双击底图结束当前测距折线时,派发事件的接口
+ * @name DistanceTool#ondrawend
+ * @event
+ * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
+ * {"points : {BMap.Point} 所有测量时,打下的节点BMap.Point对象,
+ * "overlays :{Array} 所有测量时,生成的线段BMap.Overlay对象,
+ * "distance :{Number} 测量解释时的最终距离}
+ *
+ * @example 参考示例:
+ * myDistanceToolObject.addEventListener("drawend", function(e) { alert(e.distance); });
+ */
+
+ // 生成名为ondrawend的baidu.lang.Event对象
+ // 并给该event对象添加上points、overlays和distance等属性字段
+ // 然后在此刻,将绑定在ondrawend上事件,全部赋予event参数,然后派发出去
+ var event = new baidu.lang.Event("ondrawend");
+ event.points =
+ this._points ?
+ this._points.slice(0) :
+ [];
+ event.overlays =
+ this._paths ?
+ this._paths.slice(0, this._paths.length - 1) :
+ [];
+ event.distance = this._getTotalDistance().toFixed(0);
+ this.dispatchEvent(event);
+ };
+
+ /**
+ * 关闭测距状态
+ * @return 无返回值
+ *
+ * @example 参考示例:
+ * myDistanceToolObject.close();
+ */
+ DistanceTool.prototype.close = function(){
+ if (this._isOpen == false){
+ return;
+ }
+ this._isOpen = false;
+ BMapLib._toolInUse = false;
+
+ if (this._mapMoving){
+ delete this._mapMoving;
+ }
+ var me = this;
+ me._dispatchLastEvent();
+ if (me._points.length < 2){
+ // 不是有效绘制,清除所有内容
+ me._clearCurData();
+ } else {
+ me._paths[me._paths.length - 1].remove();
+ me._paths[me._paths.length - 1] = null;
+ me._paths.length = me._paths.length - 1;
+ // 移除最近一次标记
+ var pt = me._points[me._points.length - 1];
+ if (pt.disLabel){
+ pt.disLabel.remove();
+ }
+ me._processLastOp();
+ }
+ OperationMask.hide();
+
+ // 删除绑定的事件
+ for (var i = 0, l = this.bindFunc.length; i < l; i ++){
+ baidu.un(this.bindFunc[i].elem, this.bindFunc[i].type, this.bindFunc[i].func);
+ }
+
+ // 停止地图移动
+ if (me._movingTimerId){
+ clearInterval(me._movingTimerId);
+ me._movingTimerId = null;
+ }
+
+ if (this._followTitle){
+ this._followTitle.hide();
+ }
+ };
+
+ /**
+ * 清除本次测距的暂存数据
+ * @return 无返回值
+ */
+ DistanceTool.prototype._clearCurData = function(){
+ for (var i = 0, l = this._points.length; i < l; i ++){
+ if (this._points[i].disLabel){
+ this._points[i].disLabel.remove();
+ }
+ }
+ for (var i = 0, l = this._paths.length; i < l; i ++){
+ this._paths[i].remove();
+ }
+ for (var i = 0, l = this._dots.length; i < l; i ++){
+ this._dots[i].remove();
+ }
+ this._initData();
+ };
+
+ /**
+ * 初始化存储数组
+ * @return 无返回值
+ */
+ DistanceTool.prototype._initData = function(){
+ // 初始化point数组
+ this._points.length = 0;
+ // 初始化path数组
+ this._paths.length = 0;
+ // 初始化分段距离数组
+ this._segDistance.length = 0;
+ // 初始化结点图像数组
+ this._dots.length = 0;
+ };
+
+ /**
+ * 计算两点之间距离并存放在分段距离数组中
+ * @param {Point}
+ * @param {Point}
+ * @return {Number} 两个地理点之间的距离
+ */
+ DistanceTool.prototype._setSegDistance = function(pt0, pt1){
+ if (!pt0 || !pt1){
+ return;
+ }
+ var dis = this._map.getDistance(pt0, pt1);
+ this._segDistance.push(dis);
+ return dis;
+ };
+
+ /**
+ * 获得总距离
+ * @return {Number} 总距离
+ */
+ DistanceTool.prototype._getTotalDistance = function(){
+ var totalDis = 0;
+ for (var i = 0, l = this._segDistance.length; i < l; i ++){
+ totalDis += this._segDistance[i];
+ }
+ return totalDis;
+ };
+
+ /**
+ * 将米制单位的数值换算成为目标单位下的数值
+ * @type {Number} 需要转换的数值
+ * @type {String} 字符串描述的目标单位,
+ * "metric" 表示米制单位,
+ * "us" 表示美国传统单位制
+ * @return {Number} 转换后的数值
+ */
+ DistanceTool.prototype._convertUnit = function(num, unit){
+ unit = unit || "metric";
+ if (this._units[unit]){
+ return num * this._units[unit].conv;
+ }
+ return num;
+ };
+
+ /**
+ * 添加测距结点
+ * @param {BMap.Point} 节点
+ * @return 无返回值
+ */
+ DistanceTool.prototype._addSecPoint = function(pt){
+ var ico =
+ this._opts.secIcon ?
+ this._opts.secIcon :
+ new BMap.Icon("http://api.map.baidu.com/images/mapctrls.png", new BMap.Size(11, 11), {imageOffset: new BMap.Size(-26, -313)});
+ var secPt = new BMap.Marker(pt, {
+ icon : ico,
+ clickable : false,
+ baseZIndex : 3500000,
+ zIndexFixed : true,
+ enableMassClear : this._enableMassClear
+ });
+ this._map.addOverlay(secPt);
+ this._dots.push(secPt);
+ };
+
+ /**
+ * 格式化距离字符串
+ * @param {Number} 距离
+ * @return {String} 格式化的字符串
+ */
+ DistanceTool.prototype._formatDisStr = function(distance){
+ var u = this._opts.unit;
+ var unit = this._units[u].u1;
+ var dis = this._convertUnit(distance, u);
+
+ if (dis > this._units[u].incon){
+ dis = dis / this._units[u].incon;
+ unit = this._units[u].u2;
+ dis = dis.toFixed(1);
+ } else {
+ dis = dis.toFixed(0);
+ }
+ return dis + unit;
+ };
+
+ /**
+ * 设置鼠标样式
+ * @param {String} cursor 鼠标样式
+ * @return 没有返回值
+ */
+ DistanceTool.prototype._setCursor = function(cursor){
+ // 由于webkit内核浏览器下,cursor设置后默认不会居中,所以需要对偏移值进行设置
+ var csr =
+ /webkit/.test(navigator.userAgent.toLowerCase()) ?
+ "url(" + this._opts.cursor + ") 3 6, crosshair" :
+ "url(" + this._opts.cursor + "), crosshair"
+ OperationMask._setCursor(csr);
+ };
+
+ /**
+ * 获取鼠标样式
+ * @return {String} 跟随的鼠标样式
+ */
+ DistanceTool.prototype._getCursor = function(){
+ return this._opts.cursor;
+ };
+
+ /**
+ * 调整分段距离样式
+ * @param {BMap.Label} label 提示框的Label
+ * @param {String} 需要填入的文字
+ * @return 没有返回值
+ */
+ DistanceTool.prototype._formatSegLabel = function(label, text){
+ label.setStyle({"border" : "none", "padding" : "0"});
+ label.setContent("" + text + " ");
+ };
+
+ /**
+ * 处理最后一次操作,当用户双击或测距被强行退出时调用
+ * @return 没有返回值
+ */
+ DistanceTool.prototype._processLastOp = function() {
+ var me = this;
+ // 删除上次移动临时数据
+ delete me._bind.x;
+ delete me._bind.y;
+ delete me._bind.initX;
+ delete me._bind.initY;
+ // 验证路径
+ if (me._paths.length > me._points.length - 1){
+ var l = me._paths.length - 1;
+ me._paths[l].remove();
+ me._paths[l] = null;
+ me._paths.length = l;
+ }
+ // 保存本次测距对象
+ var disObj = {};
+ disObj.points = me._points.slice(0);
+ disObj.paths = me._paths.slice(0);
+ disObj.dots = me._dots.slice(0);
+ disObj.segDis = me._segDistance.slice(0);
+ // 判断总距离和按钮位置
+ var lstPx = me._map.pointToPixel(disObj.points[disObj.points.length - 1]);
+ var prePx = me._map.pointToPixel(disObj.points[disObj.points.length - 2]);
+ var btnOffset = [0, 0];
+ var disOffset = [0, 0];
+ if (lstPx.y - prePx.y >= 0){
+ // 距离位于下端
+ disOffset = [-5, 11];
+ } else {
+ // 距离位于上端
+ disOffset = [-5, -35];
+ }
+ if (lstPx.x - prePx.x >= 0){
+ // 按钮位于右侧
+ btnOffset = [14, 0];
+ } else {
+ // 按钮位于左侧
+ btnOffset = [-14, 0];
+ }
+ // 显示总距离
+ var pt = disObj.points[disObj.points.length - 1];
+ pt.disLabel = new BMap.Label("", {offset: new BMap.Size(-15, -40), enableMassClear: me._enableMassClear});
+ pt.disLabel.setStyles({color: "#333", borderColor: "#ff0103"});
+ me._map.addOverlay(pt.disLabel);
+ pt.disLabel.setOffset(new BMap.Size(disOffset[0], disOffset[1]));
+ pt.disLabel.setPosition(pt);
+ me._formatTitle(2, "", "", pt.disLabel);
+ // 添加关闭按钮
+ var bico =
+ this._opts.closeIcon ?
+ this._opts.closeIcon :
+ new BMap.Icon("http://api.map.baidu.com/images/mapctrls.gif", new BMap.Size(12, 12), {imageOffset: new BMap.Size(0, -14)});
+ disObj.closeBtn = new BMap.Marker(disObj.points[disObj.points.length - 1],
+ {icon : bico,
+ offset : new BMap.Size(btnOffset[0], btnOffset[1]),
+ baseZIndex : 3600000,
+ enableMassClear : me._enableMassClear}
+ );
+ me._map.addOverlay(disObj.closeBtn);
+ disObj.closeBtn.setTitle("清除本次测距");
+ // 点击关闭按钮,绑定关闭按钮事件
+ disObj.closeBtn.addEventListener("click", function(e){
+ // 关闭本次测距,清除相关存储和变量
+ for (var i = 0, l = disObj.points.length; i < l; i ++){
+ disObj.points[i].disLabel.remove();
+ disObj.points[i].disLabel = null;
+ }
+ for (var i = 0, l = disObj.paths.length; i < l; i ++){
+ disObj.paths[i].remove();
+ disObj.paths[i] = null;
+ }
+ for (var i = 0, l = disObj.dots.length; i < l; i ++){
+ disObj.dots[i].remove();
+ disObj.dots[i] = null;
+ }
+ disObj.closeBtn.remove();
+ disObj.closeBtn = null;
+ stopBubble(e);
+
+ /**
+ * @ignore
+ * 测距结束后,点击线段上最后一个节点旁的关闭按钮时,派发事件的接口
+ * @name DistanceTool#onremovepolyline
+ * @event
+ * @param {Event Object} e 回调函数会返回event参数
+ *
+ * @example 参考示例:
+ * myDistanceToolObject.addEventListener("removepolyline", function(e) { alert(e.type); });
+ */
+
+ // 生成名为onremovepolyline的baidu.lang.Event对象
+ // 然后在此刻,将绑定在onremovepolyline上事件,全部赋予event参数,然后派发出去
+ var event = new baidu.lang.Event("onremovepolyline");
+ me.dispatchEvent(event);
+ });
+ me._initData();
+ };
+
+ /**
+ * 生成测距过程中的文字提示框
+ * @param {String} type
+ * @param {String} text
+ * @param {String} distance
+ * @param {Label} label
+ * @return 无返回值
+ */
+ DistanceTool.prototype._formatTitle = function(type, text, distance, label){
+ var title = label || this._followTitle;
+ if (!title){
+ return;
+ }
+ title.setStyle({"lineHeight" : "16px", "zIndex" : "85", "padding" : "0px 0px","border": "none","backgroud-color":"rgba(0,0,0,0.0)"});
+ var t = this._startFollowText || "";
+ var htmls = [];
+ if (type == 1){
+ // 测距过程中的提示
+ title.setOffset(0, 25);
+ var u = this._opts.unit;
+ var unit = this._units[u].u1;
+ var dis = this._convertUnit(distance, u);
+ if (dis > this._units[u].incon){
+ dis = dis / this._units[u].incon;
+ unit = this._units[u].u2;
+ dis = dis.toFixed(1);
+ } else {
+ dis = dis.toFixed(0);
+ }
+ htmls.push("总长:" + dis + " " + unit + " ");
+ htmls.push("" + text + " ");
+ } else if (type == 2) {
+ // 结束时的总距离展示
+ var u = this._opts.unit;
+ var unit = this._units[u].u1;
+ var dis = this._convertUnit(this._getTotalDistance(), u);
+ if (dis > this._units[u].incon){
+ dis = dis / this._units[u].incon;
+ unit = this._units[u].u2;
+ dis = dis.toFixed(1);
+ } else{
+ dis = dis.toFixed(0);
+ }
+ htmls.push("总长:" + dis + " " + unit);
+ } else {
+ title.setOffset(0, 25);
+ htmls.push(t);
+ }
+ title.setContent(htmls.join(""));
+ };
+
+ /**
+ * 更新label的距离
+ * @param HTMLElement label的DOM元素
+ * @param Number 距离
+ */
+ DistanceTool.prototype._updateInstDis = function(label, dis){
+ // 换算距离
+ var u = this._opts.unit;
+ var unit = this._units[u].u1;
+ if (dis > this._units[u].incon){
+ dis = dis / this._units[u].incon;
+ unit = this._units[u].u2;
+ dis = dis.toFixed(1);
+ } else {
+ dis = dis.toFixed(0);
+ }
+ // 修改Label的内容
+ if (label) {
+ var htmls = [];
+ htmls.push("总长:" + dis + " " + unit + " ");
+ htmls.push("" + this._opts.followText + " ");
+ label.setContent(htmls.join(""));
+ }
+ };
+
+ /**
+ * 隐藏相关的线段和提示框文字
+ * @return 无返回值
+ */
+ DistanceTool.prototype._hideCurrent = function(){
+ if (!this._isOpen){
+ return;
+ }
+ if (this._paths.length > 0){
+ var p = this._paths[this._paths.length - 1];
+ p.hide();
+ }
+ this._followTitle && this._followTitle.hide();
+ };
+
+ /**
+ * 验证传入点的位置合理性
+ * @param {BMap.Point} pt 需要被验证的point点
+ * @return 无返回值
+ */
+ DistanceTool.prototype._isPointValid = function(pt){
+ if (!pt){
+ return false;
+ }
+ var mapBounds = this._map.getBounds();
+ var sw = mapBounds.getSouthWest(),
+ ne = mapBounds.getNorthEast();
+ if (pt.lng < sw.lng ||
+ pt.lng > ne.lng ||
+ pt.lat < sw.lat ||
+ pt.lat > ne.lat) {
+ return false;
+ }
+ return true;
+ };
+
+
+ /**
+ * OperationMask,透明覆盖层,在地图上进行鼠标绘制操作时使用,
+ * 闭包,对外不暴露
+ */
+ var OperationMask = {
+ /**
+ * map对象
+ * @type {Map}
+ */
+ _map : null,
+
+ /**
+ * HTML字符串
+ * @type {String}
+ */
+ _html : "
",
+
+ /**
+ * html元素
+ * @type {HTMLElement}
+ */
+ _maskElement : null,
+
+ /**
+ * 鼠标指针
+ * @type {String}
+ */
+ _cursor: 'default',
+
+ /**
+ * 操作层是否在使用中
+ * @type {Boolean}
+ */
+ _inUse: false,
+
+ /**
+ * 透明覆盖层的显示
+ *
+ * @param {Map} map map对象
+ * @return 无返回值
+ */
+ show : function(map) {
+ if (!this._map) {
+ this._map = map;
+ }
+ this._inUse = true;
+ if (!this._maskElement) {
+ this._createMask(map);
+ }
+ this._maskElement.style.display = 'block';
+ },
+
+ /**
+ * 创建覆盖层
+ *
+ * @param {Map} map map对象
+ * @return 无返回值
+ */
+ _createMask : function(map) {
+ this._map = map;
+ if (!this._map) {
+ return;
+ }
+ baidu.insertHTML(this._map.getContainer(), "beforeEnd", this._html);
+ var elem = this._maskElement = this._map.getContainer().lastChild;
+
+ var stopAndPrevent = function(e) {
+ stopBubble(e);
+ return baidu.preventDefault(e);
+ }
+ baidu.on(elem, 'mouseup', function(e) {
+ if (e.button == 2) {
+ stopAndPrevent(e);
+ }
+ });
+ baidu.on(elem, 'contextmenu', stopAndPrevent);
+ elem.style.display = 'none';
+ },
+
+ /**
+ * 获取当前绘制点的地理坐标
+ *
+ * @param {Event} e e对象
+ * @param {Boolean} n 是否向上查到相对于地图container元素的坐标位置
+ * @return Point对象的位置信息
+ */
+ getDrawPoint : function(e, n) {
+ e = window.event || e;
+ var x = e.layerX || e.offsetX || 0;
+ var y = e.layerY || e.offsetY || 0;
+ var t = e.target || e.srcElement;
+ if (t != OperationMask.getDom(this._map) && n == true) {
+ while (t && t != this._map.getContainer()) {
+ if (!(t.clientWidth == 0 &&
+ t.clientHeight == 0 &&
+ t.offsetParent &&
+ t.offsetParent.nodeName.toLowerCase() == 'td')) {
+ x += t.offsetLeft;
+ y += t.offsetTop;
+ }
+ t = t.offsetParent;
+ }
+ }
+
+ if (t != OperationMask.getDom(this._map) &&
+ t != this._map.getContainer()) {
+ return;
+ }
+ if (typeof x === 'undefined' ||
+ typeof y === 'undefined') {
+ return;
+ }
+ if (isNaN(x) || isNaN(y)) {
+ return;
+ }
+ return this._map.pixelToPoint(new BMap.Pixel(x, y));
+ },
+
+ /**
+ * 透明覆盖层的隐藏
+ *
+ * @return 无返回值
+ */
+ hide : function() {
+ if (!this._map) {
+ return;
+ }
+ this._inUse = false;
+ if (this._maskElement) {
+ this._maskElement.style.display = 'none';
+ }
+ },
+
+ /**
+ * 获取HTML容器
+ *
+ * @param {Map} map map对象
+ * @return HTML容器元素
+ */
+ getDom : function(map) {
+ if (!this._maskElement) {
+ this._createMask(map);
+ }
+ return this._maskElement;
+ },
+
+ /**
+ * 设置鼠标样式
+ *
+ * @type {String} cursor 鼠标样式
+ * @return 无返回值
+ */
+ _setCursor : function(cursor) {
+ this._cursor = cursor || 'default';
+ if (this._maskElement) {
+ this._maskElement.style.cursor = this._cursor;
+ }
+ }
+ };
+
+ /**
+ * 停止事件冒泡传播,
+ * 闭包,对外不暴露
+ *
+ * @type {Event} e e对象
+ */
+ function stopBubble(e){
+ var e = window.event || e;
+ e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
+ };
+})();
\ No newline at end of file
diff --git a/worldmap/static/js/Register.js b/worldmap/static/js/Register.js
new file mode 100644
index 0000000..2232069
--- /dev/null
+++ b/worldmap/static/js/Register.js
@@ -0,0 +1,276 @@
+$(document).ready(function () {
+ //背景动画
+ //glInitialize();
+ //用户名验证
+ var state1 = false;
+ $("#username").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#uinfo").text("用户名不能为空");
+ state1 = false;
+ } else {
+ $.ajax({
+ url: "./userExists.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ username: $('#username').val().trim()
+ },
+ success: function (flag) {
+ if (flag == "true") {
+ $("#uinfo").text("该用户名已存在,请重新填写");
+ state1 = false;
+ } else if (flag == "false") {
+ $("#uinfo").text('');
+ $("#uinfo").append(" ");
+ state1 = true;
+ }
+ }
+ })
+ }
+ });
+
+ //密码验证
+ var state2 = false;
+ $("#password").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#pinfo").text("密码不能为空");
+ state2 = false;
+ } else {
+ if ($(this).val().length < 6) {
+ $("#pinfo").text("密码必须大于等于6位,请重新填写");
+ state2 = false;
+ } else if ($(this).val().length > 20) {
+ $("#pinfo").text("密码必须小于等于20位,请重新填写");
+ state2 = false;
+ } else {
+ $("#pinfo").text('');
+ $("#pinfo").append(" ");
+ state2 = true;
+ }
+ }
+ });
+ //确认密码
+ var state3 = false;
+ $("#passwordagain").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#painfo").text("密码不能为空");
+ state3 = false;
+ } else {
+ if ($("#passwordagain").textbox('getValue') != $("#password").val()) {
+ $("#painfo").text("两次输入的密码不一致,请重新填写");
+ state3 = false;
+ } else {
+ $("#painfo").text('');
+ $("#painfo").append(" ");
+ state3 = true;
+ }
+ }
+ });
+ //邮箱验证
+ var state4 = false;
+ $("#email").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#einfo").text("邮箱不能为空");
+ state4 = false;
+ } else {
+ if (/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test($(this).val()) == false) {
+ $("#einfo").text("邮箱格式不正确,请重新填写");
+ state4 = false;
+ } else {
+ $.ajax({
+ url: "./emailExists.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ email: $('#email').val().trim()
+ },
+ success: function (flag) {
+ if (flag == "true") {
+ $("#einfo").text("该邮箱已被占用,请重新填写");
+ state4 = false;
+ } else if (flag == "false") {
+ $("#einfo").text('');
+ $("#einfo").append(" ");
+ state4 = true;
+ }
+ }
+ })
+
+ }
+ }
+ });
+
+ var state5 = false;
+ $("#realname").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#rninfo").text("姓名不能为空");
+ state5 = false;
+ }
+ else{
+ $("#rninfo").text('');
+ $("#rninfo").append(" ");
+ state5 = true;
+ }
+ });
+
+
+ var state6 = false;
+ $("#comp").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#cpinfo").text("所在单位不能为空");
+ state6 = false;
+ }
+ else{
+ $("#cpinfo").text('');
+ $("#cpinfo").append(" ");
+ state6 = true;
+ }
+ });
+
+ var state7 = false;
+ $("#cretificate").textbox('textbox').blur(function () {
+ if ($(this).val() == '') {
+ $("#creinfo").text("证件号码不能为空");
+ state7 = false;
+ }
+ else{
+ $("#creinfo").text('');
+ $("#creinfo").append(" ");
+ state7 = true;
+ }
+ });
+
+ var state8 = false;
+ //初始化没有阅读相关政策时的状态——不能注册
+ $("#mustagree").css("display","block");
+ $("#registerbtn").addClass("disabled");
+ $("#registerbtn").css("background","#aaaaaa");
+ $("#registerbtn").hover(function(){
+ $("#registerbt").css("background","#aaaaaa");
+ })
+
+ $("#agree").click(function(){
+ if($("#agree").is(':checked')){
+ $("#mustagree").css("display","none");
+ $("#registerbtn").removeClass("disabled");
+ $("#registerbtn").css("background","#2573f0");
+ $("#registerbtn").hover(
+ function(){
+ $("#registerbtn").css("backgroun","#0000ff");
+ $("#registerbtn").css("cursor","pointer");
+ },function(){
+ $("#registerbtn").css("background","#2573f0");
+ })
+ state8 = true;
+ }else{
+ $("#mustagree").css("display","block");
+ $("#registerbtn").addClass("disabled");
+ $("#registerbtn").css("background","#aaaaaa");
+ $("#registerbtn").hover(function(){
+ $("#registerbt").css("background","#aaaaaa");
+ })
+ }
+ });
+
+ $("#cretifitype").combobox(
+ {
+ valueField:'id',
+ textField:'text',
+ data:[
+ {
+ id:0,
+ text:"身份证"
+ },
+ {
+ id:1,
+ text:"护照"
+ },
+ {
+ id:2,
+ text:"学生证"
+ }
+ ]
+
+ }
+ );
+ $("#cretifitype").combobox('select',0);
+ //发邮件
+ $("#sendcode2email").click(function () {
+ if(state4){
+ $.ajax({
+ url: "./sendcode2email.action",
+ async: true,
+ type: "POST",
+ dataType: "text",
+ data: {
+ email: $('#email').val().trim()
+ },
+ //contentType:"application/json",
+ success: function (data) {
+ alert(data);
+ },
+ error: function () {
+ alert("未知错误");
+ }
+ });
+ }else{
+ alert("邮箱信息错误!")
+ }
+ });
+
+ //注册
+ $("#registerbtn").click(function () {
+ if(!state8){}
+ if (state1 && state2 && state3 && state4
+ && state5 && state6 && state7) {
+ $.ajax({
+ url: "./register.action",
+ type: "POST",
+ dataType: "text",
+ data: {
+ username: $('#username').val().trim(),
+ password: hex_md5($('#password').val().trim()),
+ email: $('#email').val().trim(),
+ checkcode: $('#email_code').val().trim(),
+ cretificate:$('#cretificate').val().trim(),
+ realname:$('#realname').val().trim(),
+ comp:$('#comp').val().trim(),
+ cretifitype:$('#cretifitype').combobox('getValue').trim(),
+ },
+ success: function (row) {
+ if (row == 1) {
+ //alert("注册成功");
+ $.messager.show({
+ title: '恭喜您',
+ msg: '注册成功!',
+ showType: 'show',
+ timeout: 1000,
+ style: {
+ right: '',
+ bottom: '',
+ }
+ });
+ setTimeout(function () {
+ window.location.href = "./index.action"
+ }, 1000);
+ } else {
+ alert(row);
+ }
+ },
+ error: function () {
+ alert("未知错误!");
+ }
+ })
+ } else {
+ $.messager.alert('注册失败', '注册信息不正确!');
+ }
+
+ });
+
+ $("#cancelbtn").click(function (){
+ location.href = "http://localhost:8080/AncientMap/index.action";
+ });
+
+})
diff --git a/worldmap/static/js/base.js b/worldmap/static/js/base.js
new file mode 100644
index 0000000..2ac0e74
--- /dev/null
+++ b/worldmap/static/js/base.js
@@ -0,0 +1,300 @@
+window.onload=function(){
+ setImgHeight();//set the height according to the width, the rate is 4:3[noData.jpg]
+}
+//be activated when browser's size is changed
+window.onresize=function(){
+ setImgHeight();//set the height according to the width, the rate is 4:3[noData.jpg]
+}
+//set the selectchange event of category selectpicker
+function selectOnChange1(obj){
+ var value = obj.options[obj.selectedIndex].value;
+ showMaps("tmi1","hottest",value);
+}
+function selectOnChange2(obj){
+ var value = obj.options[obj.selectedIndex].value;
+ showMaps("tmi2","latest", value);
+}
+function showCategorys(language){
+ var url = "/getCategory/";
+ var data = null;
+ var csrftoken = getCookie('csrftoken');
+ $.ajax({
+ url: url,
+ async: false,
+ cache: false,
+ type: "POST",
+ data: {
+ language: language
+ },
+ success: function (res) {
+ data = $.parseJSON(res);
+ },
+ beforeSend: function(xhr, settings) {
+ xhr.setRequestHeader("X-CSRFToken", csrftoken);
+ }
+ });
+ var selectHTML = "";
+ for(category in data){
+ var categoryid = parseInt(category);
+ var categorydescription = data[category][0];
+ selectHTML += ""+categorydescription+" "
+ }
+ $("#category1").append(selectHTML);
+ $("#category2").append(selectHTML);
+ $("#category1").selectpicker('refresh');
+ $("#category2").selectpicker('refresh');
+}
+function showMaps(divIdPrefix, type, category){
+ var result = null;
+ var url = "/getMostMaps/";
+ var csrftoken = getCookie('csrftoken');
+ $.ajax({
+ url: url,
+ async: false,
+ type: "POST",
+ data: {
+ category: category,
+ type: type
+ },
+ success: function (res) {
+ result = $.parseJSON(res);
+ },
+ beforeSend: function(xhr, settings) {
+ xhr.setRequestHeader("X-CSRFToken", csrftoken);
+ }
+ });
+ for(var i = 0; i< 6; i++)
+ {
+ var mapname, curdiv, imgurl, mapurl, img;
+ if(result[i] != null)
+ {
+ mapname = result[i][0];
+ curdiv = divIdPrefix + (i+1);
+ imgurl = result[i][1];
+ mapurl = result[i][2];
+ img = $("#"+curdiv).find("img");
+ $("#"+curdiv).attr("onclick","location='"+mapurl+"'");
+ $("#"+curdiv).children("p").text(mapname);
+
+ if(type=="admin"){
+ if (mapname=="李白行迹图") {
+ imgurl =window.location.href+"uploaded/admingif/libai.gif"
+ }else if (mapname=="杜甫行迹图") {
+ imgurl =window.location.href+"uploaded/admingif/dufu.gif"
+ }else if (mapname=="汤显祖行迹图") {
+ imgurl =window.location.href+"uploaded/admingif/tangxianzu.gif"
+ }else if (mapname=="全宋文专题") {
+ imgurl =window.location.href+"uploaded/admingif/quansongwen.gif"
+ }else if (mapname=="清代妇女作家专题图") {
+ imgurl =window.location.href+"uploaded/admingif/qingdaifunv.gif"
+ }
+ }
+
+ img.attr("src",imgurl);
+ }
+ else
+ {
+ curdiv = divIdPrefix + (i+1);
+ img = $("#"+curdiv).find("img");
+ if(typeof($("#"+curdiv).attr("onclick"))!="undefined")
+ {
+ $("#"+curdiv).removeAttr("onclick");
+ $("#"+curdiv).children("p").text("");
+ img.attr("src","{{ STATIC_URL }}img/map/noData.jpg");
+ }
+ }
+ }
+}
+// get cookie value from cookies
+function getCookie(name) {
+ var cookieValue = null;
+ if (document.cookie && document.cookie !== '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) === (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+}
+function setImgHeight() {
+ var imgs = $(".picItem");
+ imgs.each(function (i) {
+ var img = $(this);
+ var width = img.width();
+ var height = width* 0.75;
+ img.height(height);
+ });
+ var imgs = $(".item");
+ imgs.each(function (i) {
+ var img = $(this);
+ var width = img.width();
+ var height = width* 0.75;
+ img.height(height);
+ });
+}
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
\ No newline at end of file
diff --git a/worldmap/static/js/bmap.js b/worldmap/static/js/bmap.js
new file mode 100644
index 0000000..e19bb47
--- /dev/null
+++ b/worldmap/static/js/bmap.js
@@ -0,0 +1,424 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory(require("echarts"));
+ else if(typeof define === 'function' && define.amd)
+ define(["echarts"], factory);
+ else if(typeof exports === 'object')
+ exports["bmap"] = factory(require("echarts"));
+ else
+ root["echarts"] = root["echarts"] || {}, root["echarts"]["bmap"] = factory(root["echarts"]);
+})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_RESULT__;/**
+ * BMap component extension
+ */
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require) {
+
+ __webpack_require__(1).registerCoordinateSystem(
+ 'bmap', __webpack_require__(2)
+ );
+ __webpack_require__(3);
+ __webpack_require__(4);
+
+ // Action
+ __webpack_require__(1).registerAction({
+ type: 'bmapRoam',
+ event: 'bmapRoam',
+ update: 'updateLayout'
+ }, function (payload, ecModel) {
+ ecModel.eachComponent('bmap', function (bMapModel) {
+ var bmap = bMapModel.getBMap();
+ var center = bmap.getCenter();
+ bMapModel.setCenterAndZoom([center.lng, center.lat], bmap.getZoom());
+ });
+ });
+
+ return {
+ version: '1.0.0'
+ };
+ }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+ module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require) {
+
+ var echarts = __webpack_require__(1);
+ var zrUtil = echarts.util;
+
+ function BMapCoordSys(bmap, api) {
+ this._bmap = bmap;
+ this.dimensions = ['lng', 'lat'];
+ this._mapOffset = [0, 0];
+
+ this._api = api;
+
+ this._projection = new BMap.MercatorProjection();
+ }
+
+ BMapCoordSys.prototype.dimensions = ['lng', 'lat'];
+
+ BMapCoordSys.prototype.setZoom = function (zoom) {
+ this._zoom = zoom;
+ };
+
+ BMapCoordSys.prototype.setCenter = function (center) {
+ this._center = this._projection.lngLatToPoint(new BMap.Point(center[0], center[1]));
+ };
+
+ BMapCoordSys.prototype.setMapOffset = function (mapOffset) {
+ this._mapOffset = mapOffset;
+ };
+
+ BMapCoordSys.prototype.getBMap = function () {
+ return this._bmap;
+ };
+
+ BMapCoordSys.prototype.dataToPoint = function (data) {
+ var point = new BMap.Point(data[0], data[1]);
+ // TODO mercator projection is toooooooo slow
+ // var mercatorPoint = this._projection.lngLatToPoint(point);
+
+ // var width = this._api.getZr().getWidth();
+ // var height = this._api.getZr().getHeight();
+ // var divider = Math.pow(2, 18 - 10);
+ // return [
+ // Math.round((mercatorPoint.x - this._center.x) / divider + width / 2),
+ // Math.round((this._center.y - mercatorPoint.y) / divider + height / 2)
+ // ];
+ var px = this._bmap.pointToOverlayPixel(point);
+ var mapOffset = this._mapOffset;
+ return [px.x - mapOffset[0], px.y - mapOffset[1]];
+ };
+
+ BMapCoordSys.prototype.pointToData = function (pt) {
+ var mapOffset = this._mapOffset;
+ var pt = this._bmap.overlayPixelToPoint({
+ x: pt[0] + mapOffset[0],
+ y: pt[1] + mapOffset[1]
+ });
+ return [pt.lng, pt.lat];
+ };
+
+ BMapCoordSys.prototype.getViewRect = function () {
+ var api = this._api;
+ return new echarts.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight());
+ };
+
+ BMapCoordSys.prototype.getRoamTransform = function () {
+ return echarts.matrix.create();
+ };
+
+ BMapCoordSys.prototype.prepareCustoms = function (data) {
+ var rect = this.getViewRect();
+ return {
+ coordSys: {
+ // The name exposed to user is always 'cartesian2d' but not 'grid'.
+ type: 'bmap',
+ x: rect.x,
+ y: rect.y,
+ width: rect.width,
+ height: rect.height
+ },
+ api: {
+ coord: zrUtil.bind(this.dataToPoint, this),
+ size: zrUtil.bind(dataToCoordSize, this)
+ }
+ };
+ };
+
+ function dataToCoordSize(dataSize, dataItem) {
+ dataItem = dataItem || [0, 0];
+ return zrUtil.map([0, 1], function (dimIdx) {
+ var val = dataItem[dimIdx];
+ var halfSize = dataSize[dimIdx] / 2;
+ var p1 = [];
+ var p2 = [];
+ p1[dimIdx] = val - halfSize;
+ p2[dimIdx] = val + halfSize;
+ p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];
+ return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);
+ }, this);
+ }
+
+ var Overlay;
+
+ // For deciding which dimensions to use when creating list data
+ BMapCoordSys.dimensions = BMapCoordSys.prototype.dimensions;
+
+ function createOverlayCtor() {
+ function Overlay(root) {
+ this._root = root;
+ }
+
+ Overlay.prototype = new BMap.Overlay();
+ /**
+ * 鍒濆鍖�
+ *
+ * @param {BMap.Map} map
+ * @override
+ */
+ Overlay.prototype.initialize = function (map) {
+ map.getPanes().labelPane.appendChild(this._root);
+ return this._root;
+ };
+ /**
+ * @override
+ */
+ Overlay.prototype.draw = function () {};
+
+ return Overlay;
+ }
+
+ BMapCoordSys.create = function (ecModel, api) {
+ var bmapCoordSys;
+ var root = api.getDom();
+
+ // TODO Dispose
+ ecModel.eachComponent('bmap', function (bmapModel) {
+ var viewportRoot = api.getZr().painter.getViewportRoot();
+ if (typeof BMap === 'undefined') {
+ throw new Error('BMap api is not loaded');
+ }
+ Overlay = Overlay || createOverlayCtor();
+ if (bmapCoordSys) {
+ throw new Error('Only one bmap component can exist');
+ }
+ if (!bmapModel.__bmap) {
+ // Not support IE8
+ var bmapRoot = root.querySelector('.ec-extension-bmap');
+ if (bmapRoot) {
+ // Reset viewport left and top, which will be changed
+ // in moving handler in BMapView
+ viewportRoot.style.left = '0px';
+ viewportRoot.style.top = '0px';
+ root.removeChild(bmapRoot);
+ }
+ bmapRoot = document.createElement('div');
+ bmapRoot.style.cssText = 'width:100%;height:100%';
+ // Not support IE8
+ bmapRoot.classList.add('ec-extension-bmap');
+ root.appendChild(bmapRoot);
+ var bmap = bmapModel.__bmap = new BMap.Map(bmapRoot);
+
+ var overlay = new Overlay(viewportRoot);
+ bmap.addOverlay(overlay);
+ }
+ var bmap = bmapModel.__bmap;
+
+ // Set bmap options
+ // centerAndZoom before layout and render
+ var center = bmapModel.get('center');
+ var zoom = bmapModel.get('zoom');
+ if (center && zoom) {
+ var pt = new BMap.Point(center[0], center[1]);
+ bmap.centerAndZoom(pt, zoom);
+ }
+
+ bmapCoordSys = new BMapCoordSys(bmap, api);
+ bmapCoordSys.setMapOffset(bmapModel.__mapOffset || [0, 0]);
+ bmapCoordSys.setZoom(zoom);
+ bmapCoordSys.setCenter(center);
+
+ bmapModel.coordinateSystem = bmapCoordSys;
+ });
+
+ ecModel.eachSeries(function (seriesModel) {
+ if (seriesModel.get('coordinateSystem') === 'bmap') {
+ seriesModel.coordinateSystem = bmapCoordSys;
+ }
+ });
+ };
+
+ return BMapCoordSys;
+ }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require) {
+
+ function v2Equal(a, b) {
+ return a && b && a[0] === b[0] && a[1] === b[1];
+ }
+
+ return __webpack_require__(1).extendComponentModel({
+ type: 'bmap',
+
+ getBMap: function () {
+ // __bmap is injected when creating BMapCoordSys
+ return this.__bmap;
+ },
+
+ setCenterAndZoom: function (center, zoom) {
+ this.option.center = center;
+ this.option.zoom = zoom;
+ },
+
+ centerOrZoomChanged: function (center, zoom) {
+ var option = this.option;
+ return !(v2Equal(center, option.center) && zoom === option.zoom);
+ },
+
+ defaultOption: {
+
+ center: [104.114129, 37.550339],
+
+ zoom: 5,
+
+ mapStyle: {},
+
+ roam: false
+ }
+ });
+ }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require) {
+
+ return __webpack_require__(1).extendComponentView({
+ type: 'bmap',
+
+ render: function (bMapModel, ecModel, api) {
+ var rendering = true;
+
+ var bmap = bMapModel.getBMap();
+ var viewportRoot = api.getZr().painter.getViewportRoot();
+ var coordSys = bMapModel.coordinateSystem;
+ var moveHandler = function (type, target) {
+ if (rendering) {
+ return;
+ }
+ var offsetEl = viewportRoot.parentNode.parentNode.parentNode;
+ var mapOffset = [
+ -parseInt(offsetEl.style.left, 10) || 0,
+ -parseInt(offsetEl.style.top, 10) || 0
+ ];
+ viewportRoot.style.left = mapOffset[0] + 'px';
+ viewportRoot.style.top = mapOffset[1] + 'px';
+
+ coordSys.setMapOffset(mapOffset);
+ bMapModel.__mapOffset = mapOffset;
+
+ api.dispatchAction({
+ type: 'bmapRoam'
+ });
+ };
+
+ function zoomEndHandler() {
+ if (rendering) {
+ return;
+ }
+ api.dispatchAction({
+ type: 'bmapRoam'
+ });
+ }
+
+ bmap.removeEventListener('moving', this._oldMoveHandler);
+ // FIXME
+ // Moveend may be triggered by centerAndZoom method when creating coordSys next time
+ // bmap.removeEventListener('moveend', this._oldMoveHandler);
+ bmap.removeEventListener('zoomend', this._oldZoomEndHandler);
+ bmap.addEventListener('moving', moveHandler);
+ // bmap.addEventListener('moveend', moveHandler);
+ bmap.addEventListener('zoomend', zoomEndHandler);
+
+ this._oldMoveHandler = moveHandler;
+ this._oldZoomEndHandler = zoomEndHandler;
+
+ var roam = bMapModel.get('roam');
+ if (roam && roam !== 'scale') {
+ bmap.enableDragging();
+ }
+ else {
+ bmap.disableDragging();
+ }
+ if (roam && roam !== 'move') {
+ bmap.enableScrollWheelZoom();
+ bmap.enableDoubleClickZoom();
+ bmap.enablePinchToZoom();
+ }
+ else {
+ bmap.disableScrollWheelZoom();
+ bmap.disableDoubleClickZoom();
+ bmap.disablePinchToZoom();
+ }
+
+ var originalStyle = bMapModel.__mapStyle;
+
+ var newMapStyle = bMapModel.get('mapStyle') || {};
+ // FIXME, Not use JSON methods
+ var mapStyleStr = JSON.stringify(newMapStyle);
+ if (JSON.stringify(originalStyle) !== mapStyleStr) {
+ // FIXME May have blank tile when dragging if setMapStyle
+ if (Object.keys(newMapStyle).length) {
+ bmap.setMapStyle(newMapStyle);
+ }
+ bMapModel.__mapStyle = JSON.parse(mapStyleStr);
+ }
+
+ rendering = false;
+ }
+ });
+ }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+
+/***/ }
+/******/ ])
+});
+;
\ No newline at end of file
diff --git a/worldmap/static/js/dragging.js b/worldmap/static/js/dragging.js
new file mode 100644
index 0000000..1c11e75
--- /dev/null
+++ b/worldmap/static/js/dragging.js
@@ -0,0 +1,71 @@
+//参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
+var Dragging=function(validateHandler){
+ var draggingObj=null; //dragging Dialog
+ var diffX=0;
+ var diffY=0;
+ var windowH;
+ var windowW;
+ function mouseHandler(e){
+ var windowH =$(window).height();
+ var windowW =$(window).width();
+
+ switch(e.type){
+ case 'mousedown':
+ draggingObj=validateHandler(e);//验证是否为可点击移动区域
+ if(draggingObj!=null){
+ diffX=e.clientX-draggingObj.offsetLeft;
+ diffY=e.clientY-draggingObj.offsetTop;
+ }
+ break;
+
+ case 'mousemove':
+ if(draggingObj){
+ if(draggingObj.className.indexOf('dragablerb')>=0){
+ draggingObj.style.right=windowW-draggingObj.offsetWidth-(e.clientX-diffX)+'px';
+ draggingObj.style.bottom=windowH-draggingObj.offsetHeight-(e.clientY-diffY)+'px';
+ }
+ else{
+ draggingObj.style.left=(e.clientX-diffX)+'px';
+ draggingObj.style.top=(e.clientY-diffY)+'px';
+
+ }
+ }
+ break;
+
+ case 'mouseup':
+ draggingObj =null;
+ diffX=0;
+ diffY=0;
+ break;
+ }
+ };
+
+ return {
+ enable:function(){
+ document.addEventListener('mousedown',mouseHandler);
+ document.addEventListener('mousemove',mouseHandler);
+ document.addEventListener('mouseup',mouseHandler);
+ },
+ disable:function(){
+ document.removeEventListener('mousedown',mouseHandler);
+ document.removeEventListener('mousemove',mouseHandler);
+ document.removeEventListener('mouseup',mouseHandler);
+ }
+ }
+ }
+
+ function getDraggingDialog(e){
+ var target=e.target;
+
+ while(target && target.className.indexOf('dragable')==-1){
+ target=target.offsetParent;
+ }
+
+ if(target!=null && target.className.indexOf('dragable')>=0)
+ return target;
+ else{
+ return null;
+ }
+ }
+
+
\ No newline at end of file
diff --git a/worldmap/static/js/echarts.js b/worldmap/static/js/echarts.js
new file mode 100644
index 0000000..ee759b2
--- /dev/null
+++ b/worldmap/static/js/echarts.js
@@ -0,0 +1,75145 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define([], factory);
+ else if(typeof exports === 'object')
+ exports["echarts"] = factory();
+ else
+ root["echarts"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Export echarts as CommonJS module
+ */
+ module.exports = __webpack_require__(1);
+
+ // Import all charts and components
+ __webpack_require__(113);
+ __webpack_require__(139);
+ __webpack_require__(146);
+ __webpack_require__(155);
+ __webpack_require__(159);
+
+ __webpack_require__(169);
+ __webpack_require__(193);
+ __webpack_require__(205);
+ __webpack_require__(226);
+ __webpack_require__(230);
+ __webpack_require__(234);
+ __webpack_require__(251);
+ __webpack_require__(257);
+ __webpack_require__(264);
+ __webpack_require__(270);
+ __webpack_require__(274);
+ __webpack_require__(283);
+ __webpack_require__(287);
+ __webpack_require__(290);
+ __webpack_require__(313);
+
+ __webpack_require__(319);
+ __webpack_require__(320);
+ __webpack_require__(321);
+ __webpack_require__(327);
+ __webpack_require__(298);
+ __webpack_require__(331);
+ __webpack_require__(344);
+ __webpack_require__(235);
+ __webpack_require__(291);
+ __webpack_require__(347);
+ __webpack_require__(358);
+
+ __webpack_require__(362);
+
+ __webpack_require__(363);
+ __webpack_require__(376);
+
+ __webpack_require__(391);
+ __webpack_require__(397);
+ __webpack_require__(400);
+
+ __webpack_require__(403);
+ __webpack_require__(412);
+
+ __webpack_require__(424);
+
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // Enable DEV mode when using source code without build. which has no __DEV__ variable
+ // In build process 'typeof __DEV__' will be replace with 'boolean'
+ // So this code will be removed or disabled anyway after built.
+ if (false) {
+ // In browser
+ if (typeof window !== 'undefined') {
+ window.__DEV__ = true;
+ }
+ // In node
+ else if (typeof global !== 'undefined') {
+ global.__DEV__ = true;
+ }
+ }
+
+ /*!
+ * ECharts, a javascript interactive chart library.
+ *
+ * Copyright (c) 2015, Baidu Inc.
+ * All rights reserved.
+ *
+ * LICENSE
+ * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
+ */
+
+ /**
+ * @module echarts
+ */
+
+
+ var env = __webpack_require__(2);
+
+ var GlobalModel = __webpack_require__(3);
+ var ExtensionAPI = __webpack_require__(75);
+ var CoordinateSystemManager = __webpack_require__(76);
+ var OptionManager = __webpack_require__(77);
+
+ var ComponentModel = __webpack_require__(69);
+ var SeriesModel = __webpack_require__(78);
+
+ var ComponentView = __webpack_require__(79);
+ var ChartView = __webpack_require__(80);
+ var graphic = __webpack_require__(18);
+ var modelUtil = __webpack_require__(5);
+ var throttle = __webpack_require__(81);
+
+ var zrender = __webpack_require__(82);
+ var zrUtil = __webpack_require__(4);
+ var colorTool = __webpack_require__(31);
+ var Eventful = __webpack_require__(25);
+ var timsort = __webpack_require__(86);
+
+ var each = zrUtil.each;
+ var parseClassType = ComponentModel.parseClassType;
+
+ var PRIORITY_PROCESSOR_FILTER = 1000;
+ var PRIORITY_PROCESSOR_STATISTIC = 5000;
+
+
+ var PRIORITY_VISUAL_LAYOUT = 1000;
+ var PRIORITY_VISUAL_GLOBAL = 2000;
+ var PRIORITY_VISUAL_CHART = 3000;
+ var PRIORITY_VISUAL_COMPONENT = 4000;
+ // FIXME
+ // necessary?
+ var PRIORITY_VISUAL_BRUSH = 5000;
+
+ // Main process have three entries: `setOption`, `dispatchAction` and `resize`,
+ // where they must not be invoked nestedly, except the only case: invoke
+ // dispatchAction with updateMethod "none" in main process.
+ // This flag is used to carry out this rule.
+ // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
+ var IN_MAIN_PROCESS = '__flagInMainProcess';
+ var HAS_GRADIENT_OR_PATTERN_BG = '__hasGradientOrPatternBg';
+ var OPTION_UPDATED = '__optionUpdated';
+ var ACTION_REG = /^[a-zA-Z0-9_]+$/;
+
+ function createRegisterEventWithLowercaseName(method) {
+ return function (eventName, handler, context) {
+ // Event name is all lowercase
+ eventName = eventName && eventName.toLowerCase();
+ Eventful.prototype[method].call(this, eventName, handler, context);
+ };
+ }
+
+ /**
+ * @module echarts~MessageCenter
+ */
+ function MessageCenter() {
+ Eventful.call(this);
+ }
+ MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');
+ MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');
+ MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');
+ zrUtil.mixin(MessageCenter, Eventful);
+
+ /**
+ * @module echarts~ECharts
+ */
+ function ECharts(dom, theme, opts) {
+ opts = opts || {};
+
+ // Get theme by name
+ if (typeof theme === 'string') {
+ theme = themeStorage[theme];
+ }
+
+ /**
+ * @type {string}
+ */
+ this.id;
+ /**
+ * Group id
+ * @type {string}
+ */
+ this.group;
+ /**
+ * @type {HTMLDomElement}
+ * @private
+ */
+ this._dom = dom;
+ /**
+ * @type {module:zrender/ZRender}
+ * @private
+ */
+ var zr = this._zr = zrender.init(dom, {
+ renderer: opts.renderer || 'canvas',
+ devicePixelRatio: opts.devicePixelRatio,
+ width: opts.width,
+ height: opts.height
+ });
+
+ /**
+ * Expect 60 pfs.
+ * @type {Function}
+ * @private
+ */
+ this._throttledZrFlush = throttle.throttle(zrUtil.bind(zr.flush, zr), 17);
+
+ /**
+ * @type {Object}
+ * @private
+ */
+ this._theme = zrUtil.clone(theme);
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this._chartsViews = [];
+
+ /**
+ * @type {Object.}
+ * @private
+ */
+ this._chartsMap = {};
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this._componentsViews = [];
+
+ /**
+ * @type {Object.}
+ * @private
+ */
+ this._componentsMap = {};
+
+ /**
+ * @type {module:echarts/CoordinateSystem}
+ * @private
+ */
+ this._coordSysMgr = new CoordinateSystemManager();
+
+ /**
+ * @type {module:echarts/ExtensionAPI}
+ * @private
+ */
+ this._api = createExtensionAPI(this);
+
+ Eventful.call(this);
+
+ /**
+ * @type {module:echarts~MessageCenter}
+ * @private
+ */
+ this._messageCenter = new MessageCenter();
+
+ // Init mouse events
+ this._initEvents();
+
+ // In case some people write `window.onresize = chart.resize`
+ this.resize = zrUtil.bind(this.resize, this);
+
+ // Can't dispatch action during rendering procedure
+ this._pendingActions = [];
+ // Sort on demand
+ function prioritySortFunc(a, b) {
+ return a.prio - b.prio;
+ }
+ timsort(visualFuncs, prioritySortFunc);
+ timsort(dataProcessorFuncs, prioritySortFunc);
+
+ zr.animation.on('frame', this._onframe, this);
+
+ // ECharts instance can be used as value.
+ zrUtil.setAsPrimitive(this);
+ }
+
+ var echartsProto = ECharts.prototype;
+
+ echartsProto._onframe = function () {
+ // Lazy update
+ if (this[OPTION_UPDATED]) {
+ var silent = this[OPTION_UPDATED].silent;
+
+ this[IN_MAIN_PROCESS] = true;
+
+ updateMethods.prepareAndUpdate.call(this);
+
+ this[IN_MAIN_PROCESS] = false;
+
+ this[OPTION_UPDATED] = false;
+
+ flushPendingActions.call(this, silent);
+
+ triggerUpdatedEvent.call(this, silent);
+ }
+ };
+ /**
+ * @return {HTMLDomElement}
+ */
+ echartsProto.getDom = function () {
+ return this._dom;
+ };
+
+ /**
+ * @return {module:zrender~ZRender}
+ */
+ echartsProto.getZr = function () {
+ return this._zr;
+ };
+
+ /**
+ * Usage:
+ * chart.setOption(option, notMerge, lazyUpdate);
+ * chart.setOption(option, {
+ * notMerge: ...,
+ * lazyUpdate: ...,
+ * silent: ...
+ * });
+ *
+ * @param {Object} option
+ * @param {Object|boolean} [opts] opts or notMerge.
+ * @param {boolean} [opts.notMerge=false]
+ * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.
+ */
+ echartsProto.setOption = function (option, notMerge, lazyUpdate) {
+ if (true) {
+ zrUtil.assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');
+ }
+
+ var silent;
+ if (zrUtil.isObject(notMerge)) {
+ lazyUpdate = notMerge.lazyUpdate;
+ silent = notMerge.silent;
+ notMerge = notMerge.notMerge;
+ }
+
+ this[IN_MAIN_PROCESS] = true;
+
+ if (!this._model || notMerge) {
+ var optionManager = new OptionManager(this._api);
+ var theme = this._theme;
+ var ecModel = this._model = new GlobalModel(null, null, theme, optionManager);
+ ecModel.init(null, null, theme, optionManager);
+ }
+
+ this._model.setOption(option, optionPreprocessorFuncs);
+
+ if (lazyUpdate) {
+ this[OPTION_UPDATED] = {silent: silent};
+ this[IN_MAIN_PROCESS] = false;
+ }
+ else {
+ updateMethods.prepareAndUpdate.call(this);
+ // Ensure zr refresh sychronously, and then pixel in canvas can be
+ // fetched after `setOption`.
+ this._zr.flush();
+
+ this[OPTION_UPDATED] = false;
+ this[IN_MAIN_PROCESS] = false;
+
+ flushPendingActions.call(this, silent);
+ triggerUpdatedEvent.call(this, silent);
+ }
+ };
+
+ /**
+ * @DEPRECATED
+ */
+ echartsProto.setTheme = function () {
+ console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
+ };
+
+ /**
+ * @return {module:echarts/model/Global}
+ */
+ echartsProto.getModel = function () {
+ return this._model;
+ };
+
+ /**
+ * @return {Object}
+ */
+ echartsProto.getOption = function () {
+ return this._model && this._model.getOption();
+ };
+
+ /**
+ * @return {number}
+ */
+ echartsProto.getWidth = function () {
+ return this._zr.getWidth();
+ };
+
+ /**
+ * @return {number}
+ */
+ echartsProto.getHeight = function () {
+ return this._zr.getHeight();
+ };
+
+ /**
+ * @return {number}
+ */
+ echartsProto.getDevicePixelRatio = function () {
+ return this._zr.painter.dpr || window.devicePixelRatio || 1;
+ };
+
+ /**
+ * Get canvas which has all thing rendered
+ * @param {Object} opts
+ * @param {string} [opts.backgroundColor]
+ */
+ echartsProto.getRenderedCanvas = function (opts) {
+ if (!env.canvasSupported) {
+ return;
+ }
+ opts = opts || {};
+ opts.pixelRatio = opts.pixelRatio || 1;
+ opts.backgroundColor = opts.backgroundColor
+ || this._model.get('backgroundColor');
+ var zr = this._zr;
+ var list = zr.storage.getDisplayList();
+ // Stop animations
+ zrUtil.each(list, function (el) {
+ el.stopAnimation(true);
+ });
+ return zr.painter.getRenderedCanvas(opts);
+ };
+ /**
+ * @return {string}
+ * @param {Object} opts
+ * @param {string} [opts.type='png']
+ * @param {string} [opts.pixelRatio=1]
+ * @param {string} [opts.backgroundColor]
+ * @param {string} [opts.excludeComponents]
+ */
+ echartsProto.getDataURL = function (opts) {
+ opts = opts || {};
+ var excludeComponents = opts.excludeComponents;
+ var ecModel = this._model;
+ var excludesComponentViews = [];
+ var self = this;
+
+ each(excludeComponents, function (componentType) {
+ ecModel.eachComponent({
+ mainType: componentType
+ }, function (component) {
+ var view = self._componentsMap[component.__viewId];
+ if (!view.group.ignore) {
+ excludesComponentViews.push(view);
+ view.group.ignore = true;
+ }
+ });
+ });
+
+ var url = this.getRenderedCanvas(opts).toDataURL(
+ 'image/' + (opts && opts.type || 'png')
+ );
+
+ each(excludesComponentViews, function (view) {
+ view.group.ignore = false;
+ });
+ return url;
+ };
+
+
+ /**
+ * @return {string}
+ * @param {Object} opts
+ * @param {string} [opts.type='png']
+ * @param {string} [opts.pixelRatio=1]
+ * @param {string} [opts.backgroundColor]
+ */
+ echartsProto.getConnectedDataURL = function (opts) {
+ if (!env.canvasSupported) {
+ return;
+ }
+ var groupId = this.group;
+ var mathMin = Math.min;
+ var mathMax = Math.max;
+ var MAX_NUMBER = Infinity;
+ if (connectedGroups[groupId]) {
+ var left = MAX_NUMBER;
+ var top = MAX_NUMBER;
+ var right = -MAX_NUMBER;
+ var bottom = -MAX_NUMBER;
+ var canvasList = [];
+ var dpr = (opts && opts.pixelRatio) || 1;
+
+ zrUtil.each(instances, function (chart, id) {
+ if (chart.group === groupId) {
+ var canvas = chart.getRenderedCanvas(
+ zrUtil.clone(opts)
+ );
+ var boundingRect = chart.getDom().getBoundingClientRect();
+ left = mathMin(boundingRect.left, left);
+ top = mathMin(boundingRect.top, top);
+ right = mathMax(boundingRect.right, right);
+ bottom = mathMax(boundingRect.bottom, bottom);
+ canvasList.push({
+ dom: canvas,
+ left: boundingRect.left,
+ top: boundingRect.top
+ });
+ }
+ });
+
+ left *= dpr;
+ top *= dpr;
+ right *= dpr;
+ bottom *= dpr;
+ var width = right - left;
+ var height = bottom - top;
+ var targetCanvas = zrUtil.createCanvas();
+ targetCanvas.width = width;
+ targetCanvas.height = height;
+ var zr = zrender.init(targetCanvas);
+
+ each(canvasList, function (item) {
+ var img = new graphic.Image({
+ style: {
+ x: item.left * dpr - left,
+ y: item.top * dpr - top,
+ image: item.dom
+ }
+ });
+ zr.add(img);
+ });
+ zr.refreshImmediately();
+
+ return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
+ }
+ else {
+ return this.getDataURL(opts);
+ }
+ };
+
+ /**
+ * Convert from logical coordinate system to pixel coordinate system.
+ * See CoordinateSystem#convertToPixel.
+ * @param {string|Object} finder
+ * If string, e.g., 'geo', means {geoIndex: 0}.
+ * If Object, could contain some of these properties below:
+ * {
+ * seriesIndex / seriesId / seriesName,
+ * geoIndex / geoId, geoName,
+ * bmapIndex / bmapId / bmapName,
+ * xAxisIndex / xAxisId / xAxisName,
+ * yAxisIndex / yAxisId / yAxisName,
+ * gridIndex / gridId / gridName,
+ * ... (can be extended)
+ * }
+ * @param {Array|number} value
+ * @return {Array|number} result
+ */
+ echartsProto.convertToPixel = zrUtil.curry(doConvertPixel, 'convertToPixel');
+
+ /**
+ * Convert from pixel coordinate system to logical coordinate system.
+ * See CoordinateSystem#convertFromPixel.
+ * @param {string|Object} finder
+ * If string, e.g., 'geo', means {geoIndex: 0}.
+ * If Object, could contain some of these properties below:
+ * {
+ * seriesIndex / seriesId / seriesName,
+ * geoIndex / geoId / geoName,
+ * bmapIndex / bmapId / bmapName,
+ * xAxisIndex / xAxisId / xAxisName,
+ * yAxisIndex / yAxisId / yAxisName
+ * gridIndex / gridId / gridName,
+ * ... (can be extended)
+ * }
+ * @param {Array|number} value
+ * @return {Array|number} result
+ */
+ echartsProto.convertFromPixel = zrUtil.curry(doConvertPixel, 'convertFromPixel');
+
+ function doConvertPixel(methodName, finder, value) {
+ var ecModel = this._model;
+ var coordSysList = this._coordSysMgr.getCoordinateSystems();
+ var result;
+
+ finder = modelUtil.parseFinder(ecModel, finder);
+
+ for (var i = 0; i < coordSysList.length; i++) {
+ var coordSys = coordSysList[i];
+ if (coordSys[methodName]
+ && (result = coordSys[methodName](ecModel, finder, value)) != null
+ ) {
+ return result;
+ }
+ }
+
+ if (true) {
+ console.warn(
+ 'No coordinate system that supports ' + methodName + ' found by the given finder.'
+ );
+ }
+ }
+
+ /**
+ * Is the specified coordinate systems or components contain the given pixel point.
+ * @param {string|Object} finder
+ * If string, e.g., 'geo', means {geoIndex: 0}.
+ * If Object, could contain some of these properties below:
+ * {
+ * seriesIndex / seriesId / seriesName,
+ * geoIndex / geoId / geoName,
+ * bmapIndex / bmapId / bmapName,
+ * xAxisIndex / xAxisId / xAxisName,
+ * yAxisIndex / yAxisId / yAxisName,
+ * gridIndex / gridId / gridName,
+ * ... (can be extended)
+ * }
+ * @param {Array|number} value
+ * @return {boolean} result
+ */
+ echartsProto.containPixel = function (finder, value) {
+ var ecModel = this._model;
+ var result;
+
+ finder = modelUtil.parseFinder(ecModel, finder);
+
+ zrUtil.each(finder, function (models, key) {
+ key.indexOf('Models') >= 0 && zrUtil.each(models, function (model) {
+ var coordSys = model.coordinateSystem;
+ if (coordSys && coordSys.containPoint) {
+ result |= !!coordSys.containPoint(value);
+ }
+ else if (key === 'seriesModels') {
+ var view = this._chartsMap[model.__viewId];
+ if (view && view.containPoint) {
+ result |= view.containPoint(value, model);
+ }
+ else {
+ if (true) {
+ console.warn(key + ': ' + (view
+ ? 'The found component do not support containPoint.'
+ : 'No view mapping to the found component.'
+ ));
+ }
+ }
+ }
+ else {
+ if (true) {
+ console.warn(key + ': containPoint is not supported');
+ }
+ }
+ }, this);
+ }, this);
+
+ return !!result;
+ };
+
+ /**
+ * Get visual from series or data.
+ * @param {string|Object} finder
+ * If string, e.g., 'series', means {seriesIndex: 0}.
+ * If Object, could contain some of these properties below:
+ * {
+ * seriesIndex / seriesId / seriesName,
+ * dataIndex / dataIndexInside
+ * }
+ * If dataIndex is not specified, series visual will be fetched,
+ * but not data item visual.
+ * If all of seriesIndex, seriesId, seriesName are not specified,
+ * visual will be fetched from first series.
+ * @param {string} visualType 'color', 'symbol', 'symbolSize'
+ */
+ echartsProto.getVisual = function (finder, visualType) {
+ var ecModel = this._model;
+
+ finder = modelUtil.parseFinder(ecModel, finder, {defaultMainType: 'series'});
+
+ var seriesModel = finder.seriesModel;
+
+ if (true) {
+ if (!seriesModel) {
+ console.warn('There is no specified seires model');
+ }
+ }
+
+ var data = seriesModel.getData();
+
+ var dataIndexInside = finder.hasOwnProperty('dataIndexInside')
+ ? finder.dataIndexInside
+ : finder.hasOwnProperty('dataIndex')
+ ? data.indexOfRawIndex(finder.dataIndex)
+ : null;
+
+ return dataIndexInside != null
+ ? data.getItemVisual(dataIndexInside, visualType)
+ : data.getVisual(visualType);
+ };
+
+ /**
+ * Get view of corresponding component model
+ * @param {module:echarts/model/Component} componentModel
+ * @return {module:echarts/view/Component}
+ */
+ echartsProto.getViewOfComponentModel = function (componentModel) {
+ return this._componentsMap[componentModel.__viewId];
+ };
+
+ /**
+ * Get view of corresponding series model
+ * @param {module:echarts/model/Series} seriesModel
+ * @return {module:echarts/view/Chart}
+ */
+ echartsProto.getViewOfSeriesModel = function (seriesModel) {
+ return this._chartsMap[seriesModel.__viewId];
+ };
+
+
+ var updateMethods = {
+
+ /**
+ * @param {Object} payload
+ * @private
+ */
+ update: function (payload) {
+ // console.profile && console.profile('update');
+
+ var ecModel = this._model;
+ var api = this._api;
+ var coordSysMgr = this._coordSysMgr;
+ var zr = this._zr;
+ // update before setOption
+ if (!ecModel) {
+ return;
+ }
+
+ // Fixme First time update ?
+ ecModel.restoreData();
+
+ // TODO
+ // Save total ecModel here for undo/redo (after restoring data and before processing data).
+ // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
+
+ // Create new coordinate system each update
+ // In LineView may save the old coordinate system and use it to get the orignal point
+ coordSysMgr.create(this._model, this._api);
+
+ processData.call(this, ecModel, api);
+
+ stackSeriesData.call(this, ecModel);
+
+ coordSysMgr.update(ecModel, api);
+
+ doVisualEncoding.call(this, ecModel, payload);
+
+ doRender.call(this, ecModel, payload);
+
+ // Set background
+ var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
+
+ var painter = zr.painter;
+ // TODO all use clearColor ?
+ if (painter.isSingleCanvas && painter.isSingleCanvas()) {
+ zr.configLayer(0, {
+ clearColor: backgroundColor
+ });
+ }
+ else {
+ // In IE8
+ if (!env.canvasSupported) {
+ var colorArr = colorTool.parse(backgroundColor);
+ backgroundColor = colorTool.stringify(colorArr, 'rgb');
+ if (colorArr[3] === 0) {
+ backgroundColor = 'transparent';
+ }
+ }
+ if (backgroundColor.colorStops || backgroundColor.image) {
+ // Gradient background
+ // FIXME Fixed layer?
+ zr.configLayer(0, {
+ clearColor: backgroundColor
+ });
+ this[HAS_GRADIENT_OR_PATTERN_BG] = true;
+
+ this._dom.style.background = 'transparent';
+ }
+ else {
+ if (this[HAS_GRADIENT_OR_PATTERN_BG]) {
+ zr.configLayer(0, {
+ clearColor: null
+ });
+ }
+ this[HAS_GRADIENT_OR_PATTERN_BG] = false;
+
+ this._dom.style.background = backgroundColor;
+ }
+ }
+
+ each(postUpdateFuncs, function (func) {
+ func(ecModel, api);
+ });
+
+ // console.profile && console.profileEnd('update');
+ },
+
+ /**
+ * @param {Object} payload
+ * @private
+ */
+ updateView: function (payload) {
+ var ecModel = this._model;
+
+ // update before setOption
+ if (!ecModel) {
+ return;
+ }
+
+ ecModel.eachSeries(function (seriesModel) {
+ seriesModel.getData().clearAllVisual();
+ });
+
+ doVisualEncoding.call(this, ecModel, payload);
+
+ invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
+ },
+
+ /**
+ * @param {Object} payload
+ * @private
+ */
+ updateVisual: function (payload) {
+ var ecModel = this._model;
+
+ // update before setOption
+ if (!ecModel) {
+ return;
+ }
+
+ ecModel.eachSeries(function (seriesModel) {
+ seriesModel.getData().clearAllVisual();
+ });
+
+ doVisualEncoding.call(this, ecModel, payload, true);
+
+ invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
+ },
+
+ /**
+ * @param {Object} payload
+ * @private
+ */
+ updateLayout: function (payload) {
+ var ecModel = this._model;
+
+ // update before setOption
+ if (!ecModel) {
+ return;
+ }
+
+ doLayout.call(this, ecModel, payload);
+
+ invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
+ },
+
+ /**
+ * @param {Object} payload
+ * @private
+ */
+ prepareAndUpdate: function (payload) {
+ var ecModel = this._model;
+
+ prepareView.call(this, 'component', ecModel);
+
+ prepareView.call(this, 'chart', ecModel);
+
+ updateMethods.update.call(this, payload);
+ }
+ };
+
+ /**
+ * @private
+ */
+ function updateDirectly(ecIns, method, payload, mainType, subType) {
+ var ecModel = ecIns._model;
+
+ // broadcast
+ if (!mainType) {
+ each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);
+ return;
+ }
+
+ var query = {};
+ query[mainType + 'Id'] = payload[mainType + 'Id'];
+ query[mainType + 'Index'] = payload[mainType + 'Index'];
+ query[mainType + 'Name'] = payload[mainType + 'Name'];
+
+ var condition = {mainType: mainType, query: query};
+ subType && (condition.subType = subType); // subType may be '' by parseClassType;
+
+ // If dispatchAction before setOption, do nothing.
+ ecModel && ecModel.eachComponent(condition, function (model, index) {
+ callView(ecIns[
+ mainType === 'series' ? '_chartsMap' : '_componentsMap'
+ ][model.__viewId]);
+ }, ecIns);
+
+ function callView(view) {
+ view && view.__alive && view[method] && view[method](
+ view.__model, ecModel, ecIns._api, payload
+ );
+ }
+ }
+
+ /**
+ * Resize the chart
+ * @param {Object} opts
+ * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)
+ * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)
+ * @param {boolean} [opts.silent=false]
+ */
+ echartsProto.resize = function (opts) {
+ if (true) {
+ zrUtil.assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');
+ }
+
+ this[IN_MAIN_PROCESS] = true;
+
+ this._zr.resize(opts);
+
+ var optionChanged = this._model && this._model.resetOption('media');
+ var updateMethod = optionChanged ? 'prepareAndUpdate' : 'update';
+
+ updateMethods[updateMethod].call(this);
+
+ // Resize loading effect
+ this._loadingFX && this._loadingFX.resize();
+
+ this[IN_MAIN_PROCESS] = false;
+
+ var silent = opts && opts.silent;
+
+ flushPendingActions.call(this, silent);
+
+ triggerUpdatedEvent.call(this, silent);
+ };
+
+ /**
+ * Show loading effect
+ * @param {string} [name='default']
+ * @param {Object} [cfg]
+ */
+ echartsProto.showLoading = function (name, cfg) {
+ if (zrUtil.isObject(name)) {
+ cfg = name;
+ name = '';
+ }
+ name = name || 'default';
+
+ this.hideLoading();
+ if (!loadingEffects[name]) {
+ if (true) {
+ console.warn('Loading effects ' + name + ' not exists.');
+ }
+ return;
+ }
+ var el = loadingEffects[name](this._api, cfg);
+ var zr = this._zr;
+ this._loadingFX = el;
+
+ zr.add(el);
+ };
+
+ /**
+ * Hide loading effect
+ */
+ echartsProto.hideLoading = function () {
+ this._loadingFX && this._zr.remove(this._loadingFX);
+ this._loadingFX = null;
+ };
+
+ /**
+ * @param {Object} eventObj
+ * @return {Object}
+ */
+ echartsProto.makeActionFromEvent = function (eventObj) {
+ var payload = zrUtil.extend({}, eventObj);
+ payload.type = eventActionMap[eventObj.type];
+ return payload;
+ };
+
+ /**
+ * @pubilc
+ * @param {Object} payload
+ * @param {string} [payload.type] Action type
+ * @param {Object|boolean} [opt] If pass boolean, means opt.silent
+ * @param {boolean} [opt.silent=false] Whether trigger events.
+ * @param {boolean} [opt.flush=undefined]
+ * true: Flush immediately, and then pixel in canvas can be fetched
+ * immediately. Caution: it might affect performance.
+ * false: Not not flush.
+ * undefined: Auto decide whether perform flush.
+ */
+ echartsProto.dispatchAction = function (payload, opt) {
+ if (!zrUtil.isObject(opt)) {
+ opt = {silent: !!opt};
+ }
+
+ if (!actions[payload.type]) {
+ return;
+ }
+
+ // May dispatchAction in rendering procedure
+ if (this[IN_MAIN_PROCESS]) {
+ this._pendingActions.push(payload);
+ return;
+ }
+
+ doDispatchAction.call(this, payload, opt.silent);
+
+ if (opt.flush) {
+ this._zr.flush(true);
+ }
+ else if (opt.flush !== false && env.browser.weChat) {
+ // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`
+ // hang when sliding page (on touch event), which cause that zr does not
+ // refresh util user interaction finished, which is not expected.
+ // But `dispatchAction` may be called too frequently when pan on touch
+ // screen, which impacts performance if do not throttle them.
+ this._throttledZrFlush();
+ }
+
+ flushPendingActions.call(this, opt.silent);
+
+ triggerUpdatedEvent.call(this, opt.silent);
+ };
+
+ function doDispatchAction(payload, silent) {
+ var payloadType = payload.type;
+ var escapeConnect = payload.escapeConnect;
+ var actionWrap = actions[payloadType];
+ var actionInfo = actionWrap.actionInfo;
+
+ var cptType = (actionInfo.update || 'update').split(':');
+ var updateMethod = cptType.pop();
+ cptType = cptType[0] != null && parseClassType(cptType[0]);
+
+ this[IN_MAIN_PROCESS] = true;
+
+ var payloads = [payload];
+ var batched = false;
+ // Batch action
+ if (payload.batch) {
+ batched = true;
+ payloads = zrUtil.map(payload.batch, function (item) {
+ item = zrUtil.defaults(zrUtil.extend({}, item), payload);
+ item.batch = null;
+ return item;
+ });
+ }
+
+ var eventObjBatch = [];
+ var eventObj;
+ var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';
+
+ each(payloads, function (batchItem) {
+ // Action can specify the event by return it.
+ eventObj = actionWrap.action(batchItem, this._model, this._api);
+ // Emit event outside
+ eventObj = eventObj || zrUtil.extend({}, batchItem);
+ // Convert type to eventType
+ eventObj.type = actionInfo.event || eventObj.type;
+ eventObjBatch.push(eventObj);
+
+ // light update does not perform data process, layout and visual.
+ if (isHighDown) {
+ // method, payload, mainType, subType
+ updateDirectly(this, updateMethod, batchItem, 'series');
+ }
+ else if (cptType) {
+ updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);
+ }
+ }, this);
+
+ if (updateMethod !== 'none' && !isHighDown && !cptType) {
+ // Still dirty
+ if (this[OPTION_UPDATED]) {
+ // FIXME Pass payload ?
+ updateMethods.prepareAndUpdate.call(this, payload);
+ this[OPTION_UPDATED] = false;
+ }
+ else {
+ updateMethods[updateMethod].call(this, payload);
+ }
+ }
+
+ // Follow the rule of action batch
+ if (batched) {
+ eventObj = {
+ type: actionInfo.event || payloadType,
+ escapeConnect: escapeConnect,
+ batch: eventObjBatch
+ };
+ }
+ else {
+ eventObj = eventObjBatch[0];
+ }
+
+ this[IN_MAIN_PROCESS] = false;
+
+ !silent && this._messageCenter.trigger(eventObj.type, eventObj);
+ }
+
+ function flushPendingActions(silent) {
+ var pendingActions = this._pendingActions;
+ while (pendingActions.length) {
+ var payload = pendingActions.shift();
+ doDispatchAction.call(this, payload, silent);
+ }
+ }
+
+ function triggerUpdatedEvent(silent) {
+ !silent && this.trigger('updated');
+ }
+
+ /**
+ * Register event
+ * @method
+ */
+ echartsProto.on = createRegisterEventWithLowercaseName('on');
+ echartsProto.off = createRegisterEventWithLowercaseName('off');
+ echartsProto.one = createRegisterEventWithLowercaseName('one');
+
+ /**
+ * @param {string} methodName
+ * @private
+ */
+ function invokeUpdateMethod(methodName, ecModel, payload) {
+ var api = this._api;
+
+ // Update all components
+ each(this._componentsViews, function (component) {
+ var componentModel = component.__model;
+ component[methodName](componentModel, ecModel, api, payload);
+
+ updateZ(componentModel, component);
+ }, this);
+
+ // Upate all charts
+ ecModel.eachSeries(function (seriesModel, idx) {
+ var chart = this._chartsMap[seriesModel.__viewId];
+ chart[methodName](seriesModel, ecModel, api, payload);
+
+ updateZ(seriesModel, chart);
+
+ updateProgressiveAndBlend(seriesModel, chart);
+ }, this);
+
+ // If use hover layer
+ updateHoverLayerStatus(this._zr, ecModel);
+
+ // Post render
+ each(postUpdateFuncs, function (func) {
+ func(ecModel, api);
+ });
+ }
+
+ /**
+ * Prepare view instances of charts and components
+ * @param {module:echarts/model/Global} ecModel
+ * @private
+ */
+ function prepareView(type, ecModel) {
+ var isComponent = type === 'component';
+ var viewList = isComponent ? this._componentsViews : this._chartsViews;
+ var viewMap = isComponent ? this._componentsMap : this._chartsMap;
+ var zr = this._zr;
+
+ for (var i = 0; i < viewList.length; i++) {
+ viewList[i].__alive = false;
+ }
+
+ ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) {
+ if (isComponent) {
+ if (componentType === 'series') {
+ return;
+ }
+ }
+ else {
+ model = componentType;
+ }
+
+ // Consider: id same and type changed.
+ var viewId = '_ec_' + model.id + '_' + model.type;
+ var view = viewMap[viewId];
+ if (!view) {
+ var classType = parseClassType(model.type);
+ var Clazz = isComponent
+ ? ComponentView.getClass(classType.main, classType.sub)
+ : ChartView.getClass(classType.sub);
+ if (Clazz) {
+ view = new Clazz();
+ view.init(ecModel, this._api);
+ viewMap[viewId] = view;
+ viewList.push(view);
+ zr.add(view.group);
+ }
+ else {
+ // Error
+ return;
+ }
+ }
+
+ model.__viewId = view.__id = viewId;
+ view.__alive = true;
+ view.__model = model;
+ view.group.__ecComponentInfo = {
+ mainType: model.mainType,
+ index: model.componentIndex
+ };
+ }, this);
+
+ for (var i = 0; i < viewList.length;) {
+ var view = viewList[i];
+ if (!view.__alive) {
+ zr.remove(view.group);
+ view.dispose(ecModel, this._api);
+ viewList.splice(i, 1);
+ delete viewMap[view.__id];
+ view.__id = view.group.__ecComponentInfo = null;
+ }
+ else {
+ i++;
+ }
+ }
+ }
+
+ /**
+ * Processor data in each series
+ *
+ * @param {module:echarts/model/Global} ecModel
+ * @private
+ */
+ function processData(ecModel, api) {
+ each(dataProcessorFuncs, function (process) {
+ process.func(ecModel, api);
+ });
+ }
+
+ /**
+ * @private
+ */
+ function stackSeriesData(ecModel) {
+ var stackedDataMap = {};
+ ecModel.eachSeries(function (series) {
+ var stack = series.get('stack');
+ var data = series.getData();
+ if (stack && data.type === 'list') {
+ var previousStack = stackedDataMap[stack];
+ // Avoid conflict with Object.prototype
+ if (stackedDataMap.hasOwnProperty(stack) && previousStack) {
+ data.stackedOn = previousStack;
+ }
+ stackedDataMap[stack] = data;
+ }
+ });
+ }
+
+ /**
+ * Layout before each chart render there series, special visual encoding stage
+ *
+ * @param {module:echarts/model/Global} ecModel
+ * @private
+ */
+ function doLayout(ecModel, payload) {
+ var api = this._api;
+ each(visualFuncs, function (visual) {
+ if (visual.isLayout) {
+ visual.func(ecModel, api, payload);
+ }
+ });
+ }
+
+ /**
+ * Encode visual infomation from data after data processing
+ *
+ * @param {module:echarts/model/Global} ecModel
+ * @param {object} layout
+ * @param {boolean} [excludesLayout]
+ * @private
+ */
+ function doVisualEncoding(ecModel, payload, excludesLayout) {
+ var api = this._api;
+ ecModel.clearColorPalette();
+ ecModel.eachSeries(function (seriesModel) {
+ seriesModel.clearColorPalette();
+ });
+ each(visualFuncs, function (visual) {
+ (!excludesLayout || !visual.isLayout)
+ && visual.func(ecModel, api, payload);
+ });
+ }
+
+ /**
+ * Render each chart and component
+ * @private
+ */
+ function doRender(ecModel, payload) {
+ var api = this._api;
+ // Render all components
+ each(this._componentsViews, function (componentView) {
+ var componentModel = componentView.__model;
+ componentView.render(componentModel, ecModel, api, payload);
+
+ updateZ(componentModel, componentView);
+ }, this);
+
+ each(this._chartsViews, function (chart) {
+ chart.__alive = false;
+ }, this);
+
+ // Render all charts
+ ecModel.eachSeries(function (seriesModel, idx) {
+ var chartView = this._chartsMap[seriesModel.__viewId];
+ chartView.__alive = true;
+ chartView.render(seriesModel, ecModel, api, payload);
+
+ chartView.group.silent = !!seriesModel.get('silent');
+
+ updateZ(seriesModel, chartView);
+
+ updateProgressiveAndBlend(seriesModel, chartView);
+
+ }, this);
+
+ // If use hover layer
+ updateHoverLayerStatus(this._zr, ecModel);
+
+ // Remove groups of unrendered charts
+ each(this._chartsViews, function (chart) {
+ if (!chart.__alive) {
+ chart.remove(ecModel, api);
+ }
+ }, this);
+ }
+
+ var MOUSE_EVENT_NAMES = [
+ 'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',
+ 'mousedown', 'mouseup', 'globalout', 'contextmenu'
+ ];
+ /**
+ * @private
+ */
+ echartsProto._initEvents = function () {
+ each(MOUSE_EVENT_NAMES, function (eveName) {
+ this._zr.on(eveName, function (e) {
+ var ecModel = this.getModel();
+ var el = e.target;
+ var params;
+
+ // no e.target when 'globalout'.
+ if (eveName === 'globalout') {
+ params = {};
+ }
+ else if (el && el.dataIndex != null) {
+
+ //**yukichange begin here made a params array as a result
+ if(el.selected&&eveName=="click"){
+ params = new Array();
+ for(var selectIndex=0;selectIndex ecModel.get('hoverLayerThreshold') && !env.node) {
+ storage.traverse(function (el) {
+ if (!el.isGroup) {
+ el.useHoverLayer = true;
+ }
+ });
+ }
+ }
+
+ /**
+ * Update chart progressive and blend.
+ * @param {module:echarts/model/Series|module:echarts/model/Component} model
+ * @param {module:echarts/view/Component|module:echarts/view/Chart} view
+ */
+ function updateProgressiveAndBlend(seriesModel, chartView) {
+ // Progressive configuration
+ var elCount = 0;
+ chartView.group.traverse(function (el) {
+ if (el.type !== 'group' && !el.ignore) {
+ elCount++;
+ }
+ });
+ var frameDrawNum = +seriesModel.get('progressive');
+ var needProgressive = elCount > seriesModel.get('progressiveThreshold') && frameDrawNum && !env.node;
+ if (needProgressive) {
+ chartView.group.traverse(function (el) {
+ // FIXME marker and other components
+ if (!el.isGroup) {
+ el.progressive = needProgressive ?
+ Math.floor(elCount++ / frameDrawNum) : -1;
+ if (needProgressive) {
+ el.stopAnimation(true);
+ }
+ }
+ });
+ }
+
+ // Blend configration
+ var blendMode = seriesModel.get('blendMode') || null;
+ if (true) {
+ if (!env.canvasSupported && blendMode && blendMode !== 'source-over') {
+ console.warn('Only canvas support blendMode');
+ }
+ }
+ chartView.group.traverse(function (el) {
+ // FIXME marker and other components
+ if (!el.isGroup) {
+ el.setStyle('blend', blendMode);
+ }
+ });
+ }
+
+ /**
+ * @param {module:echarts/model/Series|module:echarts/model/Component} model
+ * @param {module:echarts/view/Component|module:echarts/view/Chart} view
+ */
+ function updateZ(model, view) {
+ var z = model.get('z');
+ var zlevel = model.get('zlevel');
+ // Set z and zlevel
+ view.group.traverse(function (el) {
+ if (el.type !== 'group') {
+ z != null && (el.z = z);
+ zlevel != null && (el.zlevel = zlevel);
+ }
+ });
+ }
+
+ function createExtensionAPI(ecInstance) {
+ var coordSysMgr = ecInstance._coordSysMgr;
+ return zrUtil.extend(new ExtensionAPI(ecInstance), {
+ // Inject methods
+ getCoordinateSystems: zrUtil.bind(
+ coordSysMgr.getCoordinateSystems, coordSysMgr
+ ),
+ getComponentByElement: function (el) {
+ while (el) {
+ var modelInfo = el.__ecComponentInfo;
+ if (modelInfo != null) {
+ return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);
+ }
+ el = el.parent;
+ }
+ }
+ });
+ }
+
+ /**
+ * @type {Object} key: actionType.
+ * @inner
+ */
+ var actions = {};
+
+ /**
+ * Map eventType to actionType
+ * @type {Object}
+ */
+ var eventActionMap = {};
+
+ /**
+ * Data processor functions of each stage
+ * @type {Array.>}
+ * @inner
+ */
+ var dataProcessorFuncs = [];
+
+ /**
+ * @type {Array.}
+ * @inner
+ */
+ var optionPreprocessorFuncs = [];
+
+ /**
+ * @type {Array.}
+ * @inner
+ */
+ var postUpdateFuncs = [];
+
+ /**
+ * Visual encoding functions of each stage
+ * @type {Array.>}
+ * @inner
+ */
+ var visualFuncs = [];
+ /**
+ * Theme storage
+ * @type {Object.}
+ */
+ var themeStorage = {};
+ /**
+ * Loading effects
+ */
+ var loadingEffects = {};
+
+
+ var instances = {};
+ var connectedGroups = {};
+
+ var idBase = new Date() - 0;
+ var groupIdBase = new Date() - 0;
+ var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
+
+ /**
+ * @alias module:echarts
+ */
+ var echarts = {
+ /**
+ * @type {number}
+ */
+ version: '3.6.2',
+ dependencies: {
+ zrender: '3.5.2'
+ }
+ };
+
+ function enableConnect(chart) {
+ var STATUS_PENDING = 0;
+ var STATUS_UPDATING = 1;
+ var STATUS_UPDATED = 2;
+ var STATUS_KEY = '__connectUpdateStatus';
+
+ function updateConnectedChartsStatus(charts, status) {
+ for (var i = 0; i < charts.length; i++) {
+ var otherChart = charts[i];
+ otherChart[STATUS_KEY] = status;
+ }
+ }
+
+ zrUtil.each(eventActionMap, function (actionType, eventType) {
+ chart._messageCenter.on(eventType, function (event) {
+ if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {
+ if (event && event.escapeConnect) {
+ return;
+ }
+
+ var action = chart.makeActionFromEvent(event);
+ var otherCharts = [];
+
+ zrUtil.each(instances, function (otherChart) {
+ if (otherChart !== chart && otherChart.group === chart.group) {
+ otherCharts.push(otherChart);
+ }
+ });
+
+ updateConnectedChartsStatus(otherCharts, STATUS_PENDING);
+ each(otherCharts, function (otherChart) {
+ if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {
+ otherChart.dispatchAction(action);
+ }
+ });
+ updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);
+ }
+ });
+ });
+ }
+
+ /**
+ * @param {HTMLDomElement} dom
+ * @param {Object} [theme]
+ * @param {Object} opts
+ * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default
+ * @param {string} [opts.renderer] Currently only 'canvas' is supported.
+ * @param {number} [opts.width] Use clientWidth of the input `dom` by default.
+ * Can be 'auto' (the same as null/undefined)
+ * @param {number} [opts.height] Use clientHeight of the input `dom` by default.
+ * Can be 'auto' (the same as null/undefined)
+ */
+ echarts.init = function (dom, theme, opts) {
+ if (true) {
+ // Check version
+ if ((zrender.version.replace('.', '') - 0) < (echarts.dependencies.zrender.replace('.', '') - 0)) {
+ throw new Error(
+ 'ZRender ' + zrender.version
+ + ' is too old for ECharts ' + echarts.version
+ + '. Current version need ZRender '
+ + echarts.dependencies.zrender + '+'
+ );
+ }
+
+ if (!dom) {
+ throw new Error('Initialize failed: invalid dom.');
+ }
+ }
+
+ var existInstance = echarts.getInstanceByDom(dom);
+ if (existInstance) {
+ if (true) {
+ console.warn('There is a chart instance already initialized on the dom.');
+ }
+ return existInstance;
+ }
+
+ if (true) {
+ if (zrUtil.isDom(dom)
+ && dom.nodeName.toUpperCase() !== 'CANVAS'
+ && (
+ (!dom.clientWidth && (!opts || opts.width == null))
+ || (!dom.clientHeight && (!opts || opts.height == null))
+ )
+ ) {
+ console.warn('Can\'t get dom width or height');
+ }
+ }
+
+ var chart = new ECharts(dom, theme, opts);
+ chart.id = 'ec_' + idBase++;
+ instances[chart.id] = chart;
+
+ if (dom.setAttribute) {
+ dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id);
+ }
+ else {
+ dom[DOM_ATTRIBUTE_KEY] = chart.id;
+ }
+
+ enableConnect(chart);
+
+ return chart;
+ };
+
+ /**
+ * @return {string|Array.} groupId
+ */
+ echarts.connect = function (groupId) {
+ // Is array of charts
+ if (zrUtil.isArray(groupId)) {
+ var charts = groupId;
+ groupId = null;
+ // If any chart has group
+ zrUtil.each(charts, function (chart) {
+ if (chart.group != null) {
+ groupId = chart.group;
+ }
+ });
+ groupId = groupId || ('g_' + groupIdBase++);
+ zrUtil.each(charts, function (chart) {
+ chart.group = groupId;
+ });
+ }
+ connectedGroups[groupId] = true;
+ return groupId;
+ };
+
+ /**
+ * @DEPRECATED
+ * @return {string} groupId
+ */
+ echarts.disConnect = function (groupId) {
+ connectedGroups[groupId] = false;
+ };
+
+ /**
+ * @return {string} groupId
+ */
+ echarts.disconnect = echarts.disConnect;
+
+ /**
+ * Dispose a chart instance
+ * @param {module:echarts~ECharts|HTMLDomElement|string} chart
+ */
+ echarts.dispose = function (chart) {
+ if (typeof chart === 'string') {
+ chart = instances[chart];
+ }
+ else if (!(chart instanceof ECharts)){
+ // Try to treat as dom
+ chart = echarts.getInstanceByDom(chart);
+ }
+ if ((chart instanceof ECharts) && !chart.isDisposed()) {
+ chart.dispose();
+ }
+ };
+
+ /**
+ * @param {HTMLDomElement} dom
+ * @return {echarts~ECharts}
+ */
+ echarts.getInstanceByDom = function (dom) {
+ var key;
+ if (dom.getAttribute) {
+ key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
+ }
+ else {
+ key = dom[DOM_ATTRIBUTE_KEY];
+ }
+ return instances[key];
+ };
+
+ /**
+ * @param {string} key
+ * @return {echarts~ECharts}
+ */
+ echarts.getInstanceById = function (key) {
+ return instances[key];
+ };
+
+ /**
+ * Register theme
+ */
+ echarts.registerTheme = function (name, theme) {
+ themeStorage[name] = theme;
+ };
+
+ /**
+ * Register option preprocessor
+ * @param {Function} preprocessorFunc
+ */
+ echarts.registerPreprocessor = function (preprocessorFunc) {
+ optionPreprocessorFuncs.push(preprocessorFunc);
+ };
+
+ /**
+ * @param {number} [priority=1000]
+ * @param {Function} processorFunc
+ */
+ echarts.registerProcessor = function (priority, processorFunc) {
+ if (typeof priority === 'function') {
+ processorFunc = priority;
+ priority = PRIORITY_PROCESSOR_FILTER;
+ }
+ if (true) {
+ if (isNaN(priority)) {
+ throw new Error('Unkown processor priority');
+ }
+ }
+ dataProcessorFuncs.push({
+ prio: priority,
+ func: processorFunc
+ });
+ };
+
+ /**
+ * Register postUpdater
+ * @param {Function} postUpdateFunc
+ */
+ echarts.registerPostUpdate = function (postUpdateFunc) {
+ postUpdateFuncs.push(postUpdateFunc);
+ };
+
+ /**
+ * Usage:
+ * registerAction('someAction', 'someEvent', function () { ... });
+ * registerAction('someAction', function () { ... });
+ * registerAction(
+ * {type: 'someAction', event: 'someEvent', update: 'updateView'},
+ * function () { ... }
+ * );
+ *
+ * @param {(string|Object)} actionInfo
+ * @param {string} actionInfo.type
+ * @param {string} [actionInfo.event]
+ * @param {string} [actionInfo.update]
+ * @param {string} [eventName]
+ * @param {Function} action
+ */
+ echarts.registerAction = function (actionInfo, eventName, action) {
+ if (typeof eventName === 'function') {
+ action = eventName;
+ eventName = '';
+ }
+ var actionType = zrUtil.isObject(actionInfo)
+ ? actionInfo.type
+ : ([actionInfo, actionInfo = {
+ event: eventName
+ }][0]);
+
+ // Event name is all lowercase
+ actionInfo.event = (actionInfo.event || actionType).toLowerCase();
+ eventName = actionInfo.event;
+
+ // Validate action type and event name.
+ zrUtil.assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));
+
+ if (!actions[actionType]) {
+ actions[actionType] = {action: action, actionInfo: actionInfo};
+ }
+ eventActionMap[eventName] = actionType;
+ };
+
+ /**
+ * @param {string} type
+ * @param {*} CoordinateSystem
+ */
+ echarts.registerCoordinateSystem = function (type, CoordinateSystem) {
+ CoordinateSystemManager.register(type, CoordinateSystem);
+ };
+
+ /**
+ * Get dimensions of specified coordinate system.
+ * @param {string} type
+ * @return {Array.}
+ */
+ echarts.getCoordinateSystemDimensions = function (type) {
+ var coordSysCreator = CoordinateSystemManager.get(type);
+ if (coordSysCreator) {
+ return coordSysCreator.getDimensionsInfo
+ ? coordSysCreator.getDimensionsInfo()
+ : coordSysCreator.dimensions.slice();
+ }
+ };
+
+ /**
+ * Layout is a special stage of visual encoding
+ * Most visual encoding like color are common for different chart
+ * But each chart has it's own layout algorithm
+ *
+ * @param {number} [priority=1000]
+ * @param {Function} layoutFunc
+ */
+ echarts.registerLayout = function (priority, layoutFunc) {
+ if (typeof priority === 'function') {
+ layoutFunc = priority;
+ priority = PRIORITY_VISUAL_LAYOUT;
+ }
+ if (true) {
+ if (isNaN(priority)) {
+ throw new Error('Unkown layout priority');
+ }
+ }
+ visualFuncs.push({
+ prio: priority,
+ func: layoutFunc,
+ isLayout: true
+ });
+ };
+
+ /**
+ * @param {number} [priority=3000]
+ * @param {Function} visualFunc
+ */
+ echarts.registerVisual = function (priority, visualFunc) {
+ if (typeof priority === 'function') {
+ visualFunc = priority;
+ priority = PRIORITY_VISUAL_CHART;
+ }
+ if (true) {
+ if (isNaN(priority)) {
+ throw new Error('Unkown visual priority');
+ }
+ }
+ visualFuncs.push({
+ prio: priority,
+ func: visualFunc
+ });
+ };
+
+ /**
+ * @param {string} name
+ */
+ echarts.registerLoading = function (name, loadingFx) {
+ loadingEffects[name] = loadingFx;
+ };
+
+ /**
+ * @param {Object} opts
+ * @param {string} [superClass]
+ */
+ echarts.extendComponentModel = function (opts/*, superClass*/) {
+ // var Clazz = ComponentModel;
+ // if (superClass) {
+ // var classType = parseClassType(superClass);
+ // Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
+ // }
+ return ComponentModel.extend(opts);
+ };
+
+ /**
+ * @param {Object} opts
+ * @param {string} [superClass]
+ */
+ echarts.extendComponentView = function (opts/*, superClass*/) {
+ // var Clazz = ComponentView;
+ // if (superClass) {
+ // var classType = parseClassType(superClass);
+ // Clazz = ComponentView.getClass(classType.main, classType.sub, true);
+ // }
+ return ComponentView.extend(opts);
+ };
+
+ /**
+ * @param {Object} opts
+ * @param {string} [superClass]
+ */
+ echarts.extendSeriesModel = function (opts/*, superClass*/) {
+ // var Clazz = SeriesModel;
+ // if (superClass) {
+ // superClass = 'series.' + superClass.replace('series.', '');
+ // var classType = parseClassType(superClass);
+ // Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
+ // }
+ return SeriesModel.extend(opts);
+ };
+
+ /**
+ * @param {Object} opts
+ * @param {string} [superClass]
+ */
+ echarts.extendChartView = function (opts/*, superClass*/) {
+ // var Clazz = ChartView;
+ // if (superClass) {
+ // superClass = superClass.replace('series.', '');
+ // var classType = parseClassType(superClass);
+ // Clazz = ChartView.getClass(classType.main, true);
+ // }
+ return ChartView.extend(opts);
+ };
+
+ /**
+ * ZRender need a canvas context to do measureText.
+ * But in node environment canvas may be created by node-canvas.
+ * So we need to specify how to create a canvas instead of using document.createElement('canvas')
+ *
+ * Be careful of using it in the browser.
+ *
+ * @param {Function} creator
+ * @example
+ * var Canvas = require('canvas');
+ * var echarts = require('echarts');
+ * echarts.setCanvasCreator(function () {
+ * // Small size is enough.
+ * return new Canvas(32, 32);
+ * });
+ */
+ echarts.setCanvasCreator = function (creator) {
+ zrUtil.createCanvas = creator;
+ };
+
+ echarts.registerVisual(PRIORITY_VISUAL_GLOBAL, __webpack_require__(94));
+ echarts.registerPreprocessor(__webpack_require__(95));
+ echarts.registerLoading('default', __webpack_require__(97));
+
+ // Default action
+ echarts.registerAction({
+ type: 'highlight',
+ event: 'highlight',
+ update: 'highlight'
+ }, zrUtil.noop);
+ echarts.registerAction({
+ type: 'downplay',
+ event: 'downplay',
+ update: 'downplay'
+ }, zrUtil.noop);
+
+
+ // --------
+ // Exports
+ // --------
+ echarts.zrender = zrender;
+
+ echarts.List = __webpack_require__(98);
+ echarts.Model = __webpack_require__(12);
+
+ echarts.Axis = __webpack_require__(100);
+
+ echarts.graphic = __webpack_require__(18);
+ echarts.number = __webpack_require__(7);
+ echarts.format = __webpack_require__(6);
+ echarts.throttle = throttle.throttle;
+ echarts.matrix = __webpack_require__(11);
+ echarts.vector = __webpack_require__(10);
+ echarts.color = __webpack_require__(31);
+
+ echarts.util = {};
+ each([
+ 'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',
+ 'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',
+ 'extend', 'defaults', 'clone', 'merge'
+ ],
+ function (name) {
+ echarts.util[name] = zrUtil[name];
+ }
+ );
+
+ echarts.helper = __webpack_require__(108);
+
+
+ // PRIORITY
+ echarts.PRIORITY = {
+ PROCESSOR: {
+ FILTER: PRIORITY_PROCESSOR_FILTER,
+ STATISTIC: PRIORITY_PROCESSOR_STATISTIC
+ },
+ VISUAL: {
+ LAYOUT: PRIORITY_VISUAL_LAYOUT,
+ GLOBAL: PRIORITY_VISUAL_GLOBAL,
+ CHART: PRIORITY_VISUAL_CHART,
+ COMPONENT: PRIORITY_VISUAL_COMPONENT,
+ BRUSH: PRIORITY_VISUAL_BRUSH
+ }
+ };
+
+ module.exports = echarts;
+
+
+/***/ },
+/* 2 */
+/***/ function(module, exports) {
+
+ /**
+ * echarts设备环境识别
+ *
+ * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
+ * @author firede[firede@firede.us]
+ * @desc thanks zepto.
+ */
+
+ var env = {};
+ if (typeof navigator === 'undefined') {
+ // In node
+ env = {
+ browser: {},
+ os: {},
+ node: true,
+ // Assume canvas is supported
+ canvasSupported: true
+ };
+ }
+ else {
+ env = detect(navigator.userAgent);
+ }
+
+ module.exports = env;
+
+ // Zepto.js
+ // (c) 2010-2013 Thomas Fuchs
+ // Zepto.js may be freely distributed under the MIT license.
+
+ function detect(ua) {
+ var os = {};
+ var browser = {};
+ // var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/);
+ // var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
+ // var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
+ // var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
+ // var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
+ // var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/);
+ // var touchpad = webos && ua.match(/TouchPad/);
+ // var kindle = ua.match(/Kindle\/([\d.]+)/);
+ // var silk = ua.match(/Silk\/([\d._]+)/);
+ // var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/);
+ // var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/);
+ // var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/);
+ // var playbook = ua.match(/PlayBook/);
+ // var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/);
+ var firefox = ua.match(/Firefox\/([\d.]+)/);
+ // var safari = webkit && ua.match(/Mobile\//) && !chrome;
+ // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;
+ var ie = ua.match(/MSIE\s([\d.]+)/)
+ // IE 11 Trident/7.0; rv:11.0
+ || ua.match(/Trident\/.+?rv:(([\d.]+))/);
+ var edge = ua.match(/Edge\/([\d.]+)/); // IE 12 and 12+
+
+ var weChat = (/micromessenger/i).test(ua);
+
+ // Todo: clean this up with a better OS/browser seperation:
+ // - discern (more) between multiple browsers on android
+ // - decide if kindle fire in silk mode is android or not
+ // - Firefox on Android doesn't specify the Android version
+ // - possibly devide in os, device and browser hashes
+
+ // if (browser.webkit = !!webkit) browser.version = webkit[1];
+
+ // if (android) os.android = true, os.version = android[2];
+ // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');
+ // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');
+ // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
+ // if (webos) os.webos = true, os.version = webos[2];
+ // if (touchpad) os.touchpad = true;
+ // if (blackberry) os.blackberry = true, os.version = blackberry[2];
+ // if (bb10) os.bb10 = true, os.version = bb10[2];
+ // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];
+ // if (playbook) browser.playbook = true;
+ // if (kindle) os.kindle = true, os.version = kindle[1];
+ // if (silk) browser.silk = true, browser.version = silk[1];
+ // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;
+ // if (chrome) browser.chrome = true, browser.version = chrome[1];
+ if (firefox) {
+ browser.firefox = true;
+ browser.version = firefox[1];
+ }
+ // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;
+ // if (webview) browser.webview = true;
+
+ if (ie) {
+ browser.ie = true;
+ browser.version = ie[1];
+ }
+
+ if (edge) {
+ browser.edge = true;
+ browser.version = edge[1];
+ }
+
+ // It is difficult to detect WeChat in Win Phone precisely, because ua can
+ // not be set on win phone. So we do not consider Win Phone.
+ if (weChat) {
+ browser.weChat = true;
+ }
+
+ // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||
+ // (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));
+ // os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos ||
+ // (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) ||
+ // (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));
+
+ return {
+ browser: browser,
+ os: os,
+ node: false,
+ // 原生canvas支持,改极端点了
+ // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)
+ canvasSupported : document.createElement('canvas').getContext ? true : false,
+ // @see
+ // works on most browsers
+ // IE10/11 does not support touch event, and MS Edge supports them but not by
+ // default, so we dont check navigator.maxTouchPoints for them here.
+ touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,
+ // .
+ pointerEventsSupported: 'onpointerdown' in window
+ // Firefox supports pointer but not by default, only MS browsers are reliable on pointer
+ // events currently. So we dont use that on other browsers unless tested sufficiently.
+ // Although IE 10 supports pointer event, it use old style and is different from the
+ // standard. So we exclude that. (IE 10 is hardly used on touch device)
+ && (browser.edge || (browser.ie && browser.version >= 11))
+ };
+ }
+
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * ECharts global model
+ *
+ * @module {echarts/model/Global}
+ */
+
+
+
+ /**
+ * Caution: If the mechanism should be changed some day, these cases
+ * should be considered:
+ *
+ * (1) In `merge option` mode, if using the same option to call `setOption`
+ * many times, the result should be the same (try our best to ensure that).
+ * (2) In `merge option` mode, if a component has no id/name specified, it
+ * will be merged by index, and the result sequence of the components is
+ * consistent to the original sequence.
+ * (3) `reset` feature (in toolbox). Find detailed info in comments about
+ * `mergeOption` in module:echarts/model/OptionManager.
+ */
+
+ var zrUtil = __webpack_require__(4);
+ var modelUtil = __webpack_require__(5);
+ var Model = __webpack_require__(12);
+ var each = zrUtil.each;
+ var filter = zrUtil.filter;
+ var map = zrUtil.map;
+ var isArray = zrUtil.isArray;
+ var indexOf = zrUtil.indexOf;
+ var isObject = zrUtil.isObject;
+
+ var ComponentModel = __webpack_require__(69);
+
+ var globalDefault = __webpack_require__(73);
+
+ var OPTION_INNER_KEY = '\0_ec_inner';
+
+ /**
+ * @alias module:echarts/model/Global
+ *
+ * @param {Object} option
+ * @param {module:echarts/model/Model} parentModel
+ * @param {Object} theme
+ */
+ var GlobalModel = Model.extend({
+
+ constructor: GlobalModel,
+
+ init: function (option, parentModel, theme, optionManager) {
+ theme = theme || {};
+
+ this.option = null; // Mark as not initialized.
+
+ /**
+ * @type {module:echarts/model/Model}
+ * @private
+ */
+ this._theme = new Model(theme);
+
+ /**
+ * @type {module:echarts/model/OptionManager}
+ */
+ this._optionManager = optionManager;
+ },
+
+ setOption: function (option, optionPreprocessorFuncs) {
+ zrUtil.assert(
+ !(OPTION_INNER_KEY in option),
+ 'please use chart.getOption()'
+ );
+ //**yuki lebal** here to the first step;
+ this._optionManager.setOption(option, optionPreprocessorFuncs);
+
+ this.resetOption(null);
+ },
+
+ /**
+ * @param {string} type null/undefined: reset all.
+ * 'recreate': force recreate all.
+ * 'timeline': only reset timeline option
+ * 'media': only reset media query option
+ * @return {boolean} Whether option changed.
+ */
+ resetOption: function (type) {
+ var optionChanged = false;
+ var optionManager = this._optionManager;
+
+ if (!type || type === 'recreate') {
+ var baseOption = optionManager.mountOption(type === 'recreate');
+
+ if (!this.option || type === 'recreate') {
+ initBase.call(this, baseOption);
+ }
+ else {
+ this.restoreData();
+ //**yuki**lebal
+ this.mergeOption(baseOption);
+ }
+ optionChanged = true;
+ }
+
+ if (type === 'timeline' || type === 'media') {
+ this.restoreData();
+ }
+
+ if (!type || type === 'recreate' || type === 'timeline') {
+ var timelineOption = optionManager.getTimelineOption(this);
+ timelineOption && (this.mergeOption(timelineOption), optionChanged = true);
+ }
+
+ if (!type || type === 'recreate' || type === 'media') {
+ var mediaOptions = optionManager.getMediaOption(this, this._api);
+ if (mediaOptions.length) {
+ each(mediaOptions, function (mediaOption) {
+ this.mergeOption(mediaOption, optionChanged = true);
+ }, this);
+ }
+ }
+
+ return optionChanged;
+ },
+
+ /**
+ * @protected
+ */
+ mergeOption: function (newOption) {
+ //**yuki**changed begin
+ //the second step set this.option.series to null;
+ this.option.series = [];
+ //**yuki**changed over
+ var option = this.option;
+ this._componentsMap._ec_series=[];
+ var componentsMap = this._componentsMap;
+ var newCptTypes = [];
+
+ // 如果不存在对应的 component model 则直接 merge
+ each(newOption, function (componentOption, mainType) {
+ if (componentOption == null) {
+ return;
+ }
+
+ if (!ComponentModel.hasClass(mainType)) {
+ //如果不存在对应的 component model 则直接 merge
+ {
+ option[mainType] = option[mainType] == null
+ ? zrUtil.clone(componentOption)
+ : zrUtil.merge(option[mainType], componentOption, true);
+ }
+ }
+ else {
+ newCptTypes.push(mainType);
+ }
+ });
+
+ // FIXME OPTION 同步是否要改回原来的
+ ComponentModel.topologicalTravel(
+ newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this
+ );
+ //**yuki**changed begin
+ this._seriesIndices = createSeriesIndices(componentsMap.get('series'));
+ //this._seriesIndices = this._seriesIndices || [];
+ //to fake a seriesIndeices
+ function visitComponent(mainType, dependencies) {
+ var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]);
+
+ var mapResult = modelUtil.mappingToExists(
+ componentsMap.get(mainType), newCptOptionList
+ );
+
+ modelUtil.makeIdAndName(mapResult);
+
+ // Set mainType and complete subType.
+ each(mapResult, function (item, index) {
+ var opt = item.option;
+ if (isObject(opt)) {
+ item.keyInfo.mainType = mainType;
+ item.keyInfo.subType = determineSubType(mainType, opt, item.exist);
+ }
+ });
+
+ var dependentModels = getComponentsByTypes(
+ componentsMap, dependencies
+ );
+
+ option[mainType] = [];
+ componentsMap.set(mainType, []);
+
+ each(mapResult, function (resultItem, index) {
+ var componentModel = resultItem.exist;
+ var newCptOption = resultItem.option;
+
+ zrUtil.assert(
+ isObject(newCptOption) || componentModel,
+ 'Empty component definition'
+ );
+
+ // Consider where is no new option and should be merged using {},
+ // see removeEdgeAndAdd in topologicalTravel and
+ // ComponentModel.getAllClassMainTypes.
+ if (!newCptOption) {
+ componentModel.mergeOption({}, this);
+ componentModel.optionUpdated({}, false);
+ }
+ else {
+ var ComponentModelClass = ComponentModel.getClass(
+ mainType, resultItem.keyInfo.subType, true
+ );
+
+ if (componentModel && componentModel instanceof ComponentModelClass) {
+ componentModel.name = resultItem.keyInfo.name;
+ componentModel.mergeOption(newCptOption, this);
+ componentModel.optionUpdated(newCptOption, false);
+ }
+ else {
+ // PENDING Global as parent ?
+ var extraOpt = zrUtil.extend(
+ {
+ dependentModels: dependentModels,
+ componentIndex: index
+ },
+ resultItem.keyInfo
+ );
+ componentModel = new ComponentModelClass(
+ newCptOption, this, this, extraOpt
+ );
+ zrUtil.extend(componentModel, extraOpt);
+ componentModel.init(newCptOption, this, this, extraOpt);
+ // Call optionUpdated after init.
+ // newCptOption has been used as componentModel.option
+ // and may be merged with theme and default, so pass null
+ // to avoid confusion.
+ componentModel.optionUpdated(null, true);
+ }
+ }
+
+ componentsMap.get(mainType)[index] = componentModel;
+ option[mainType][index] = componentModel.option;
+ }, this);
+
+ // Backup series for filtering.
+ if (mainType === 'series') {
+ this._seriesIndices = createSeriesIndices(componentsMap.get('series'));
+ }
+ }
+ },
+
+ /**
+ * Get option for output (cloned option and inner info removed)
+ * @public
+ * @return {Object}
+ */
+ getOption: function () {
+ var option = zrUtil.clone(this.option);
+
+ each(option, function (opts, mainType) {
+ if (ComponentModel.hasClass(mainType)) {
+ var opts = modelUtil.normalizeToArray(opts);
+ for (var i = opts.length - 1; i >= 0; i--) {
+ // Remove options with inner id.
+ if (modelUtil.isIdInner(opts[i])) {
+ opts.splice(i, 1);
+ }
+ }
+ option[mainType] = opts;
+ }
+ });
+
+ delete option[OPTION_INNER_KEY];
+
+ return option;
+ },
+
+ /**
+ * @return {module:echarts/model/Model}
+ */
+ getTheme: function () {
+ return this._theme;
+ },
+
+ /**
+ * @param {string} mainType
+ * @param {number} [idx=0]
+ * @return {module:echarts/model/Component}
+ */
+ getComponent: function (mainType, idx) {
+ var list = this._componentsMap.get(mainType);
+ if (list) {
+ return list[idx || 0];
+ }
+ },
+
+ /**
+ * If none of index and id and name used, return all components with mainType.
+ * @param {Object} condition
+ * @param {string} condition.mainType
+ * @param {string} [condition.subType] If ignore, only query by mainType
+ * @param {number|Array.} [condition.index] Either input index or id or name.
+ * @param {string|Array.} [condition.id] Either input index or id or name.
+ * @param {string|Array.} [condition.name] Either input index or id or name.
+ * @return {Array.}
+ */
+ queryComponents: function (condition) {
+ var mainType = condition.mainType;
+ if (!mainType) {
+ return [];
+ }
+
+ var index = condition.index;
+ var id = condition.id;
+ var name = condition.name;
+
+ var cpts = this._componentsMap.get(mainType);
+
+ if (!cpts || !cpts.length) {
+ return [];
+ }
+
+ var result;
+
+ if (index != null) {
+ if (!isArray(index)) {
+ index = [index];
+ }
+ result = filter(map(index, function (idx) {
+ return cpts[idx];
+ }), function (val) {
+ return !!val;
+ });
+ }
+ else if (id != null) {
+ var isIdArray = isArray(id);
+ result = filter(cpts, function (cpt) {
+ return (isIdArray && indexOf(id, cpt.id) >= 0)
+ || (!isIdArray && cpt.id === id);
+ });
+ }
+ else if (name != null) {
+ var isNameArray = isArray(name);
+ result = filter(cpts, function (cpt) {
+ return (isNameArray && indexOf(name, cpt.name) >= 0)
+ || (!isNameArray && cpt.name === name);
+ });
+ }
+ else {
+ // Return all components with mainType
+ result = cpts.slice();
+ }
+
+ return filterBySubType(result, condition);
+ },
+
+ /**
+ * The interface is different from queryComponents,
+ * which is convenient for inner usage.
+ *
+ * @usage
+ * var result = findComponents(
+ * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}
+ * );
+ * var result = findComponents(
+ * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}
+ * );
+ * var result = findComponents(
+ * {mainType: 'series'},
+ * function (model, index) {...}
+ * );
+ * // result like [component0, componnet1, ...]
+ *
+ * @param {Object} condition
+ * @param {string} condition.mainType Mandatory.
+ * @param {string} [condition.subType] Optional.
+ * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},
+ * where xxx is mainType.
+ * If query attribute is null/undefined or has no index/id/name,
+ * do not filtering by query conditions, which is convenient for
+ * no-payload situations or when target of action is global.
+ * @param {Function} [condition.filter] parameter: component, return boolean.
+ * @return {Array.}
+ */
+ findComponents: function (condition) {
+ var query = condition.query;
+ var mainType = condition.mainType;
+
+ var queryCond = getQueryCond(query);
+ var result = queryCond
+ ? this.queryComponents(queryCond)
+ : this._componentsMap.get(mainType);
+
+ return doFilter(filterBySubType(result, condition));
+
+ function getQueryCond(q) {
+ var indexAttr = mainType + 'Index';
+ var idAttr = mainType + 'Id';
+ var nameAttr = mainType + 'Name';
+ return q && (
+ q[indexAttr] != null
+ || q[idAttr] != null
+ || q[nameAttr] != null
+ )
+ ? {
+ mainType: mainType,
+ // subType will be filtered finally.
+ index: q[indexAttr],
+ id: q[idAttr],
+ name: q[nameAttr]
+ }
+ : null;
+ }
+
+ function doFilter(res) {
+ return condition.filter
+ ? filter(res, condition.filter)
+ : res;
+ }
+ },
+
+ /**
+ * @usage
+ * eachComponent('legend', function (legendModel, index) {
+ * ...
+ * });
+ * eachComponent(function (componentType, model, index) {
+ * // componentType does not include subType
+ * // (componentType is 'xxx' but not 'xxx.aa')
+ * });
+ * eachComponent(
+ * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},
+ * function (model, index) {...}
+ * );
+ * eachComponent(
+ * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},
+ * function (model, index) {...}
+ * );
+ *
+ * @param {string|Object=} mainType When mainType is object, the definition
+ * is the same as the method 'findComponents'.
+ * @param {Function} cb
+ * @param {*} context
+ */
+ eachComponent: function (mainType, cb, context) {
+ var componentsMap = this._componentsMap;
+
+ if (typeof mainType === 'function') {
+ context = cb;
+ cb = mainType;
+ componentsMap.each(function (components, componentType) {
+ each(components, function (component, index) {
+ cb.call(context, componentType, component, index);
+ });
+ });
+ }
+ else if (zrUtil.isString(mainType)) {
+ each(componentsMap.get(mainType), cb, context);
+ }
+ else if (isObject(mainType)) {
+ var queryResult = this.findComponents(mainType);
+ each(queryResult, cb, context);
+ }
+ },
+
+ /**
+ * @param {string} name
+ * @return {Array.}
+ */
+ getSeriesByName: function (name) {
+ var series = this._componentsMap.get('series');
+ return filter(series, function (oneSeries) {
+ return oneSeries.name === name;
+ });
+ },
+
+ /**
+ * @param {number} seriesIndex
+ * @return {module:echarts/model/Series}
+ */
+ getSeriesByIndex: function (seriesIndex) {
+ return this._componentsMap.get('series')[seriesIndex];
+ },
+
+ /**
+ * @param {string} subType
+ * @return {Array.}
+ */
+ getSeriesByType: function (subType) {
+ var series = this._componentsMap.get('series');
+ return filter(series, function (oneSeries) {
+ return oneSeries.subType === subType;
+ });
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getSeries: function () {
+ return this._componentsMap.get('series').slice();
+ },
+
+ /**
+ * After filtering, series may be different
+ * frome raw series.
+ *
+ * @param {Function} cb
+ * @param {*} context
+ */
+ eachSeries: function (cb, context) {
+ assertSeriesInitialized(this);
+ each(this._seriesIndices, function (rawSeriesIndex) {
+ var series = this._componentsMap.get('series')[rawSeriesIndex];
+ cb.call(context, series, rawSeriesIndex);
+ }, this);
+ },
+
+ /**
+ * Iterate raw series before filtered.
+ *
+ * @param {Function} cb
+ * @param {*} context
+ */
+ eachRawSeries: function (cb, context) {
+ each(this._componentsMap.get('series'), cb, context);
+ },
+
+ /**
+ * After filtering, series may be different.
+ * frome raw series.
+ *
+ * @parma {string} subType
+ * @param {Function} cb
+ * @param {*} context
+ */
+ eachSeriesByType: function (subType, cb, context) {
+ assertSeriesInitialized(this);
+ each(this._seriesIndices, function (rawSeriesIndex) {
+ var series = this._componentsMap.get('series')[rawSeriesIndex];
+ if (series.subType === subType) {
+ cb.call(context, series, rawSeriesIndex);
+ }
+ }, this);
+ },
+
+ /**
+ * Iterate raw series before filtered of given type.
+ *
+ * @parma {string} subType
+ * @param {Function} cb
+ * @param {*} context
+ */
+ eachRawSeriesByType: function (subType, cb, context) {
+ return each(this.getSeriesByType(subType), cb, context);
+ },
+
+ /**
+ * @param {module:echarts/model/Series} seriesModel
+ */
+ isSeriesFiltered: function (seriesModel) {
+ assertSeriesInitialized(this);
+ return zrUtil.indexOf(this._seriesIndices, seriesModel.componentIndex) < 0;
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getCurrentSeriesIndices: function () {
+ return (this._seriesIndices || []).slice();
+ },
+
+ /**
+ * @param {Function} cb
+ * @param {*} context
+ */
+ filterSeries: function (cb, context) {
+ assertSeriesInitialized(this);
+ var filteredSeries = filter(
+ this._componentsMap.get('series'), cb, context
+ );
+ this._seriesIndices = createSeriesIndices(filteredSeries);
+ },
+
+ restoreData: function () {
+ var componentsMap = this._componentsMap;
+
+ this._seriesIndices = createSeriesIndices(componentsMap.get('series'));
+
+ var componentTypes = [];
+ componentsMap.each(function (components, componentType) {
+ componentTypes.push(componentType);
+ });
+
+ ComponentModel.topologicalTravel(
+ componentTypes,
+ ComponentModel.getAllClassMainTypes(),
+ function (componentType, dependencies) {
+ each(componentsMap.get(componentType), function (component) {
+ component.restoreData();
+ });
+ }
+ );
+ }
+
+ });
+
+ /**
+ * @inner
+ */
+ function mergeTheme(option, theme) {
+ zrUtil.each(theme, function (themeItem, name) {
+ // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理
+ if (!ComponentModel.hasClass(name)) {
+ if (typeof themeItem === 'object') {
+ option[name] = !option[name]
+ ? zrUtil.clone(themeItem)
+ : zrUtil.merge(option[name], themeItem, false);
+ }
+ else {
+ if (option[name] == null) {
+ option[name] = themeItem;
+ }
+ }
+ }
+ });
+ }
+
+ function initBase(baseOption) {
+ baseOption = baseOption;
+
+ // Using OPTION_INNER_KEY to mark that this option can not be used outside,
+ // i.e. `chart.setOption(chart.getModel().option);` is forbiden.
+ this.option = {};
+ this.option[OPTION_INNER_KEY] = 1;
+
+ /**
+ * Init with series: [], in case of calling findSeries method
+ * before series initialized.
+ * @type {Object.>}
+ * @private
+ */
+ this._componentsMap = zrUtil.createHashMap({series: []});
+
+ /**
+ * Mapping between filtered series list and raw series list.
+ * key: filtered series indices, value: raw series indices.
+ * @type {Array.}
+ * @private
+ */
+ this._seriesIndices = null;
+
+ mergeTheme(baseOption, this._theme.option);
+
+ // TODO Needs clone when merging to the unexisted property
+ zrUtil.merge(baseOption, globalDefault, false);
+
+ this.mergeOption(baseOption);
+ }
+
+ /**
+ * @inner
+ * @param {Array.|string} types model types
+ * @return {Object} key: {string} type, value: {Array.} models
+ */
+ function getComponentsByTypes(componentsMap, types) {
+ if (!zrUtil.isArray(types)) {
+ types = types ? [types] : [];
+ }
+
+ var ret = {};
+ each(types, function (type) {
+ ret[type] = (componentsMap.get(type) || []).slice();
+ });
+
+ return ret;
+ }
+
+ /**
+ * @inner
+ */
+ function determineSubType(mainType, newCptOption, existComponent) {
+ var subType = newCptOption.type
+ ? newCptOption.type
+ : existComponent
+ ? existComponent.subType
+ // Use determineSubType only when there is no existComponent.
+ : ComponentModel.determineSubType(mainType, newCptOption);
+
+ // tooltip, markline, markpoint may always has no subType
+ return subType;
+ }
+
+ /**
+ * @inner
+ */
+ function createSeriesIndices(seriesModels) {
+ return map(seriesModels, function (series) {
+ return series.componentIndex;
+ }) || [];
+ }
+
+ /**
+ * @inner
+ */
+ function filterBySubType(components, condition) {
+ // Using hasOwnProperty for restrict. Consider
+ // subType is undefined in user payload.
+ return condition.hasOwnProperty('subType')
+ ? filter(components, function (cpt) {
+ return cpt.subType === condition.subType;
+ })
+ : components;
+ }
+
+ /**
+ * @inner
+ */
+ function assertSeriesInitialized(ecModel) {
+ // Components that use _seriesIndices should depends on series component,
+ // which make sure that their initialization is after series.
+ if (true) {
+ if (!ecModel._seriesIndices) {
+ throw new Error('Option should contains series.');
+ }
+ }
+ }
+
+ zrUtil.mixin(GlobalModel, __webpack_require__(74));
+
+ module.exports = GlobalModel;
+
+
+/***/ },
+/* 4 */
+/***/ function(module, exports) {
+
+ /**
+ * @module zrender/core/util
+ */
+
+
+ // 用于处理merge时无法遍历Date等对象的问题
+ var BUILTIN_OBJECT = {
+ '[object Function]': 1,
+ '[object RegExp]': 1,
+ '[object Date]': 1,
+ '[object Error]': 1,
+ '[object CanvasGradient]': 1,
+ '[object CanvasPattern]': 1,
+ // For node-canvas
+ '[object Image]': 1,
+ '[object Canvas]': 1
+ };
+
+ var TYPED_ARRAY = {
+ '[object Int8Array]': 1,
+ '[object Uint8Array]': 1,
+ '[object Uint8ClampedArray]': 1,
+ '[object Int16Array]': 1,
+ '[object Uint16Array]': 1,
+ '[object Int32Array]': 1,
+ '[object Uint32Array]': 1,
+ '[object Float32Array]': 1,
+ '[object Float64Array]': 1
+ };
+
+ var objToString = Object.prototype.toString;
+
+ var arrayProto = Array.prototype;
+ var nativeForEach = arrayProto.forEach;
+ var nativeFilter = arrayProto.filter;
+ var nativeSlice = arrayProto.slice;
+ var nativeMap = arrayProto.map;
+ var nativeReduce = arrayProto.reduce;
+
+ /**
+ * Those data types can be cloned:
+ * Plain object, Array, TypedArray, number, string, null, undefined.
+ * Those data types will be assgined using the orginal data:
+ * BUILTIN_OBJECT
+ * Instance of user defined class will be cloned to a plain object, without
+ * properties in prototype.
+ * Other data types is not supported (not sure what will happen).
+ *
+ * Caution: do not support clone Date, for performance consideration.
+ * (There might be a large number of date in `series.data`).
+ * So date should not be modified in and out of echarts.
+ *
+ * @param {*} source
+ * @return {*} new
+ */
+ function clone(source) {
+ if (source == null || typeof source != 'object') {
+ return source;
+ }
+
+ var result = source;
+ var typeStr = objToString.call(source);
+
+ if (typeStr === '[object Array]') {
+ result = [];
+ for (var i = 0, len = source.length; i < len; i++) {
+ result[i] = clone(source[i]);
+ }
+ }
+ else if (TYPED_ARRAY[typeStr]) {
+ result = source.constructor.from(source);
+ }
+ else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
+ result = {};
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ result[key] = clone(source[key]);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} target
+ * @param {*} source
+ * @param {boolean} [overwrite=false]
+ */
+ function merge(target, source, overwrite) {
+ // We should escapse that source is string
+ // and enter for ... in ...
+ if (!isObject(source) || !isObject(target)) {
+ return overwrite ? clone(source) : target;
+ }
+
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ var targetProp = target[key];
+ var sourceProp = source[key];
+
+ if (isObject(sourceProp)
+ && isObject(targetProp)
+ && !isArray(sourceProp)
+ && !isArray(targetProp)
+ && !isDom(sourceProp)
+ && !isDom(targetProp)
+ && !isBuiltInObject(sourceProp)
+ && !isBuiltInObject(targetProp)
+ && !isPrimitive(sourceProp)
+ && !isPrimitive(targetProp)
+ ) {
+ // 如果需要递归覆盖,就递归调用merge
+ merge(targetProp, sourceProp, overwrite);
+ }
+ else if (overwrite || !(key in target)) {
+ // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况
+ // NOTE,在 target[key] 不存在的时候也是直接覆盖
+ target[key] = clone(source[key], true);
+ }
+ }
+ }
+
+ return target;
+ }
+
+ /**
+ * @param {Array} targetAndSources The first item is target, and the rests are source.
+ * @param {boolean} [overwrite=false]
+ * @return {*} target
+ */
+ function mergeAll(targetAndSources, overwrite) {
+ var result = targetAndSources[0];
+ for (var i = 1, len = targetAndSources.length; i < len; i++) {
+ result = merge(result, targetAndSources[i], overwrite);
+ }
+ return result;
+ }
+
+ /**
+ * @param {*} target
+ * @param {*} source
+ * @memberOf module:zrender/core/util
+ */
+ function extend(target, source) {
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ target[key] = source[key];
+ }
+ }
+ return target;
+ }
+
+ /**
+ * @param {*} target
+ * @param {*} source
+ * @param {boolen} [overlay=false]
+ * @memberOf module:zrender/core/util
+ */
+ function defaults(target, source, overlay) {
+ for (var key in source) {
+ if (source.hasOwnProperty(key)
+ && (overlay ? source[key] != null : target[key] == null)
+ ) {
+ target[key] = source[key];
+ }
+ }
+ return target;
+ }
+
+ function createCanvas() {
+ return document.createElement('canvas');
+ }
+ // FIXME
+ var _ctx;
+ function getContext() {
+ if (!_ctx) {
+ // Use util.createCanvas instead of createCanvas
+ // because createCanvas may be overwritten in different environment
+ _ctx = util.createCanvas().getContext('2d');
+ }
+ return _ctx;
+ }
+
+ /**
+ * 查询数组中元素的index
+ * @memberOf module:zrender/core/util
+ */
+ function indexOf(array, value) {
+ if (array) {
+ if (array.indexOf) {
+ return array.indexOf(value);
+ }
+ for (var i = 0, len = array.length; i < len; i++) {
+ if (array[i] === value) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 构造类继承关系
+ *
+ * @memberOf module:zrender/core/util
+ * @param {Function} clazz 源类
+ * @param {Function} baseClazz 基类
+ */
+ function inherits(clazz, baseClazz) {
+ var clazzPrototype = clazz.prototype;
+ function F() {}
+ F.prototype = baseClazz.prototype;
+ clazz.prototype = new F();
+
+ for (var prop in clazzPrototype) {
+ clazz.prototype[prop] = clazzPrototype[prop];
+ }
+ clazz.prototype.constructor = clazz;
+ clazz.superClass = baseClazz;
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {Object|Function} target
+ * @param {Object|Function} sorce
+ * @param {boolean} overlay
+ */
+ function mixin(target, source, overlay) {
+ target = 'prototype' in target ? target.prototype : target;
+ source = 'prototype' in source ? source.prototype : source;
+
+ defaults(target, source, overlay);
+ }
+
+ /**
+ * Consider typed array.
+ * @param {Array|TypedArray} data
+ */
+ function isArrayLike(data) {
+ if (! data) {
+ return;
+ }
+ if (typeof data == 'string') {
+ return false;
+ }
+ return typeof data.length == 'number';
+ }
+
+ /**
+ * 数组或对象遍历
+ * @memberOf module:zrender/core/util
+ * @param {Object|Array} obj
+ * @param {Function} cb
+ * @param {*} [context]
+ */
+ function each(obj, cb, context) {
+ if (!(obj && cb)) {
+ return;
+ }
+ if (obj.forEach && obj.forEach === nativeForEach) {
+ obj.forEach(cb, context);
+ }
+ else if (obj.length === +obj.length) {
+ for (var i = 0, len = obj.length; i < len; i++) {
+ cb.call(context, obj[i], i, obj);
+ }
+ }
+ else {
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ cb.call(context, obj[key], key, obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * 数组映射
+ * @memberOf module:zrender/core/util
+ * @param {Array} obj
+ * @param {Function} cb
+ * @param {*} [context]
+ * @return {Array}
+ */
+ function map(obj, cb, context) {
+ if (!(obj && cb)) {
+ return;
+ }
+ if (obj.map && obj.map === nativeMap) {
+ return obj.map(cb, context);
+ }
+ else {
+ var result = [];
+ for (var i = 0, len = obj.length; i < len; i++) {
+ result.push(cb.call(context, obj[i], i, obj));
+ }
+ return result;
+ }
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {Array} obj
+ * @param {Function} cb
+ * @param {Object} [memo]
+ * @param {*} [context]
+ * @return {Array}
+ */
+ function reduce(obj, cb, memo, context) {
+ if (!(obj && cb)) {
+ return;
+ }
+ if (obj.reduce && obj.reduce === nativeReduce) {
+ return obj.reduce(cb, memo, context);
+ }
+ else {
+ for (var i = 0, len = obj.length; i < len; i++) {
+ memo = cb.call(context, memo, obj[i], i, obj);
+ }
+ return memo;
+ }
+ }
+
+ /**
+ * 数组过滤
+ * @memberOf module:zrender/core/util
+ * @param {Array} obj
+ * @param {Function} cb
+ * @param {*} [context]
+ * @return {Array}
+ */
+ function filter(obj, cb, context) {
+ if (!(obj && cb)) {
+ return;
+ }
+ if (obj.filter && obj.filter === nativeFilter) {
+ return obj.filter(cb, context);
+ }
+ else {
+ var result = [];
+ for (var i = 0, len = obj.length; i < len; i++) {
+ if (cb.call(context, obj[i], i, obj)) {
+ result.push(obj[i]);
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * 数组项查找
+ * @memberOf module:zrender/core/util
+ * @param {Array} obj
+ * @param {Function} cb
+ * @param {*} [context]
+ * @return {Array}
+ */
+ function find(obj, cb, context) {
+ if (!(obj && cb)) {
+ return;
+ }
+ for (var i = 0, len = obj.length; i < len; i++) {
+ if (cb.call(context, obj[i], i, obj)) {
+ return obj[i];
+ }
+ }
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {Function} func
+ * @param {*} context
+ * @return {Function}
+ */
+ function bind(func, context) {
+ var args = nativeSlice.call(arguments, 2);
+ return function () {
+ return func.apply(context, args.concat(nativeSlice.call(arguments)));
+ };
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {Function} func
+ * @return {Function}
+ */
+ function curry(func) {
+ var args = nativeSlice.call(arguments, 1);
+ return function () {
+ return func.apply(this, args.concat(nativeSlice.call(arguments)));
+ };
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isArray(value) {
+ return objToString.call(value) === '[object Array]';
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isFunction(value) {
+ return typeof value === 'function';
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isString(value) {
+ return objToString.call(value) === '[object String]';
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return type === 'function' || (!!value && type == 'object');
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isBuiltInObject(value) {
+ return !!BUILTIN_OBJECT[objToString.call(value)];
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {*} value
+ * @return {boolean}
+ */
+ function isDom(value) {
+ return typeof value === 'object'
+ && typeof value.nodeType === 'number'
+ && typeof value.ownerDocument === 'object';
+ }
+
+ /**
+ * Whether is exactly NaN. Notice isNaN('a') returns true.
+ * @param {*} value
+ * @return {boolean}
+ */
+ function eqNaN(value) {
+ return value !== value;
+ }
+
+ /**
+ * If value1 is not null, then return value1, otherwise judget rest of values.
+ * @memberOf module:zrender/core/util
+ * @return {*} Final value
+ */
+ function retrieve(values) {
+ for (var i = 0, len = arguments.length; i < len; i++) {
+ if (arguments[i] != null) {
+ return arguments[i];
+ }
+ }
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {Array} arr
+ * @param {number} startIndex
+ * @param {number} endIndex
+ * @return {Array}
+ */
+ function slice() {
+ return Function.call.apply(nativeSlice, arguments);
+ }
+
+ /**
+ * @memberOf module:zrender/core/util
+ * @param {boolean} condition
+ * @param {string} message
+ */
+ function assert(condition, message) {
+ if (!condition) {
+ throw new Error(message);
+ }
+ }
+
+ var primitiveKey = '__ec_primitive__';
+ /**
+ * Set an object as primitive to be ignored traversing children in clone or merge
+ */
+ function setAsPrimitive(obj) {
+ obj[primitiveKey] = true;
+ }
+
+ function isPrimitive(obj) {
+ return obj[primitiveKey];
+ }
+
+ /**
+ * @constructor
+ * @param {Object} obj Only apply `ownProperty`.
+ */
+ function HashMap(obj) {
+ obj && each(obj, function (value, key) {
+ this.set(key, value);
+ }, this);
+ }
+
+ // Add prefix to avoid conflict with Object.prototype.
+ var HASH_MAP_PREFIX = '_ec_';
+ var HASH_MAP_PREFIX_LENGTH = 4;
+
+ HashMap.prototype = {
+ constructor: HashMap,
+ // Do not provide `has` method to avoid defining what is `has`.
+ // (We usually treat `null` and `undefined` as the same, different
+ // from ES6 Map).
+ get: function (key) {
+ return this[HASH_MAP_PREFIX + key];
+ },
+ set: function (key, value) {
+ this[HASH_MAP_PREFIX + key] = value;
+ // Comparing with invocation chaining, `return value` is more commonly
+ // used in this case: `var someVal = map.set('a', genVal());`
+ return value;
+ },
+ // Although util.each can be performed on this hashMap directly, user
+ // should not use the exposed keys, who are prefixed.
+ each: function (cb, context) {
+ context !== void 0 && (cb = bind(cb, context));
+ for (var prefixedKey in this) {
+ this.hasOwnProperty(prefixedKey)
+ && cb(this[prefixedKey], prefixedKey.slice(HASH_MAP_PREFIX_LENGTH));
+ }
+ },
+ // Do not use this method if performance sensitive.
+ removeKey: function (key) {
+ delete this[key];
+ }
+ };
+
+ function createHashMap(obj) {
+ return new HashMap(obj);
+ }
+
+ var util = {
+ inherits: inherits,
+ mixin: mixin,
+ clone: clone,
+ merge: merge,
+ mergeAll: mergeAll,
+ extend: extend,
+ defaults: defaults,
+ getContext: getContext,
+ createCanvas: createCanvas,
+ indexOf: indexOf,
+ slice: slice,
+ find: find,
+ isArrayLike: isArrayLike,
+ each: each,
+ map: map,
+ reduce: reduce,
+ filter: filter,
+ bind: bind,
+ curry: curry,
+ isArray: isArray,
+ isString: isString,
+ isObject: isObject,
+ isFunction: isFunction,
+ isBuiltInObject: isBuiltInObject,
+ isDom: isDom,
+ eqNaN: eqNaN,
+ retrieve: retrieve,
+ assert: assert,
+ setAsPrimitive: setAsPrimitive,
+ createHashMap: createHashMap,
+ noop: function () {}
+ };
+ module.exports = util;
+
+
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var formatUtil = __webpack_require__(6);
+ var nubmerUtil = __webpack_require__(7);
+ var Model = __webpack_require__(12);
+ var zrUtil = __webpack_require__(4);
+ var each = zrUtil.each;
+ var isObject = zrUtil.isObject;
+
+ var modelUtil = {};
+
+ /**
+ * If value is not array, then translate it to array.
+ * @param {*} value
+ * @return {Array} [value] or value
+ */
+ modelUtil.normalizeToArray = function (value) {
+ return value instanceof Array
+ ? value
+ : value == null
+ ? []
+ : [value];
+ };
+
+ /**
+ * Sync default option between normal and emphasis like `position` and `show`
+ * In case some one will write code like
+ * label: {
+ * normal: {
+ * show: false,
+ * position: 'outside',
+ * textStyle: {
+ * fontSize: 18
+ * }
+ * },
+ * emphasis: {
+ * show: true
+ * }
+ * }
+ * @param {Object} opt
+ * @param {Array.} subOpts
+ */
+ modelUtil.defaultEmphasis = function (opt, subOpts) {
+ if (opt) {
+ var emphasisOpt = opt.emphasis = opt.emphasis || {};
+ var normalOpt = opt.normal = opt.normal || {};
+
+ // Default emphasis option from normal
+ each(subOpts, function (subOptName) {
+ var val = zrUtil.retrieve(emphasisOpt[subOptName], normalOpt[subOptName]);
+ if (val != null) {
+ emphasisOpt[subOptName] = val;
+ }
+ });
+ }
+ };
+
+ modelUtil.LABEL_OPTIONS = ['position', 'offset', 'show', 'textStyle', 'distance', 'formatter'];
+
+ /**
+ * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
+ * This helper method retieves value from data.
+ * @param {string|number|Date|Array|Object} dataItem
+ * @return {number|string|Date|Array.}
+ */
+ modelUtil.getDataItemValue = function (dataItem) {
+ // Performance sensitive.
+ return dataItem && (dataItem.value == null ? dataItem : dataItem.value);
+ };
+
+ /**
+ * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
+ * This helper method determine if dataItem has extra option besides value
+ * @param {string|number|Date|Array|Object} dataItem
+ */
+ modelUtil.isDataItemOption = function (dataItem) {
+ return isObject(dataItem)
+ && !(dataItem instanceof Array);
+ // // markLine data can be array
+ // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));
+ };
+
+ /**
+ * This helper method convert value in data.
+ * @param {string|number|Date} value
+ * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.
+ */
+ modelUtil.converDataValue = function (value, dimInfo) {
+ // Performance sensitive.
+ var dimType = dimInfo && dimInfo.type;
+ if (dimType === 'ordinal') {
+ return value;
+ }
+
+ if (dimType === 'time'
+ // spead up when using timestamp
+ && typeof value !== 'number'
+ && value != null
+ && value !== '-'
+ ) {
+ value = +nubmerUtil.parseDate(value);
+ }
+
+ // dimType defaults 'number'.
+ // If dimType is not ordinal and value is null or undefined or NaN or '-',
+ // parse to NaN.
+ return (value == null || value === '')
+ ? NaN : +value; // If string (like '-'), using '+' parse to NaN
+ };
+
+ /**
+ * Create a model proxy to be used in tooltip for edge data, markLine data, markPoint data.
+ * @param {module:echarts/data/List} data
+ * @param {Object} opt
+ * @param {string} [opt.seriesIndex]
+ * @param {Object} [opt.name]
+ * @param {Object} [opt.mainType]
+ * @param {Object} [opt.subType]
+ */
+ modelUtil.createDataFormatModel = function (data, opt) {
+ var model = new Model();
+ zrUtil.mixin(model, modelUtil.dataFormatMixin);
+ model.seriesIndex = opt.seriesIndex;
+ model.name = opt.name || '';
+ model.mainType = opt.mainType;
+ model.subType = opt.subType;
+
+ model.getData = function () {
+ return data;
+ };
+ return model;
+ };
+
+ // PENDING A little ugly
+ modelUtil.dataFormatMixin = {
+ /**
+ * Get params for formatter
+ * @param {number} dataIndex
+ * @param {string} [dataType]
+ * @return {Object}
+ */
+ getDataParams: function (dataIndex, dataType) {
+ var data = this.getData(dataType);
+ var rawValue = this.getRawValue(dataIndex, dataType);
+ var rawDataIndex = data.getRawIndex(dataIndex);
+ var name = data.getName(dataIndex, true);
+ var itemOpt = data.getRawDataItem(dataIndex);
+ var color = data.getItemVisual(dataIndex, 'color');
+
+ return {
+ componentType: this.mainType,
+ componentSubType: this.subType,
+ seriesType: this.mainType === 'series' ? this.subType : null,
+ seriesIndex: this.seriesIndex,
+ seriesId: this.id,
+ seriesName: this.name,
+ name: name,
+ dataIndex: rawDataIndex,
+ data: itemOpt,
+ dataType: dataType,
+ value: rawValue,
+ color: color,
+ marker: formatUtil.getTooltipMarker(color),
+
+ // Param name list for mapping `a`, `b`, `c`, `d`, `e`
+ $vars: ['seriesName', 'name', 'value']
+ };
+ },
+
+ /**
+ * Format label
+ * @param {number} dataIndex
+ * @param {string} [status='normal'] 'normal' or 'emphasis'
+ * @param {string} [dataType]
+ * @param {number} [dimIndex]
+ * @param {string} [labelProp='label']
+ * @return {string}
+ */
+ getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {
+ status = status || 'normal';
+ var data = this.getData(dataType);
+ var itemModel = data.getItemModel(dataIndex);
+
+ var params = this.getDataParams(dataIndex, dataType);
+ if (dimIndex != null && (params.value instanceof Array)) {
+ params.value = params.value[dimIndex];
+ }
+
+ var formatter = itemModel.get([labelProp || 'label', status, 'formatter']);
+
+ if (typeof formatter === 'function') {
+ params.status = status;
+ return formatter(params);
+ }
+ else if (typeof formatter === 'string') {
+ return formatUtil.formatTpl(formatter, params);
+ }
+ },
+
+ /**
+ * Get raw value in option
+ * @param {number} idx
+ * @param {string} [dataType]
+ * @return {Object}
+ */
+ getRawValue: function (idx, dataType) {
+ var data = this.getData(dataType);
+ var dataItem = data.getRawDataItem(idx);
+ if (dataItem != null) {
+ return (isObject(dataItem) && !(dataItem instanceof Array))
+ ? dataItem.value : dataItem;
+ }
+ },
+
+ /**
+ * Should be implemented.
+ * @param {number} dataIndex
+ * @param {boolean} [multipleSeries=false]
+ * @param {number} [dataType]
+ * @return {string} tooltip string
+ */
+ formatTooltip: zrUtil.noop
+ };
+
+ /**
+ * Mapping to exists for merge.
+ *
+ * @public
+ * @param {Array.|Array.} exists
+ * @param {Object|Array.} newCptOptions
+ * @return {Array.} Result, like [{exist: ..., option: ...}, {}],
+ * index of which is the same as exists.
+ */
+ modelUtil.mappingToExists = function (exists, newCptOptions) {
+ // Mapping by the order by original option (but not order of
+ // new option) in merge mode. Because we should ensure
+ // some specified index (like xAxisIndex) is consistent with
+ // original option, which is easy to understand, espatially in
+ // media query. And in most case, merge option is used to
+ // update partial option but not be expected to change order.
+ newCptOptions = (newCptOptions || []).slice();
+
+ var result = zrUtil.map(exists || [], function (obj, index) {
+ return {exist: obj};
+ });
+
+ // Mapping by id or name if specified.
+ each(newCptOptions, function (cptOption, index) {
+ if (!isObject(cptOption)) {
+ return;
+ }
+
+ // id has highest priority.
+ for (var i = 0; i < result.length; i++) {
+ if (!result[i].option // Consider name: two map to one.
+ && cptOption.id != null
+ && result[i].exist.id === cptOption.id + ''
+ ) {
+ result[i].option = cptOption;
+ newCptOptions[index] = null;
+ return;
+ }
+ }
+
+ for (var i = 0; i < result.length; i++) {
+ var exist = result[i].exist;
+ if (!result[i].option // Consider name: two map to one.
+ // Can not match when both ids exist but different.
+ && (exist.id == null || cptOption.id == null)
+ && cptOption.name != null
+ && !modelUtil.isIdInner(cptOption)
+ && !modelUtil.isIdInner(exist)
+ && exist.name === cptOption.name + ''
+ ) {
+ result[i].option = cptOption;
+ newCptOptions[index] = null;
+ return;
+ }
+ }
+ });
+
+ // Otherwise mapping by index.
+ each(newCptOptions, function (cptOption, index) {
+ if (!isObject(cptOption)) {
+ return;
+ }
+
+ var i = 0;
+ for (; i < result.length; i++) {
+ var exist = result[i].exist;
+ if (!result[i].option
+ // Existing model that already has id should be able to
+ // mapped to (because after mapping performed model may
+ // be assigned with a id, whish should not affect next
+ // mapping), except those has inner id.
+ && !modelUtil.isIdInner(exist)
+ // Caution:
+ // Do not overwrite id. But name can be overwritten,
+ // because axis use name as 'show label text'.
+ // 'exist' always has id and name and we dont
+ // need to check it.
+ && cptOption.id == null
+ ) {
+ result[i].option = cptOption;
+ break;
+ }
+ }
+
+ if (i >= result.length) {
+ result.push({option: cptOption});
+ }
+ });
+
+ return result;
+ };
+
+ /**
+ * Make id and name for mapping result (result of mappingToExists)
+ * into `keyInfo` field.
+ *
+ * @public
+ * @param {Array.} Result, like [{exist: ..., option: ...}, {}],
+ * which order is the same as exists.
+ * @return {Array.} The input.
+ */
+ modelUtil.makeIdAndName = function (mapResult) {
+ // We use this id to hash component models and view instances
+ // in echarts. id can be specified by user, or auto generated.
+
+ // The id generation rule ensures new view instance are able
+ // to mapped to old instance when setOption are called in
+ // no-merge mode. So we generate model id by name and plus
+ // type in view id.
+
+ // name can be duplicated among components, which is convenient
+ // to specify multi components (like series) by one name.
+
+ // Ensure that each id is distinct.
+ var idMap = zrUtil.createHashMap();
+
+ each(mapResult, function (item, index) {
+ var existCpt = item.exist;
+ existCpt && idMap.set(existCpt.id, item);
+ });
+
+ each(mapResult, function (item, index) {
+ var opt = item.option;
+
+ zrUtil.assert(
+ !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,
+ 'id duplicates: ' + (opt && opt.id)
+ );
+
+ opt && opt.id != null && idMap.set(opt.id, item);
+ !item.keyInfo && (item.keyInfo = {});
+ });
+
+ // Make name and id.
+ each(mapResult, function (item, index) {
+ var existCpt = item.exist;
+ var opt = item.option;
+ var keyInfo = item.keyInfo;
+
+ if (!isObject(opt)) {
+ return;
+ }
+
+ // name can be overwitten. Consider case: axis.name = '20km'.
+ // But id generated by name will not be changed, which affect
+ // only in that case: setOption with 'not merge mode' and view
+ // instance will be recreated, which can be accepted.
+ keyInfo.name = opt.name != null
+ ? opt.name + ''
+ : existCpt
+ ? existCpt.name
+ : '\0-'; // name may be displayed on screen, so use '-'.
+
+ if (existCpt) {
+ keyInfo.id = existCpt.id;
+ }
+ else if (opt.id != null) {
+ keyInfo.id = opt.id + '';
+ }
+ else {
+ // Consider this situatoin:
+ // optionA: [{name: 'a'}, {name: 'a'}, {..}]
+ // optionB [{..}, {name: 'a'}, {name: 'a'}]
+ // Series with the same name between optionA and optionB
+ // should be mapped.
+ var idNum = 0;
+ do {
+ keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++;
+ }
+ while (idMap.get(keyInfo.id));
+ }
+
+ idMap.set(keyInfo.id, item);
+ });
+ };
+
+ /**
+ * @public
+ * @param {Object} cptOption
+ * @return {boolean}
+ */
+ modelUtil.isIdInner = function (cptOption) {
+ return isObject(cptOption)
+ && cptOption.id
+ && (cptOption.id + '').indexOf('\0_ec_\0') === 0;
+ };
+
+ /**
+ * A helper for removing duplicate items between batchA and batchB,
+ * and in themselves, and categorize by series.
+ *
+ * @param {Array.} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
+ * @param {Array.} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
+ * @return {Array., Array.>} result: [resultBatchA, resultBatchB]
+ */
+ modelUtil.compressBatches = function (batchA, batchB) {
+ var mapA = {};
+ var mapB = {};
+
+ makeMap(batchA || [], mapA);
+ makeMap(batchB || [], mapB, mapA);
+
+ return [mapToArray(mapA), mapToArray(mapB)];
+
+ function makeMap(sourceBatch, map, otherMap) {
+ for (var i = 0, len = sourceBatch.length; i < len; i++) {
+ var seriesId = sourceBatch[i].seriesId;
+ var dataIndices = modelUtil.normalizeToArray(sourceBatch[i].dataIndex);
+ var otherDataIndices = otherMap && otherMap[seriesId];
+
+ for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {
+ var dataIndex = dataIndices[j];
+
+ if (otherDataIndices && otherDataIndices[dataIndex]) {
+ otherDataIndices[dataIndex] = null;
+ }
+ else {
+ (map[seriesId] || (map[seriesId] = {}))[dataIndex] = 1;
+ }
+ }
+ }
+ }
+
+ function mapToArray(map, isData) {
+ var result = [];
+ for (var i in map) {
+ if (map.hasOwnProperty(i) && map[i] != null) {
+ if (isData) {
+ result.push(+i);
+ }
+ else {
+ var dataIndices = mapToArray(map[i], true);
+ dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices});
+ }
+ }
+ }
+ return result;
+ }
+ };
+
+ /**
+ * @param {module:echarts/data/List} data
+ * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name
+ * each of which can be Array or primary type.
+ * @return {number|Array.} dataIndex If not found, return undefined/null.
+ */
+ modelUtil.queryDataIndex = function (data, payload) {
+ if (payload.dataIndexInside != null) {
+ return payload.dataIndexInside;
+ }
+ else if (payload.dataIndex != null) {
+ return zrUtil.isArray(payload.dataIndex)
+ ? zrUtil.map(payload.dataIndex, function (value) {
+ return data.indexOfRawIndex(value);
+ })
+ : data.indexOfRawIndex(payload.dataIndex);
+ }
+ else if (payload.name != null) {
+ return zrUtil.isArray(payload.name)
+ ? zrUtil.map(payload.name, function (value) {
+ return data.indexOfName(value);
+ })
+ : data.indexOfName(payload.name);
+ }
+ };
+
+ /**
+ * Enable property storage to any host object.
+ * Notice: Serialization is not supported.
+ *
+ * For example:
+ * var get = modelUitl.makeGetter();
+ *
+ * function some(hostObj) {
+ * get(hostObj)._someProperty = 1212;
+ * ...
+ * }
+ *
+ * @return {Function}
+ */
+ modelUtil.makeGetter = (function () {
+ var index = 0;
+ return function () {
+ var key = '\0__ec_prop_getter_' + index++;
+ return function (hostObj) {
+ return hostObj[key] || (hostObj[key] = {});
+ };
+ };
+ })();
+
+ /**
+ * @param {module:echarts/model/Global} ecModel
+ * @param {string|Object} finder
+ * If string, e.g., 'geo', means {geoIndex: 0}.
+ * If Object, could contain some of these properties below:
+ * {
+ * seriesIndex, seriesId, seriesName,
+ * geoIndex, geoId, geoName,
+ * bmapIndex, bmapId, bmapName,
+ * xAxisIndex, xAxisId, xAxisName,
+ * yAxisIndex, yAxisId, yAxisName,
+ * gridIndex, gridId, gridName,
+ * ... (can be extended)
+ * }
+ * Each properties can be number|string|Array.|Array.
+ * For example, a finder could be
+ * {
+ * seriesIndex: 3,
+ * geoId: ['aa', 'cc'],
+ * gridName: ['xx', 'rr']
+ * }
+ * xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)
+ * If nothing or null/undefined specified, return nothing.
+ * @param {Object} [opt]
+ * @param {string} [opt.defaultMainType]
+ * @param {Array.} [opt.includeMainTypes]
+ * @return {Object} result like:
+ * {
+ * seriesModels: [seriesModel1, seriesModel2],
+ * seriesModel: seriesModel1, // The first model
+ * geoModels: [geoModel1, geoModel2],
+ * geoModel: geoModel1, // The first model
+ * ...
+ * }
+ */
+ modelUtil.parseFinder = function (ecModel, finder, opt) {
+ if (zrUtil.isString(finder)) {
+ var obj = {};
+ obj[finder + 'Index'] = 0;
+ finder = obj;
+ }
+
+ var defaultMainType = opt && opt.defaultMainType;
+ if (defaultMainType
+ && !has(finder, defaultMainType + 'Index')
+ && !has(finder, defaultMainType + 'Id')
+ && !has(finder, defaultMainType + 'Name')
+ ) {
+ finder[defaultMainType + 'Index'] = 0;
+ }
+
+ var result = {};
+
+ each(finder, function (value, key) {
+ var value = finder[key];
+
+ // Exclude 'dataIndex' and other illgal keys.
+ if (key === 'dataIndex' || key === 'dataIndexInside') {
+ result[key] = value;
+ return;
+ }
+
+ var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || [];
+ var mainType = parsedKey[1];
+ var queryType = (parsedKey[2] || '').toLowerCase();
+
+ if (!mainType
+ || !queryType
+ || value == null
+ || (queryType === 'index' && value === 'none')
+ || (opt && opt.includeMainTypes && zrUtil.indexOf(opt.includeMainTypes, mainType) < 0)
+ ) {
+ return;
+ }
+
+ var queryParam = {mainType: mainType};
+ if (queryType !== 'index' || value !== 'all') {
+ queryParam[queryType] = value;
+ }
+
+ var models = ecModel.queryComponents(queryParam);
+ result[mainType + 'Models'] = models;
+ result[mainType + 'Model'] = models[0];
+ });
+
+ return result;
+ };
+
+ /**
+ * @see {module:echarts/data/helper/completeDimensions}
+ * @param {module:echarts/data/List} data
+ * @param {string|number} dataDim
+ * @return {string}
+ */
+ modelUtil.dataDimToCoordDim = function (data, dataDim) {
+ var dimensions = data.dimensions;
+ dataDim = data.getDimension(dataDim);
+ for (var i = 0; i < dimensions.length; i++) {
+ var dimItem = data.getDimensionInfo(dimensions[i]);
+ if (dimItem.name === dataDim) {
+ return dimItem.coordDim;
+ }
+ }
+ };
+
+ /**
+ * @see {module:echarts/data/helper/completeDimensions}
+ * @param {module:echarts/data/List} data
+ * @param {string} coordDim
+ * @return {Array.} data dimensions on the coordDim.
+ */
+ modelUtil.coordDimToDataDim = function (data, coordDim) {
+ var dataDim = [];
+ each(data.dimensions, function (dimName) {
+ var dimItem = data.getDimensionInfo(dimName);
+ if (dimItem.coordDim === coordDim) {
+ dataDim[dimItem.coordDimIndex] = dimItem.name;
+ }
+ });
+ return dataDim;
+ };
+
+ /**
+ * @see {module:echarts/data/helper/completeDimensions}
+ * @param {module:echarts/data/List} data
+ * @param {string} otherDim Can be `otherDims`
+ * like 'label' or 'tooltip'.
+ * @return {Array.} data dimensions on the otherDim.
+ */
+ modelUtil.otherDimToDataDim = function (data, otherDim) {
+ var dataDim = [];
+ each(data.dimensions, function (dimName) {
+ var dimItem = data.getDimensionInfo(dimName);
+ var otherDims = dimItem.otherDims;
+ var dimIndex = otherDims[otherDim];
+ if (dimIndex != null && dimIndex !== false) {
+ dataDim[dimIndex] = dimItem.name;
+ }
+ });
+ return dataDim;
+ };
+
+ function has(obj, prop) {
+ return obj && obj.hasOwnProperty(prop);
+ }
+
+ module.exports = modelUtil;
+
+
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var zrUtil = __webpack_require__(4);
+ var numberUtil = __webpack_require__(7);
+ var textContain = __webpack_require__(8);
+
+ var formatUtil = {};
+
+ /**
+ * 每三位默认加,格式化
+ * @param {string|number} x
+ * @return {string}
+ */
+ formatUtil.addCommas = function (x) {
+ if (isNaN(x)) {
+ return '-';
+ }
+ x = (x + '').split('.');
+ return x[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,'$1,')
+ + (x.length > 1 ? ('.' + x[1]) : '');
+ };
+
+ /**
+ * @param {string} str
+ * @param {boolean} [upperCaseFirst=false]
+ * @return {string} str
+ */
+ formatUtil.toCamelCase = function (str, upperCaseFirst) {
+ str = (str || '').toLowerCase().replace(/-(.)/g, function(match, group1) {
+ return group1.toUpperCase();
+ });
+
+ if (upperCaseFirst && str) {
+ str = str.charAt(0).toUpperCase() + str.slice(1);
+ }
+
+ return str;
+ };
+
+ /**
+ * Normalize css liked array configuration
+ * e.g.
+ * 3 => [3, 3, 3, 3]
+ * [4, 2] => [4, 2, 4, 2]
+ * [4, 3, 2] => [4, 3, 2, 3]
+ * @param {number|Array.} val
+ */
+ formatUtil.normalizeCssArray = function (val) {
+ var len = val.length;
+ if (typeof (val) === 'number') {
+ return [val, val, val, val];
+ }
+ else if (len === 2) {
+ // vertical | horizontal
+ return [val[0], val[1], val[0], val[1]];
+ }
+ else if (len === 3) {
+ // top | horizontal | bottom
+ return [val[0], val[1], val[2], val[1]];
+ }
+ return val;
+ };
+
+ var encodeHTML = formatUtil.encodeHTML = function (source) {
+ return String(source)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ };
+
+ var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
+
+ var wrapVar = function (varName, seriesIdx) {
+ return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';
+ };
+
+ /**
+ * Template formatter
+ * @param {string} tpl
+ * @param {Array.|Object} paramsList
+ * @param {boolean} [encode=false]
+ * @return {string}
+ */
+ formatUtil.formatTpl = function (tpl, paramsList, encode) {
+ if (!zrUtil.isArray(paramsList)) {
+ paramsList = [paramsList];
+ }
+ var seriesLen = paramsList.length;
+ if (!seriesLen) {
+ return '';
+ }
+
+ var $vars = paramsList[0].$vars || [];
+ for (var i = 0; i < $vars.length; i++) {
+ var alias = TPL_VAR_ALIAS[i];
+ var val = wrapVar(alias, 0);
+ tpl = tpl.replace(wrapVar(alias), encode ? encodeHTML(val) : val);
+ }
+ for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {
+ for (var k = 0; k < $vars.length; k++) {
+ var val = paramsList[seriesIdx][$vars[k]];
+ tpl = tpl.replace(
+ wrapVar(TPL_VAR_ALIAS[k], seriesIdx),
+ encode ? encodeHTML(val) : val
+ );
+ }
+ }
+
+ return tpl;
+ };
+
+ /**
+ * simple Template formatter
+ *
+ * @param {string} tpl
+ * @param {Object} param
+ * @param {boolean} [encode=false]
+ * @return {string}
+ */
+ formatUtil.formatTplSimple = function (tpl, param, encode) {
+ zrUtil.each(param, function (value, key) {
+ tpl = tpl.replace(
+ '{' + key + '}',
+ encode ? encodeHTML(value) : value
+ );
+ });
+ return tpl;
+ };
+
+ /**
+ * @param {string} color
+ * @param {string} [extraCssText]
+ * @return {string}
+ */
+ formatUtil.getTooltipMarker = function (color, extraCssText) {
+ return color
+ ? ' '
+ : '';
+ };
+
+ /**
+ * @param {string} str
+ * @return {string}
+ * @inner
+ */
+ var s2d = function (str) {
+ return str < 10 ? ('0' + str) : str;
+ };
+
+ /**
+ * ISO Date format
+ * @param {string} tpl
+ * @param {number} value
+ * @param {boolean} [isUTC=false] Default in local time.
+ * see `module:echarts/scale/Time`
+ * and `module:echarts/util/number#parseDate`.
+ * @inner
+ */
+ formatUtil.formatTime = function (tpl, value, isUTC) {
+ if (tpl === 'week'
+ || tpl === 'month'
+ || tpl === 'quarter'
+ || tpl === 'half-year'
+ || tpl === 'year'
+ ) {
+ tpl = 'MM-dd\nyyyy';
+ }
+
+ var date = numberUtil.parseDate(value);
+ var utc = isUTC ? 'UTC' : '';
+ var y = date['get' + utc + 'FullYear']();
+ var M = date['get' + utc + 'Month']() + 1;
+ var d = date['get' + utc + 'Date']();
+ var h = date['get' + utc + 'Hours']();
+ var m = date['get' + utc + 'Minutes']();
+ var s = date['get' + utc + 'Seconds']();
+
+ tpl = tpl.replace('MM', s2d(M))
+ .toLowerCase()
+ .replace('yyyy', y)
+ .replace('yy', y % 100)
+ .replace('dd', s2d(d))
+ .replace('d', d)
+ .replace('hh', s2d(h))
+ .replace('h', h)
+ .replace('mm', s2d(m))
+ .replace('m', m)
+ .replace('ss', s2d(s))
+ .replace('s', s);
+
+ return tpl;
+ };
+
+ /**
+ * Capital first
+ * @param {string} str
+ * @return {string}
+ */
+ formatUtil.capitalFirst = function (str) {
+ return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;
+ };
+
+ formatUtil.truncateText = textContain.truncateText;
+
+ module.exports = formatUtil;
+
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 数值处理模块
+ * @module echarts/util/number
+ */
+
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var number = {};
+
+ var RADIAN_EPSILON = 1e-4;
+
+ function _trim(str) {
+ return str.replace(/^\s+/, '').replace(/\s+$/, '');
+ }
+
+ /**
+ * Linear mapping a value from domain to range
+ * @memberOf module:echarts/util/number
+ * @param {(number|Array.)} val
+ * @param {Array.} domain Domain extent domain[0] can be bigger than domain[1]
+ * @param {Array.} range Range extent range[0] can be bigger than range[1]
+ * @param {boolean} clamp
+ * @return {(number|Array.}
+ */
+ number.linearMap = function (val, domain, range, clamp) {
+ var subDomain = domain[1] - domain[0];
+ var subRange = range[1] - range[0];
+
+ if (subDomain === 0) {
+ return subRange === 0
+ ? range[0]
+ : (range[0] + range[1]) / 2;
+ }
+
+ // Avoid accuracy problem in edge, such as
+ // 146.39 - 62.83 === 83.55999999999999.
+ // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError
+ // It is a little verbose for efficiency considering this method
+ // is a hotspot.
+ if (clamp) {
+ if (subDomain > 0) {
+ if (val <= domain[0]) {
+ return range[0];
+ }
+ else if (val >= domain[1]) {
+ return range[1];
+ }
+ }
+ else {
+ if (val >= domain[0]) {
+ return range[0];
+ }
+ else if (val <= domain[1]) {
+ return range[1];
+ }
+ }
+ }
+ else {
+ if (val === domain[0]) {
+ return range[0];
+ }
+ if (val === domain[1]) {
+ return range[1];
+ }
+ }
+
+ return (val - domain[0]) / subDomain * subRange + range[0];
+ };
+
+ /**
+ * Convert a percent string to absolute number.
+ * Returns NaN if percent is not a valid string or number
+ * @memberOf module:echarts/util/number
+ * @param {string|number} percent
+ * @param {number} all
+ * @return {number}
+ */
+ number.parsePercent = function(percent, all) {
+ switch (percent) {
+ case 'center':
+ case 'middle':
+ percent = '50%';
+ break;
+ case 'left':
+ case 'top':
+ percent = '0%';
+ break;
+ case 'right':
+ case 'bottom':
+ percent = '100%';
+ break;
+ }
+ if (typeof percent === 'string') {
+ if (_trim(percent).match(/%$/)) {
+ return parseFloat(percent) / 100 * all;
+ }
+
+ return parseFloat(percent);
+ }
+
+ return percent == null ? NaN : +percent;
+ };
+
+ /**
+ * (1) Fix rounding error of float numbers.
+ * (2) Support return string to avoid scientific notation like '3.5e-7'.
+ *
+ * @param {number} x
+ * @param {number} [precision]
+ * @param {boolean} [returnStr]
+ * @return {number|string}
+ */
+ number.round = function (x, precision, returnStr) {
+ if (precision == null) {
+ precision = 10;
+ }
+ // Avoid range error
+ precision = Math.min(Math.max(0, precision), 20);
+ x = (+x).toFixed(precision);
+ return returnStr ? x : +x;
+ };
+
+ number.asc = function (arr) {
+ arr.sort(function (a, b) {
+ return a - b;
+ });
+ return arr;
+ };
+
+ /**
+ * Get precision
+ * @param {number} val
+ */
+ number.getPrecision = function (val) {
+ val = +val;
+ if (isNaN(val)) {
+ return 0;
+ }
+ // It is much faster than methods converting number to string as follows
+ // var tmp = val.toString();
+ // return tmp.length - 1 - tmp.indexOf('.');
+ // especially when precision is low
+ var e = 1;
+ var count = 0;
+ while (Math.round(val * e) / e !== val) {
+ e *= 10;
+ count++;
+ }
+ return count;
+ };
+
+ /**
+ * @param {string|number} val
+ * @return {number}
+ */
+ number.getPrecisionSafe = function (val) {
+ var str = val.toString();
+
+ // Consider scientific notation: '3.4e-12' '3.4e+12'
+ var eIndex = str.indexOf('e');
+ if (eIndex > 0) {
+ var precision = +str.slice(eIndex + 1);
+ return precision < 0 ? -precision : 0;
+ }
+ else {
+ var dotIndex = str.indexOf('.');
+ return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;
+ }
+ };
+
+ /**
+ * Minimal dicernible data precisioin according to a single pixel.
+ *
+ * @param {Array.} dataExtent
+ * @param {Array.} pixelExtent
+ * @return {number} precision
+ */
+ number.getPixelPrecision = function (dataExtent, pixelExtent) {
+ var log = Math.log;
+ var LN10 = Math.LN10;
+ var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);
+ var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);
+ // toFixed() digits argument must be between 0 and 20.
+ var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);
+ return !isFinite(precision) ? 20 : precision;
+ };
+
+ /**
+ * Get a data of given precision, assuring the sum of percentages
+ * in valueList is 1.
+ * The largest remainer method is used.
+ * https://en.wikipedia.org/wiki/Largest_remainder_method
+ *
+ * @param {Array.} valueList a list of all data
+ * @param {number} idx index of the data to be processed in valueList
+ * @param {number} precision integer number showing digits of precision
+ * @return {number} percent ranging from 0 to 100
+ */
+ number.getPercentWithPrecision = function (valueList, idx, precision) {
+ if (!valueList[idx]) {
+ return 0;
+ }
+
+ var sum = zrUtil.reduce(valueList, function (acc, val) {
+ return acc + (isNaN(val) ? 0 : val);
+ }, 0);
+ if (sum === 0) {
+ return 0;
+ }
+
+ var digits = Math.pow(10, precision);
+ var votesPerQuota = zrUtil.map(valueList, function (val) {
+ return (isNaN(val) ? 0 : val) / sum * digits * 100;
+ });
+ var targetSeats = digits * 100;
+
+ var seats = zrUtil.map(votesPerQuota, function (votes) {
+ // Assign automatic seats.
+ return Math.floor(votes);
+ });
+ var currentSum = zrUtil.reduce(seats, function (acc, val) {
+ return acc + val;
+ }, 0);
+
+ var remainder = zrUtil.map(votesPerQuota, function (votes, idx) {
+ return votes - seats[idx];
+ });
+
+ // Has remainding votes.
+ while (currentSum < targetSeats) {
+ // Find next largest remainder.
+ var max = Number.NEGATIVE_INFINITY;
+ var maxId = null;
+ for (var i = 0, len = remainder.length; i < len; ++i) {
+ if (remainder[i] > max) {
+ max = remainder[i];
+ maxId = i;
+ }
+ }
+
+ // Add a vote to max remainder.
+ ++seats[maxId];
+ remainder[maxId] = 0;
+ ++currentSum;
+ }
+
+ return seats[idx] / digits;
+ };
+
+ // Number.MAX_SAFE_INTEGER, ie do not support.
+ number.MAX_SAFE_INTEGER = 9007199254740991;
+
+ /**
+ * To 0 - 2 * PI, considering negative radian.
+ * @param {number} radian
+ * @return {number}
+ */
+ number.remRadian = function (radian) {
+ var pi2 = Math.PI * 2;
+ return (radian % pi2 + pi2) % pi2;
+ };
+
+ /**
+ * @param {type} radian
+ * @return {boolean}
+ */
+ number.isRadianAroundZero = function (val) {
+ return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;
+ };
+
+ var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d\d)(?::(\d\d)(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line
+
+ /**
+ * @return {number} in minutes
+ */
+ number.getTimezoneOffset = function () {
+ return (new Date()).getTimezoneOffset();
+ };
+
+ /**
+ * @param {string|Date|number} value These values can be accepted:
+ * + An instance of Date, represent a time in its own time zone.
+ * + Or string in a subset of ISO 8601, only including:
+ * + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',
+ * + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',
+ * + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',
+ * all of which will be treated as local time if time zone is not specified
+ * (see ).
+ * + Or other string format, including (all of which will be treated as loacal time):
+ * '2012', '2012-3-1', '2012/3/1', '2012/03/01',
+ * '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'
+ * + a timestamp, which represent a time in UTC.
+ * @return {Date} date
+ */
+ number.parseDate = function (value) {
+ if (value instanceof Date) {
+ return value;
+ }
+ else if (typeof value === 'string') {
+ // Different browsers parse date in different way, so we parse it manually.
+ // Some other issues:
+ // new Date('1970-01-01') is UTC,
+ // new Date('1970/01/01') and new Date('1970-1-01') is local.
+ // See issue #3623
+ var match = TIME_REG.exec(value);
+
+ if (!match) {
+ // return Invalid Date.
+ return new Date(NaN);
+ }
+
+ var timezoneOffset = number.getTimezoneOffset();
+ var timeOffset = !match[8]
+ ? 0
+ : match[8].toUpperCase() === 'Z'
+ ? timezoneOffset
+ : +match[8].slice(0, 3) * 60 + timezoneOffset;
+
+ // match[n] can only be string or undefined.
+ // But take care of '12' + 1 => '121'.
+ return new Date(
+ +match[1],
+ +(match[2] || 1) - 1,
+ +match[3] || 1,
+ +match[4] || 0,
+ +(match[5] || 0) - timeOffset,
+ +match[6] || 0,
+ +match[7] || 0
+ );
+ }
+ else if (value == null) {
+ return new Date(NaN);
+ }
+
+ return new Date(Math.round(value));
+ };
+
+ /**
+ * Quantity of a number. e.g. 0.1, 1, 10, 100
+ *
+ * @param {number} val
+ * @return {number}
+ */
+ number.quantity = function (val) {
+ return Math.pow(10, quantityExponent(val));
+ };
+
+ function quantityExponent(val) {
+ return Math.floor(Math.log(val) / Math.LN10);
+ }
+
+ /**
+ * find a “nice” number approximately equal to x. Round the number if round = true,
+ * take ceiling if round = false. The primary observation is that the “nicest”
+ * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.
+ *
+ * See "Nice Numbers for Graph Labels" of Graphic Gems.
+ *
+ * @param {number} val Non-negative value.
+ * @param {boolean} round
+ * @return {number}
+ */
+ number.nice = function (val, round) {
+ var exponent = quantityExponent(val);
+ var exp10 = Math.pow(10, exponent);
+ var f = val / exp10; // 1 <= f < 10
+ var nf;
+ if (round) {
+ if (f < 1.5) { nf = 1; }
+ else if (f < 2.5) { nf = 2; }
+ else if (f < 4) { nf = 3; }
+ else if (f < 7) { nf = 5; }
+ else { nf = 10; }
+ }
+ else {
+ if (f < 1) { nf = 1; }
+ else if (f < 2) { nf = 2; }
+ else if (f < 3) { nf = 3; }
+ else if (f < 5) { nf = 5; }
+ else { nf = 10; }
+ }
+ val = nf * exp10;
+
+ // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).
+ // 20 is the uppper bound of toFixed.
+ return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;
+ };
+
+ /**
+ * Order intervals asc, and split them when overlap.
+ * expect(numberUtil.reformIntervals([
+ * {interval: [18, 62], close: [1, 1]},
+ * {interval: [-Infinity, -70], close: [0, 0]},
+ * {interval: [-70, -26], close: [1, 1]},
+ * {interval: [-26, 18], close: [1, 1]},
+ * {interval: [62, 150], close: [1, 1]},
+ * {interval: [106, 150], close: [1, 1]},
+ * {interval: [150, Infinity], close: [0, 0]}
+ * ])).toEqual([
+ * {interval: [-Infinity, -70], close: [0, 0]},
+ * {interval: [-70, -26], close: [1, 1]},
+ * {interval: [-26, 18], close: [0, 1]},
+ * {interval: [18, 62], close: [0, 1]},
+ * {interval: [62, 150], close: [0, 1]},
+ * {interval: [150, Infinity], close: [0, 0]}
+ * ]);
+ * @param {Array.} list, where `close` mean open or close
+ * of the interval, and Infinity can be used.
+ * @return {Array.} The origin list, which has been reformed.
+ */
+ number.reformIntervals = function (list) {
+ list.sort(function (a, b) {
+ return littleThan(a, b, 0) ? -1 : 1;
+ });
+
+ var curr = -Infinity;
+ var currClose = 1;
+ for (var i = 0; i < list.length;) {
+ var interval = list[i].interval;
+ var close = list[i].close;
+
+ for (var lg = 0; lg < 2; lg++) {
+ if (interval[lg] <= curr) {
+ interval[lg] = curr;
+ close[lg] = !lg ? 1 - currClose : 1;
+ }
+ curr = interval[lg];
+ currClose = close[lg];
+ }
+
+ if (interval[0] === interval[1] && close[0] * close[1] !== 1) {
+ list.splice(i, 1);
+ }
+ else {
+ i++;
+ }
+ }
+
+ return list;
+
+ function littleThan(a, b, lg) {
+ return a.interval[lg] < b.interval[lg]
+ || (
+ a.interval[lg] === b.interval[lg]
+ && (
+ (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))
+ || (!lg && littleThan(a, b, 1))
+ )
+ );
+ }
+ };
+
+ /**
+ * parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ * ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ * subtraction forces infinities to NaN
+ *
+ * @param {*} v
+ * @return {boolean}
+ */
+ number.isNumeric = function (v) {
+ return v - parseFloat(v) >= 0;
+ };
+
+ module.exports = number;
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var textWidthCache = {};
+ var textWidthCacheCounter = 0;
+ var TEXT_CACHE_MAX = 5000;
+
+ var util = __webpack_require__(4);
+ var BoundingRect = __webpack_require__(9);
+ var retrieve = util.retrieve;
+
+ function getTextWidth(text, textFont) {
+ var key = text + ':' + textFont;
+ if (textWidthCache[key]) {
+ return textWidthCache[key];
+ }
+
+ var textLines = (text + '').split('\n');
+ var width = 0;
+
+ for (var i = 0, l = textLines.length; i < l; i++) {
+ // measureText 可以被覆盖以兼容不支持 Canvas 的环境
+ width = Math.max(textContain.measureText(textLines[i], textFont).width, width);
+ }
+
+ if (textWidthCacheCounter > TEXT_CACHE_MAX) {
+ textWidthCacheCounter = 0;
+ textWidthCache = {};
+ }
+ textWidthCacheCounter++;
+ textWidthCache[key] = width;
+
+ return width;
+ }
+
+ function getTextRect(text, textFont, textAlign, textBaseline) {
+ var textLineLen = ((text || '') + '').split('\n').length;
+
+ var width = getTextWidth(text, textFont);
+ // FIXME 高度计算比较粗暴
+ var lineHeight = getTextWidth('国', textFont);
+ var height = textLineLen * lineHeight;
+
+ var rect = new BoundingRect(0, 0, width, height);
+ // Text has a special line height property
+ rect.lineHeight = lineHeight;
+
+ switch (textBaseline) {
+ case 'bottom':
+ case 'alphabetic':
+ rect.y -= lineHeight;
+ break;
+ case 'middle':
+ rect.y -= lineHeight / 2;
+ break;
+ // case 'hanging':
+ // case 'top':
+ }
+
+ // FIXME Right to left language
+ switch (textAlign) {
+ case 'end':
+ case 'right':
+ rect.x -= rect.width;
+ break;
+ case 'center':
+ rect.x -= rect.width / 2;
+ break;
+ // case 'start':
+ // case 'left':
+ }
+
+ return rect;
+ }
+
+ function adjustTextPositionOnRect(textPosition, rect, textRect, distance) {
+
+ var x = rect.x;
+ var y = rect.y;
+
+ var height = rect.height;
+ var width = rect.width;
+
+ var textHeight = textRect.height;
+
+ var lineHeight = textRect.lineHeight;
+ var halfHeight = height / 2 - textHeight / 2 + lineHeight;
+
+ var textAlign = 'left';
+
+ switch (textPosition) {
+ case 'left':
+ x -= distance;
+ y += halfHeight;
+ textAlign = 'right';
+ break;
+ case 'right':
+ x += distance + width;
+ y += halfHeight;
+ textAlign = 'left';
+ break;
+ case 'top':
+ x += width / 2;
+ y -= distance + textHeight - lineHeight;
+ textAlign = 'center';
+ break;
+ case 'bottom':
+ x += width / 2;
+ y += height + distance + lineHeight;
+ textAlign = 'center';
+ break;
+ case 'inside':
+ x += width / 2;
+ y += halfHeight;
+ textAlign = 'center';
+ break;
+ case 'insideLeft':
+ x += distance;
+ y += halfHeight;
+ textAlign = 'left';
+ break;
+ case 'insideRight':
+ x += width - distance;
+ y += halfHeight;
+ textAlign = 'right';
+ break;
+ case 'insideTop':
+ x += width / 2;
+ y += distance + lineHeight;
+ textAlign = 'center';
+ break;
+ case 'insideBottom':
+ x += width / 2;
+ y += height - textHeight - distance + lineHeight;
+ textAlign = 'center';
+ break;
+ case 'insideTopLeft':
+ x += distance;
+ y += distance + lineHeight;
+ textAlign = 'left';
+ break;
+ case 'insideTopRight':
+ x += width - distance;
+ y += distance + lineHeight;
+ textAlign = 'right';
+ break;
+ case 'insideBottomLeft':
+ x += distance;
+ y += height - textHeight - distance + lineHeight;
+ break;
+ case 'insideBottomRight':
+ x += width - distance;
+ y += height - textHeight - distance + lineHeight;
+ textAlign = 'right';
+ break;
+ }
+
+ return {
+ x: x,
+ y: y,
+ textAlign: textAlign,
+ textBaseline: 'alphabetic'
+ };
+ }
+
+ /**
+ * Show ellipsis if overflow.
+ *
+ * @param {string} text
+ * @param {string} containerWidth
+ * @param {string} textFont
+ * @param {number} [ellipsis='...']
+ * @param {Object} [options]
+ * @param {number} [options.maxIterations=3]
+ * @param {number} [options.minChar=0] If truncate result are less
+ * then minChar, ellipsis will not show, which is
+ * better for user hint in some cases.
+ * @param {number} [options.placeholder=''] When all truncated, use the placeholder.
+ * @return {string}
+ */
+ function truncateText(text, containerWidth, textFont, ellipsis, options) {
+ if (!containerWidth) {
+ return '';
+ }
+
+ options = options || {};
+
+ ellipsis = retrieve(ellipsis, '...');
+ var maxIterations = retrieve(options.maxIterations, 2);
+ var minChar = retrieve(options.minChar, 0);
+ // FIXME
+ // Other languages?
+ var cnCharWidth = getTextWidth('国', textFont);
+ // FIXME
+ // Consider proportional font?
+ var ascCharWidth = getTextWidth('a', textFont);
+ var placeholder = retrieve(options.placeholder, '');
+
+ // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.
+ // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.
+ var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.
+ for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
+ contentWidth -= ascCharWidth;
+ }
+
+ var ellipsisWidth = getTextWidth(ellipsis);
+ if (ellipsisWidth > contentWidth) {
+ ellipsis = '';
+ ellipsisWidth = 0;
+ }
+
+ contentWidth = containerWidth - ellipsisWidth;
+
+ var textLines = (text + '').split('\n');
+
+ for (var i = 0, len = textLines.length; i < len; i++) {
+ var textLine = textLines[i];
+ var lineWidth = getTextWidth(textLine, textFont);
+
+ if (lineWidth <= containerWidth) {
+ continue;
+ }
+
+ for (var j = 0;; j++) {
+ if (lineWidth <= contentWidth || j >= maxIterations) {
+ textLine += ellipsis;
+ break;
+ }
+
+ var subLength = j === 0
+ ? estimateLength(textLine, contentWidth, ascCharWidth, cnCharWidth)
+ : lineWidth > 0
+ ? Math.floor(textLine.length * contentWidth / lineWidth)
+ : 0;
+
+ textLine = textLine.substr(0, subLength);
+ lineWidth = getTextWidth(textLine, textFont);
+ }
+
+ if (textLine === '') {
+ textLine = placeholder;
+ }
+
+ textLines[i] = textLine;
+ }
+
+ return textLines.join('\n');
+ }
+
+ function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
+ var width = 0;
+ var i = 0;
+ for (var len = text.length; i < len && width < contentWidth; i++) {
+ var charCode = text.charCodeAt(i);
+ width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;
+ }
+ return i;
+ }
+
+ var textContain = {
+
+ getWidth: getTextWidth,
+
+ getBoundingRect: getTextRect,
+
+ adjustTextPositionOnRect: adjustTextPositionOnRect,
+
+ truncateText: truncateText,
+
+ measureText: function (text, textFont) {
+ var ctx = util.getContext();
+ ctx.font = textFont || '12px sans-serif';
+ return ctx.measureText(text);
+ }
+ };
+
+ module.exports = textContain;
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * @module echarts/core/BoundingRect
+ */
+
+
+ var vec2 = __webpack_require__(10);
+ var matrix = __webpack_require__(11);
+
+ var v2ApplyTransform = vec2.applyTransform;
+ var mathMin = Math.min;
+ var mathMax = Math.max;
+ /**
+ * @alias module:echarts/core/BoundingRect
+ */
+ function BoundingRect(x, y, width, height) {
+
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+
+ /**
+ * @type {number}
+ */
+ this.x = x;
+ /**
+ * @type {number}
+ */
+ this.y = y;
+ /**
+ * @type {number}
+ */
+ this.width = width;
+ /**
+ * @type {number}
+ */
+ this.height = height;
+ }
+
+ BoundingRect.prototype = {
+
+ constructor: BoundingRect,
+
+ /**
+ * @param {module:echarts/core/BoundingRect} other
+ */
+ union: function (other) {
+ var x = mathMin(other.x, this.x);
+ var y = mathMin(other.y, this.y);
+
+ this.width = mathMax(
+ other.x + other.width,
+ this.x + this.width
+ ) - x;
+ this.height = mathMax(
+ other.y + other.height,
+ this.y + this.height
+ ) - y;
+ this.x = x;
+ this.y = y;
+ },
+
+ /**
+ * @param {Array.} m
+ * @methods
+ */
+ applyTransform: (function () {
+ var lt = [];
+ var rb = [];
+ var lb = [];
+ var rt = [];
+ return function (m) {
+ // In case usage like this
+ // el.getBoundingRect().applyTransform(el.transform)
+ // And element has no transform
+ if (!m) {
+ return;
+ }
+ lt[0] = lb[0] = this.x;
+ lt[1] = rt[1] = this.y;
+ rb[0] = rt[0] = this.x + this.width;
+ rb[1] = lb[1] = this.y + this.height;
+
+ v2ApplyTransform(lt, lt, m);
+ v2ApplyTransform(rb, rb, m);
+ v2ApplyTransform(lb, lb, m);
+ v2ApplyTransform(rt, rt, m);
+
+ this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);
+ this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);
+ var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);
+ var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);
+ this.width = maxX - this.x;
+ this.height = maxY - this.y;
+ };
+ })(),
+
+ /**
+ * Calculate matrix of transforming from self to target rect
+ * @param {module:zrender/core/BoundingRect} b
+ * @return {Array.}
+ */
+ calculateTransform: function (b) {
+ var a = this;
+ var sx = b.width / a.width;
+ var sy = b.height / a.height;
+
+ var m = matrix.create();
+
+ // 矩阵右乘
+ matrix.translate(m, m, [-a.x, -a.y]);
+ matrix.scale(m, m, [sx, sy]);
+ matrix.translate(m, m, [b.x, b.y]);
+
+ return m;
+ },
+
+ /**
+ * @param {(module:echarts/core/BoundingRect|Object)} b
+ * @return {boolean}
+ */
+ intersect: function (b) {
+ if (!b) {
+ return false;
+ }
+
+ if (!(b instanceof BoundingRect)) {
+ // Normalize negative width/height.
+ b = BoundingRect.create(b);
+ }
+
+ var a = this;
+ var ax0 = a.x;
+ var ax1 = a.x + a.width;
+ var ay0 = a.y;
+ var ay1 = a.y + a.height;
+
+ var bx0 = b.x;
+ var bx1 = b.x + b.width;
+ var by0 = b.y;
+ var by1 = b.y + b.height;
+
+ return ! (ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
+ },
+
+ contain: function (x, y) {
+ var rect = this;
+ return x >= rect.x
+ && x <= (rect.x + rect.width)
+ && y >= rect.y
+ && y <= (rect.y + rect.height);
+ },
+
+ /**
+ * @return {module:echarts/core/BoundingRect}
+ */
+ clone: function () {
+ return new BoundingRect(this.x, this.y, this.width, this.height);
+ },
+
+ /**
+ * Copy from another rect
+ */
+ copy: function (other) {
+ this.x = other.x;
+ this.y = other.y;
+ this.width = other.width;
+ this.height = other.height;
+ },
+
+ plain: function () {
+ return {
+ x: this.x,
+ y: this.y,
+ width: this.width,
+ height: this.height
+ };
+ }
+ };
+
+ /**
+ * @param {Object|module:zrender/core/BoundingRect} rect
+ * @param {number} rect.x
+ * @param {number} rect.y
+ * @param {number} rect.width
+ * @param {number} rect.height
+ * @return {module:zrender/core/BoundingRect}
+ */
+ BoundingRect.create = function (rect) {
+ return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
+ };
+
+ module.exports = BoundingRect;
+
+
+/***/ },
+/* 10 */
+/***/ function(module, exports) {
+
+
+ var ArrayCtor = typeof Float32Array === 'undefined'
+ ? Array
+ : Float32Array;
+
+ /**
+ * @typedef {Float32Array|Array.} Vector2
+ */
+ /**
+ * 二维向量类
+ * @exports zrender/tool/vector
+ */
+ var vector = {
+ /**
+ * 创建一个向量
+ * @param {number} [x=0]
+ * @param {number} [y=0]
+ * @return {Vector2}
+ */
+ create: function (x, y) {
+ var out = new ArrayCtor(2);
+ if (x == null) {
+ x = 0;
+ }
+ if (y == null) {
+ y = 0;
+ }
+ out[0] = x;
+ out[1] = y;
+ return out;
+ },
+
+ /**
+ * 复制向量数据
+ * @param {Vector2} out
+ * @param {Vector2} v
+ * @return {Vector2}
+ */
+ copy: function (out, v) {
+ out[0] = v[0];
+ out[1] = v[1];
+ return out;
+ },
+
+ /**
+ * 克隆一个向量
+ * @param {Vector2} v
+ * @return {Vector2}
+ */
+ clone: function (v) {
+ var out = new ArrayCtor(2);
+ out[0] = v[0];
+ out[1] = v[1];
+ return out;
+ },
+
+ /**
+ * 设置向量的两个项
+ * @param {Vector2} out
+ * @param {number} a
+ * @param {number} b
+ * @return {Vector2} 结果
+ */
+ set: function (out, a, b) {
+ out[0] = a;
+ out[1] = b;
+ return out;
+ },
+
+ /**
+ * 向量相加
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ add: function (out, v1, v2) {
+ out[0] = v1[0] + v2[0];
+ out[1] = v1[1] + v2[1];
+ return out;
+ },
+
+ /**
+ * 向量缩放后相加
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ * @param {number} a
+ */
+ scaleAndAdd: function (out, v1, v2, a) {
+ out[0] = v1[0] + v2[0] * a;
+ out[1] = v1[1] + v2[1] * a;
+ return out;
+ },
+
+ /**
+ * 向量相减
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ sub: function (out, v1, v2) {
+ out[0] = v1[0] - v2[0];
+ out[1] = v1[1] - v2[1];
+ return out;
+ },
+
+ /**
+ * 向量长度
+ * @param {Vector2} v
+ * @return {number}
+ */
+ len: function (v) {
+ return Math.sqrt(this.lenSquare(v));
+ },
+
+ /**
+ * 向量长度平方
+ * @param {Vector2} v
+ * @return {number}
+ */
+ lenSquare: function (v) {
+ return v[0] * v[0] + v[1] * v[1];
+ },
+
+ /**
+ * 向量乘法
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ mul: function (out, v1, v2) {
+ out[0] = v1[0] * v2[0];
+ out[1] = v1[1] * v2[1];
+ return out;
+ },
+
+ /**
+ * 向量除法
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ div: function (out, v1, v2) {
+ out[0] = v1[0] / v2[0];
+ out[1] = v1[1] / v2[1];
+ return out;
+ },
+
+ /**
+ * 向量点乘
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ * @return {number}
+ */
+ dot: function (v1, v2) {
+ return v1[0] * v2[0] + v1[1] * v2[1];
+ },
+
+ /**
+ * 向量缩放
+ * @param {Vector2} out
+ * @param {Vector2} v
+ * @param {number} s
+ */
+ scale: function (out, v, s) {
+ out[0] = v[0] * s;
+ out[1] = v[1] * s;
+ return out;
+ },
+
+ /**
+ * 向量归一化
+ * @param {Vector2} out
+ * @param {Vector2} v
+ */
+ normalize: function (out, v) {
+ var d = vector.len(v);
+ if (d === 0) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+ else {
+ out[0] = v[0] / d;
+ out[1] = v[1] / d;
+ }
+ return out;
+ },
+
+ /**
+ * 计算向量间距离
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ * @return {number}
+ */
+ distance: function (v1, v2) {
+ return Math.sqrt(
+ (v1[0] - v2[0]) * (v1[0] - v2[0])
+ + (v1[1] - v2[1]) * (v1[1] - v2[1])
+ );
+ },
+
+ /**
+ * 向量距离平方
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ * @return {number}
+ */
+ distanceSquare: function (v1, v2) {
+ return (v1[0] - v2[0]) * (v1[0] - v2[0])
+ + (v1[1] - v2[1]) * (v1[1] - v2[1]);
+ },
+
+ /**
+ * 求负向量
+ * @param {Vector2} out
+ * @param {Vector2} v
+ */
+ negate: function (out, v) {
+ out[0] = -v[0];
+ out[1] = -v[1];
+ return out;
+ },
+
+ /**
+ * 插值两个点
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ * @param {number} t
+ */
+ lerp: function (out, v1, v2, t) {
+ out[0] = v1[0] + t * (v2[0] - v1[0]);
+ out[1] = v1[1] + t * (v2[1] - v1[1]);
+ return out;
+ },
+
+ /**
+ * 矩阵左乘向量
+ * @param {Vector2} out
+ * @param {Vector2} v
+ * @param {Vector2} m
+ */
+ applyTransform: function (out, v, m) {
+ var x = v[0];
+ var y = v[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+ },
+ /**
+ * 求两个向量最小值
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ min: function (out, v1, v2) {
+ out[0] = Math.min(v1[0], v2[0]);
+ out[1] = Math.min(v1[1], v2[1]);
+ return out;
+ },
+ /**
+ * 求两个向量最大值
+ * @param {Vector2} out
+ * @param {Vector2} v1
+ * @param {Vector2} v2
+ */
+ max: function (out, v1, v2) {
+ out[0] = Math.max(v1[0], v2[0]);
+ out[1] = Math.max(v1[1], v2[1]);
+ return out;
+ }
+ };
+
+ vector.length = vector.len;
+ vector.lengthSquare = vector.lenSquare;
+ vector.dist = vector.distance;
+ vector.distSquare = vector.distanceSquare;
+
+ module.exports = vector;
+
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports) {
+
+
+ var ArrayCtor = typeof Float32Array === 'undefined'
+ ? Array
+ : Float32Array;
+ /**
+ * 3x2矩阵操作类
+ * @exports zrender/tool/matrix
+ */
+ var matrix = {
+ /**
+ * 创建一个单位矩阵
+ * @return {Float32Array|Array.}
+ */
+ create : function() {
+ var out = new ArrayCtor(6);
+ matrix.identity(out);
+
+ return out;
+ },
+ /**
+ * 设置矩阵为单位矩阵
+ * @param {Float32Array|Array.} out
+ */
+ identity : function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+ },
+ /**
+ * 复制矩阵
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} m
+ */
+ copy: function(out, m) {
+ out[0] = m[0];
+ out[1] = m[1];
+ out[2] = m[2];
+ out[3] = m[3];
+ out[4] = m[4];
+ out[5] = m[5];
+ return out;
+ },
+ /**
+ * 矩阵相乘
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} m1
+ * @param {Float32Array|Array.} m2
+ */
+ mul : function (out, m1, m2) {
+ // Consider matrix.mul(m, m2, m);
+ // where out is the same as m2.
+ // So use temp variable to escape error.
+ var out0 = m1[0] * m2[0] + m1[2] * m2[1];
+ var out1 = m1[1] * m2[0] + m1[3] * m2[1];
+ var out2 = m1[0] * m2[2] + m1[2] * m2[3];
+ var out3 = m1[1] * m2[2] + m1[3] * m2[3];
+ var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
+ var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
+ out[0] = out0;
+ out[1] = out1;
+ out[2] = out2;
+ out[3] = out3;
+ out[4] = out4;
+ out[5] = out5;
+ return out;
+ },
+ /**
+ * 平移变换
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} a
+ * @param {Float32Array|Array.} v
+ */
+ translate : function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+ },
+ /**
+ * 旋转变换
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} a
+ * @param {number} rad
+ */
+ rotate : function(out, a, rad) {
+ var aa = a[0];
+ var ac = a[2];
+ var atx = a[4];
+ var ab = a[1];
+ var ad = a[3];
+ var aty = a[5];
+ var st = Math.sin(rad);
+ var ct = Math.cos(rad);
+
+ out[0] = aa * ct + ab * st;
+ out[1] = -aa * st + ab * ct;
+ out[2] = ac * ct + ad * st;
+ out[3] = -ac * st + ct * ad;
+ out[4] = ct * atx + st * aty;
+ out[5] = ct * aty - st * atx;
+ return out;
+ },
+ /**
+ * 缩放变换
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} a
+ * @param {Float32Array|Array.} v
+ */
+ scale : function(out, a, v) {
+ var vx = v[0];
+ var vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+ },
+ /**
+ * 求逆矩阵
+ * @param {Float32Array|Array.} out
+ * @param {Float32Array|Array.} a
+ */
+ invert : function(out, a) {
+
+ var aa = a[0];
+ var ac = a[2];
+ var atx = a[4];
+ var ab = a[1];
+ var ad = a[3];
+ var aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+ }
+ };
+
+ module.exports = matrix;
+
+
+
+/***/ },
+/* 12 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @module echarts/model/Model
+ */
+
+
+ var zrUtil = __webpack_require__(4);
+ var clazzUtil = __webpack_require__(13);
+ var env = __webpack_require__(2);
+
+ /**
+ * @alias module:echarts/model/Model
+ * @constructor
+ * @param {Object} option
+ * @param {module:echarts/model/Model} [parentModel]
+ * @param {module:echarts/model/Global} [ecModel]
+ */
+ function Model(option, parentModel, ecModel) {
+ /**
+ * @type {module:echarts/model/Model}
+ * @readOnly
+ */
+ this.parentModel = parentModel;
+
+ /**
+ * @type {module:echarts/model/Global}
+ * @readOnly
+ */
+ this.ecModel = ecModel;
+
+ /**
+ * @type {Object}
+ * @protected
+ */
+ this.option = option;
+
+ // Simple optimization
+ // if (this.init) {
+ // if (arguments.length <= 4) {
+ // this.init(option, parentModel, ecModel, extraOpt);
+ // }
+ // else {
+ // this.init.apply(this, arguments);
+ // }
+ // }
+ }
+
+ Model.prototype = {
+
+ constructor: Model,
+
+ /**
+ * Model 的初始化函数
+ * @param {Object} option
+ */
+ init: null,
+
+ /**
+ * 从新的 Option merge
+ */
+ mergeOption: function (option) {
+ zrUtil.merge(this.option, option, true);
+ },
+
+ /**
+ * @param {string|Array.} path
+ * @param {boolean} [ignoreParent=false]
+ * @return {*}
+ */
+ get: function (path, ignoreParent) {
+ if (path == null) {
+ return this.option;
+ }
+
+ return doGet(
+ this.option,
+ this.parsePath(path),
+ !ignoreParent && getParent(this, path)
+ );
+ },
+
+ /**
+ * @param {string} key
+ * @param {boolean} [ignoreParent=false]
+ * @return {*}
+ */
+ getShallow: function (key, ignoreParent) {
+ var option = this.option;
+
+ var val = option == null ? option : option[key];
+ var parentModel = !ignoreParent && getParent(this, key);
+ if (val == null && parentModel) {
+ val = parentModel.getShallow(key);
+ }
+ return val;
+ },
+
+ /**
+ * @param {string|Array.} [path]
+ * @param {module:echarts/model/Model} [parentModel]
+ * @return {module:echarts/model/Model}
+ */
+ getModel: function (path, parentModel) {
+ var obj = path == null
+ ? this.option
+ : doGet(this.option, path = this.parsePath(path));
+
+ var thisParentModel;
+ parentModel = parentModel || (
+ (thisParentModel = getParent(this, path))
+ && thisParentModel.getModel(path)
+ );
+
+ return new Model(obj, parentModel, this.ecModel);
+ },
+
+ /**
+ * If model has option
+ */
+ isEmpty: function () {
+ return this.option == null;
+ },
+
+ restoreData: function () {},
+
+ // Pending
+ clone: function () {
+ var Ctor = this.constructor;
+ return new Ctor(zrUtil.clone(this.option));
+ },
+
+ setReadOnly: function (properties) {
+ clazzUtil.setReadOnly(this, properties);
+ },
+
+ // If path is null/undefined, return null/undefined.
+ parsePath: function(path) {
+ if (typeof path === 'string') {
+ path = path.split('.');
+ }
+ return path;
+ },
+
+ /**
+ * @param {Function} getParentMethod
+ * param {Array.|string} path
+ * return {module:echarts/model/Model}
+ */
+ customizeGetParent: function (getParentMethod) {
+ clazzUtil.set(this, 'getParent', getParentMethod);
+ },
+
+ isAnimationEnabled: function () {
+ if (!env.node) {
+ if (this.option.animation != null) {
+ return !!this.option.animation;
+ }
+ else if (this.parentModel) {
+ return this.parentModel.isAnimationEnabled();
+ }
+ }
+ }
+ };
+
+ function doGet(obj, pathArr, parentModel) {
+ for (var i = 0; i < pathArr.length; i++) {
+ // Ignore empty
+ if (!pathArr[i]) {
+ continue;
+ }
+ // obj could be number/string/... (like 0)
+ obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;
+ if (obj == null) {
+ break;
+ }
+ }
+ if (obj == null && parentModel) {
+ obj = parentModel.get(pathArr);
+ }
+ return obj;
+ }
+
+ // `path` can be null/undefined
+ function getParent(model, path) {
+ var getParentMethod = clazzUtil.get(model, 'getParent');
+ return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;
+ }
+
+ // Enable Model.extend.
+ clazzUtil.enableClassExtend(Model);
+
+ var mixin = zrUtil.mixin;
+ mixin(Model, __webpack_require__(14));
+ mixin(Model, __webpack_require__(16));
+ mixin(Model, __webpack_require__(17));
+ mixin(Model, __webpack_require__(68));
+
+ module.exports = Model;
+
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var clazz = {};
+
+ var TYPE_DELIMITER = '.';
+ var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
+ var MEMBER_PRIFIX = '\0ec_\0';
+
+ /**
+ * Hide private class member.
+ * The same behavior as `host[name] = value;` (can be right-value)
+ * @public
+ */
+ clazz.set = function (host, name, value) {
+ return (host[MEMBER_PRIFIX + name] = value);
+ };
+
+ /**
+ * Hide private class member.
+ * The same behavior as `host[name];`
+ * @public
+ */
+ clazz.get = function (host, name) {
+ return host[MEMBER_PRIFIX + name];
+ };
+
+ /**
+ * For hidden private class member.
+ * The same behavior as `host.hasOwnProperty(name);`
+ * @public
+ */
+ clazz.hasOwn = function (host, name) {
+ return host.hasOwnProperty(MEMBER_PRIFIX + name);
+ };
+
+ /**
+ * Notice, parseClassType('') should returns {main: '', sub: ''}
+ * @public
+ */
+ var parseClassType = clazz.parseClassType = function (componentType) {
+ var ret = {main: '', sub: ''};
+ if (componentType) {
+ componentType = componentType.split(TYPE_DELIMITER);
+ ret.main = componentType[0] || '';
+ ret.sub = componentType[1] || '';
+ }
+ return ret;
+ };
+
+ /**
+ * @public
+ */
+ function checkClassType(componentType) {
+ zrUtil.assert(
+ /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),
+ 'componentType "' + componentType + '" illegal'
+ );
+ }
+
+ /**
+ * @public
+ */
+ clazz.enableClassExtend = function (RootClass, mandatoryMethods) {
+
+ RootClass.$constructor = RootClass;
+ RootClass.extend = function (proto) {
+
+ if (true) {
+ zrUtil.each(mandatoryMethods, function (method) {
+ if (!proto[method]) {
+ console.warn(
+ 'Method `' + method + '` should be implemented'
+ + (proto.type ? ' in ' + proto.type : '') + '.'
+ );
+ }
+ });
+ }
+
+ var superClass = this;
+ var ExtendedClass = function () {
+ if (!proto.$constructor) {
+ superClass.apply(this, arguments);
+ }
+ else {
+ proto.$constructor.apply(this, arguments);
+ }
+ };
+
+ zrUtil.extend(ExtendedClass.prototype, proto);
+
+ ExtendedClass.extend = this.extend;
+ ExtendedClass.superCall = superCall;
+ ExtendedClass.superApply = superApply;
+ zrUtil.inherits(ExtendedClass, this);
+ ExtendedClass.superClass = superClass;
+
+ return ExtendedClass;
+ };
+ };
+
+ // superCall should have class info, which can not be fetch from 'this'.
+ // Consider this case:
+ // class A has method f,
+ // class B inherits class A, overrides method f, f call superApply('f'),
+ // class C inherits class B, do not overrides method f,
+ // then when method of class C is called, dead loop occured.
+ function superCall(context, methodName) {
+ var args = zrUtil.slice(arguments, 2);
+ return this.superClass.prototype[methodName].apply(context, args);
+ }
+
+ function superApply(context, methodName, args) {
+ return this.superClass.prototype[methodName].apply(context, args);
+ }
+
+ /**
+ * @param {Object} entity
+ * @param {Object} options
+ * @param {boolean} [options.registerWhenExtend]
+ * @public
+ */
+ clazz.enableClassManagement = function (entity, options) {
+ options = options || {};
+
+ /**
+ * Component model classes
+ * key: componentType,
+ * value:
+ * componentClass, when componentType is 'xxx'
+ * or Object., when componentType is 'xxx.yy'
+ * @type {Object}
+ */
+ var storage = {};
+
+ entity.registerClass = function (Clazz, componentType) {
+ if (componentType) {
+ checkClassType(componentType);
+ componentType = parseClassType(componentType);
+
+ if (!componentType.sub) {
+ if (true) {
+ if (storage[componentType.main]) {
+ console.warn(componentType.main + ' exists.');
+ }
+ }
+ storage[componentType.main] = Clazz;
+ }
+ else if (componentType.sub !== IS_CONTAINER) {
+ var container = makeContainer(componentType);
+ container[componentType.sub] = Clazz;
+ }
+ }
+ return Clazz;
+ };
+
+ entity.getClass = function (componentMainType, subType, throwWhenNotFound) {
+ var Clazz = storage[componentMainType];
+
+ if (Clazz && Clazz[IS_CONTAINER]) {
+ Clazz = subType ? Clazz[subType] : null;
+ }
+
+ if (throwWhenNotFound && !Clazz) {
+ throw new Error(
+ !subType
+ ? componentMainType + '.' + 'type should be specified.'
+ : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'
+ );
+ }
+
+ return Clazz;
+ };
+
+ entity.getClassesByMainType = function (componentType) {
+ componentType = parseClassType(componentType);
+
+ var result = [];
+ var obj = storage[componentType.main];
+
+ if (obj && obj[IS_CONTAINER]) {
+ zrUtil.each(obj, function (o, type) {
+ type !== IS_CONTAINER && result.push(o);
+ });
+ }
+ else {
+ result.push(obj);
+ }
+
+ return result;
+ };
+
+ entity.hasClass = function (componentType) {
+ // Just consider componentType.main.
+ componentType = parseClassType(componentType);
+ return !!storage[componentType.main];
+ };
+
+ /**
+ * @return {Array.} Like ['aa', 'bb'], but can not be ['aa.xx']
+ */
+ entity.getAllClassMainTypes = function () {
+ var types = [];
+ zrUtil.each(storage, function (obj, type) {
+ types.push(type);
+ });
+ return types;
+ };
+
+ /**
+ * If a main type is container and has sub types
+ * @param {string} mainType
+ * @return {boolean}
+ */
+ entity.hasSubTypes = function (componentType) {
+ componentType = parseClassType(componentType);
+ var obj = storage[componentType.main];
+ return obj && obj[IS_CONTAINER];
+ };
+
+ entity.parseClassType = parseClassType;
+
+ function makeContainer(componentType) {
+ var container = storage[componentType.main];
+ if (!container || !container[IS_CONTAINER]) {
+ container = storage[componentType.main] = {};
+ container[IS_CONTAINER] = true;
+ }
+ return container;
+ }
+
+ if (options.registerWhenExtend) {
+ var originalExtend = entity.extend;
+ if (originalExtend) {
+ entity.extend = function (proto) {
+ var ExtendedClass = originalExtend.call(this, proto);
+ return entity.registerClass(ExtendedClass, proto.type);
+ };
+ }
+ }
+
+ return entity;
+ };
+
+ /**
+ * @param {string|Array.} properties
+ */
+ clazz.setReadOnly = function (obj, properties) {
+ // FIXME It seems broken in IE8 simulation of IE11
+ // if (!zrUtil.isArray(properties)) {
+ // properties = properties != null ? [properties] : [];
+ // }
+ // zrUtil.each(properties, function (prop) {
+ // var value = obj[prop];
+
+ // Object.defineProperty
+ // && Object.defineProperty(obj, prop, {
+ // value: value, writable: false
+ // });
+ // zrUtil.isArray(obj[prop])
+ // && Object.freeze
+ // && Object.freeze(obj[prop]);
+ // });
+ };
+
+ module.exports = clazz;
+
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ var getLineStyle = __webpack_require__(15)(
+ [
+ ['lineWidth', 'width'],
+ ['stroke', 'color'],
+ ['opacity'],
+ ['shadowBlur'],
+ ['shadowOffsetX'],
+ ['shadowOffsetY'],
+ ['shadowColor']
+ ]
+ );
+ module.exports = {
+ getLineStyle: function (excludes) {
+ var style = getLineStyle.call(this, excludes);
+ var lineDash = this.getLineDash(style.lineWidth);
+ lineDash && (style.lineDash = lineDash);
+ return style;
+ },
+
+ getLineDash: function (lineWidth) {
+ if (lineWidth == null) {
+ lineWidth = 1;
+ }
+ var lineType = this.get('type');
+ var dotSize = Math.max(lineWidth, 2);
+ var dashSize = lineWidth * 4;
+ return (lineType === 'solid' || lineType == null) ? null
+ : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);
+ }
+ };
+
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // TODO Parse shadow style
+ // TODO Only shallow path support
+
+ var zrUtil = __webpack_require__(4);
+
+ module.exports = function (properties) {
+ // Normalize
+ for (var i = 0; i < properties.length; i++) {
+ if (!properties[i][1]) {
+ properties[i][1] = properties[i][0];
+ }
+ }
+ return function (excludes, includes) {
+ var style = {};
+ for (var i = 0; i < properties.length; i++) {
+ var propName = properties[i][1];
+ if ((excludes && zrUtil.indexOf(excludes, propName) >= 0)
+ || (includes && zrUtil.indexOf(includes, propName) < 0)
+ ) {
+ continue;
+ }
+ var val = this.getShallow(propName);
+ if (val != null) {
+ style[properties[i][0]] = val;
+ }
+ }
+ return style;
+ };
+ };
+
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ module.exports = {
+ getAreaStyle: __webpack_require__(15)(
+ [
+ ['fill', 'color'],
+ ['shadowBlur'],
+ ['shadowOffsetX'],
+ ['shadowOffsetY'],
+ ['opacity'],
+ ['shadowColor']
+ ]
+ )
+ };
+
+
+/***/ },
+/* 17 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var textContain = __webpack_require__(8);
+ var graphicUtil = __webpack_require__(18);
+
+ module.exports = {
+ /**
+ * Get color property or get color from option.textStyle.color
+ * @return {string}
+ */
+ getTextColor: function () {
+ var ecModel = this.ecModel;
+ return this.getShallow('color')
+ || (ecModel && ecModel.get('textStyle.color'));
+ },
+
+ /**
+ * Create font string from fontStyle, fontWeight, fontSize, fontFamily
+ * @return {string}
+ */
+ getFont: function () {
+ return graphicUtil.getFont({
+ fontStyle: this.getShallow('fontStyle'),
+ fontWeight: this.getShallow('fontWeight'),
+ fontSize: this.getShallow('fontSize'),
+ fontFamily: this.getShallow('fontFamily')
+ }, this.ecModel);
+ },
+
+ getTextRect: function (text) {
+ return textContain.getBoundingRect(
+ text,
+ this.getFont(),
+ this.getShallow('align'),
+ this.getShallow('baseline')
+ );
+ },
+
+ truncateText: function (text, containerWidth, ellipsis, options) {
+ return textContain.truncateText(
+ text, containerWidth, this.getFont(), ellipsis, options
+ );
+ }
+ };
+
+
+/***/ },
+/* 18 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var pathTool = __webpack_require__(19);
+ var Path = __webpack_require__(20);
+ var colorTool = __webpack_require__(31);
+ var matrix = __webpack_require__(11);
+ var vector = __webpack_require__(10);
+ var Transformable = __webpack_require__(26);
+ var BoundingRect = __webpack_require__(9);
+
+ var round = Math.round;
+ var mathMax = Math.max;
+ var mathMin = Math.min;
+
+ var graphic = {};
+
+ graphic.Group = __webpack_require__(48);
+
+ graphic.Image = __webpack_require__(49);
+
+ graphic.Text = __webpack_require__(50);
+
+ graphic.Circle = __webpack_require__(51);
+
+ graphic.Sector = __webpack_require__(52);
+
+ graphic.Ring = __webpack_require__(53);
+
+ graphic.Polygon = __webpack_require__(54);
+
+ graphic.Polyline = __webpack_require__(58);
+
+ graphic.Rect = __webpack_require__(59);
+
+ graphic.Line = __webpack_require__(61);
+
+ graphic.BezierCurve = __webpack_require__(62);
+
+ graphic.Arc = __webpack_require__(63);
+
+ graphic.CompoundPath = __webpack_require__(64);
+
+ graphic.LinearGradient = __webpack_require__(65);
+
+ graphic.RadialGradient = __webpack_require__(67);
+
+ graphic.BoundingRect = BoundingRect;
+
+ /**
+ * Extend shape with parameters
+ */
+ graphic.extendShape = function (opts) {
+ return Path.extend(opts);
+ };
+
+ /**
+ * Extend path
+ */
+ graphic.extendPath = function (pathData, opts) {
+ return pathTool.extendFromString(pathData, opts);
+ };
+
+ /**
+ * Create a path element from path data string
+ * @param {string} pathData
+ * @param {Object} opts
+ * @param {module:zrender/core/BoundingRect} rect
+ * @param {string} [layout=cover] 'center' or 'cover'
+ */
+ graphic.makePath = function (pathData, opts, rect, layout) {
+ var path = pathTool.createFromString(pathData, opts);
+ var boundingRect = path.getBoundingRect();
+ if (rect) {
+ var aspect = boundingRect.width / boundingRect.height;
+
+ if (layout === 'center') {
+ // Set rect to center, keep width / height ratio.
+ var width = rect.height * aspect;
+ var height;
+ if (width <= rect.width) {
+ height = rect.height;
+ }
+ else {
+ width = rect.width;
+ height = width / aspect;
+ }
+ var cx = rect.x + rect.width / 2;
+ var cy = rect.y + rect.height / 2;
+
+ rect.x = cx - width / 2;
+ rect.y = cy - height / 2;
+ rect.width = width;
+ rect.height = height;
+ }
+
+ graphic.resizePath(path, rect);
+ }
+ return path;
+ };
+
+ graphic.mergePath = pathTool.mergePath,
+
+ /**
+ * Resize a path to fit the rect
+ * @param {module:zrender/graphic/Path} path
+ * @param {Object} rect
+ */
+ graphic.resizePath = function (path, rect) {
+ if (!path.applyTransform) {
+ return;
+ }
+
+ var pathRect = path.getBoundingRect();
+
+ var m = pathRect.calculateTransform(rect);
+
+ path.applyTransform(m);
+ };
+
+ /**
+ * Sub pixel optimize line for canvas
+ *
+ * @param {Object} param
+ * @param {Object} [param.shape]
+ * @param {number} [param.shape.x1]
+ * @param {number} [param.shape.y1]
+ * @param {number} [param.shape.x2]
+ * @param {number} [param.shape.y2]
+ * @param {Object} [param.style]
+ * @param {number} [param.style.lineWidth]
+ * @return {Object} Modified param
+ */
+ graphic.subPixelOptimizeLine = function (param) {
+ var subPixelOptimize = graphic.subPixelOptimize;
+ var shape = param.shape;
+ var lineWidth = param.style.lineWidth;
+
+ if (round(shape.x1 * 2) === round(shape.x2 * 2)) {
+ shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);
+ }
+ if (round(shape.y1 * 2) === round(shape.y2 * 2)) {
+ shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);
+ }
+ return param;
+ };
+
+ /**
+ * Sub pixel optimize rect for canvas
+ *
+ * @param {Object} param
+ * @param {Object} [param.shape]
+ * @param {number} [param.shape.x]
+ * @param {number} [param.shape.y]
+ * @param {number} [param.shape.width]
+ * @param {number} [param.shape.height]
+ * @param {Object} [param.style]
+ * @param {number} [param.style.lineWidth]
+ * @return {Object} Modified param
+ */
+ graphic.subPixelOptimizeRect = function (param) {
+ var subPixelOptimize = graphic.subPixelOptimize;
+ var shape = param.shape;
+ var lineWidth = param.style.lineWidth;
+ var originX = shape.x;
+ var originY = shape.y;
+ var originWidth = shape.width;
+ var originHeight = shape.height;
+ shape.x = subPixelOptimize(shape.x, lineWidth, true);
+ shape.y = subPixelOptimize(shape.y, lineWidth, true);
+ shape.width = Math.max(
+ subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,
+ originWidth === 0 ? 0 : 1
+ );
+ shape.height = Math.max(
+ subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,
+ originHeight === 0 ? 0 : 1
+ );
+ return param;
+ };
+
+ /**
+ * Sub pixel optimize for canvas
+ *
+ * @param {number} position Coordinate, such as x, y
+ * @param {number} lineWidth Should be nonnegative integer.
+ * @param {boolean=} positiveOrNegative Default false (negative).
+ * @return {number} Optimized position.
+ */
+ graphic.subPixelOptimize = function (position, lineWidth, positiveOrNegative) {
+ // Assure that (position + lineWidth / 2) is near integer edge,
+ // otherwise line will be fuzzy in canvas.
+ var doubledPosition = round(position * 2);
+ return (doubledPosition + round(lineWidth)) % 2 === 0
+ ? doubledPosition / 2
+ : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;
+ };
+
+ function hasFillOrStroke(fillOrStroke) {
+ return fillOrStroke != null && fillOrStroke != 'none';
+ }
+
+ function liftColor(color) {
+ return typeof color === 'string' ? colorTool.lift(color, -0.1) : color;
+ }
+
+ /**
+ * @private
+ */
+ function cacheElementStl(el) {
+ if (el.__hoverStlDirty) {
+ var stroke = el.style.stroke;
+ var fill = el.style.fill;
+
+ // Create hoverStyle on mouseover
+ var hoverStyle = el.__hoverStl;
+ hoverStyle.fill = hoverStyle.fill
+ || (hasFillOrStroke(fill) ? liftColor(fill) : null);
+ hoverStyle.stroke = hoverStyle.stroke
+ || (hasFillOrStroke(stroke) ? liftColor(stroke) : null);
+
+ var normalStyle = {};
+ for (var name in hoverStyle) {
+ if (hoverStyle.hasOwnProperty(name)) {
+ normalStyle[name] = el.style[name];
+ }
+ }
+
+ el.__normalStl = normalStyle;
+
+ el.__hoverStlDirty = false;
+ }
+ }
+
+ /**
+ * @private
+ */
+ function doSingleEnterHover(el) {
+ if (el.__isHover) {
+ return;
+ }
+
+ cacheElementStl(el);
+
+ if (el.useHoverLayer) {
+ el.__zr && el.__zr.addHover(el, el.__hoverStl);
+ }
+ else {
+ el.setStyle(el.__hoverStl);
+ el.z2 += 1;
+ }
+
+ el.__isHover = true;
+ }
+
+ /**
+ * @inner
+ */
+ function doSingleLeaveHover(el) {
+ if (!el.__isHover) {
+ return;
+ }
+
+ var normalStl = el.__normalStl;
+ if (el.useHoverLayer) {
+ el.__zr && el.__zr.removeHover(el);
+ }
+ else {
+ normalStl && el.setStyle(normalStl);
+ el.z2 -= 1;
+ }
+
+ el.__isHover = false;
+ }
+
+ /**
+ * @inner
+ */
+ function doEnterHover(el) {
+ el.type === 'group'
+ ? el.traverse(function (child) {
+ if (child.type !== 'group') {
+ doSingleEnterHover(child);
+ }
+ })
+ : doSingleEnterHover(el);
+ }
+
+ function doLeaveHover(el) {
+ el.type === 'group'
+ ? el.traverse(function (child) {
+ if (child.type !== 'group') {
+ doSingleLeaveHover(child);
+ }
+ })
+ : doSingleLeaveHover(el);
+ }
+
+ /**
+ * @inner
+ */
+ function setElementHoverStl(el, hoverStl) {
+ // If element has sepcified hoverStyle, then use it instead of given hoverStyle
+ // Often used when item group has a label element and it's hoverStyle is different
+ el.__hoverStl = el.hoverStyle || hoverStl || {};
+ el.__hoverStlDirty = true;
+
+ if (el.__isHover) {
+ cacheElementStl(el);
+ }
+ }
+
+ /**
+ * @inner
+ */
+ function onElementMouseOver(e) {
+ if (this.__hoverSilentOnTouch && e.zrByTouch) {
+ return;
+ }
+
+ // Only if element is not in emphasis status
+ !this.__isEmphasis && doEnterHover(this);
+ }
+
+ /**
+ * @inner
+ */
+ function onElementMouseOut(e) {
+ if (this.__hoverSilentOnTouch && e.zrByTouch) {
+ return;
+ }
+
+ // Only if element is not in emphasis status
+ !this.__isEmphasis && doLeaveHover(this);
+ }
+
+ /**
+ * @inner
+ */
+ function enterEmphasis() {
+ this.__isEmphasis = true;
+ doEnterHover(this);
+ }
+
+ /**
+ * @inner
+ */
+ function leaveEmphasis() {
+ this.__isEmphasis = false;
+ doLeaveHover(this);
+ }
+
+ /**
+ * Set hover style of element.
+ * This method can be called repeatly without side-effects.
+ * @param {module:zrender/Element} el
+ * @param {Object} [hoverStyle]
+ * @param {Object} [opt]
+ * @param {boolean} [opt.hoverSilentOnTouch=false]
+ * In touch device, mouseover event will be trigger on touchstart event
+ * (see module:zrender/dom/HandlerProxy). By this mechanism, we can
+ * conviniently use hoverStyle when tap on touch screen without additional
+ * code for compatibility.
+ * But if the chart/component has select feature, which usually also use
+ * hoverStyle, there might be conflict between 'select-highlight' and
+ * 'hover-highlight' especially when roam is enabled (see geo for example).
+ * In this case, hoverSilentOnTouch should be used to disable hover-highlight
+ * on touch device.
+ */
+ graphic.setHoverStyle = function (el, hoverStyle, opt) {
+ el.__hoverSilentOnTouch = opt && opt.hoverSilentOnTouch;
+
+ el.type === 'group'
+ ? el.traverse(function (child) {
+ if (child.type !== 'group') {
+ setElementHoverStl(child, hoverStyle);
+ }
+ })
+ : setElementHoverStl(el, hoverStyle);
+
+ // Duplicated function will be auto-ignored, see Eventful.js.
+ el.on('mouseover', onElementMouseOver)
+ .on('mouseout', onElementMouseOut);
+
+ // Emphasis, normal can be triggered manually
+ el.on('emphasis', enterEmphasis)
+ .on('normal', leaveEmphasis);
+ };
+
+ /**
+ * Set text option in the style
+ * @param {Object} textStyle
+ * @param {module:echarts/model/Model} labelModel
+ * @param {string} color
+ */
+ graphic.setText = function (textStyle, labelModel, color) {
+ var labelPosition = labelModel.getShallow('position') || 'inside';
+ var labelOffset = labelModel.getShallow('offset');
+ var labelColor = labelPosition.indexOf('inside') >= 0 ? 'white' : color;
+ var textStyleModel = labelModel.getModel('textStyle');
+ zrUtil.extend(textStyle, {
+ textDistance: labelModel.getShallow('distance') || 5,
+ textFont: textStyleModel.getFont(),
+ textPosition: labelPosition,
+ textOffset: labelOffset,
+ textFill: textStyleModel.getTextColor() || labelColor
+ });
+ };
+
+ graphic.getFont = function (opt, ecModel) {
+ var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
+ return [
+ // FIXME in node-canvas fontWeight is before fontStyle
+ opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',
+ opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',
+ (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',
+ opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'
+ ].join(' ');
+ };
+
+ function animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {
+ if (typeof dataIndex === 'function') {
+ cb = dataIndex;
+ dataIndex = null;
+ }
+ // Do not check 'animation' property directly here. Consider this case:
+ // animation model is an `itemModel`, whose does not have `isAnimationEnabled`
+ // but its parent model (`seriesModel`) does.
+ var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
+
+ if (animationEnabled) {
+ var postfix = isUpdate ? 'Update' : '';
+ var duration = animatableModel.getShallow('animationDuration' + postfix);
+ var animationEasing = animatableModel.getShallow('animationEasing' + postfix);
+ var animationDelay = animatableModel.getShallow('animationDelay' + postfix);
+ if (typeof animationDelay === 'function') {
+ animationDelay = animationDelay(
+ dataIndex,
+ animatableModel.getAnimationDelayParams
+ ? animatableModel.getAnimationDelayParams(el, dataIndex)
+ : null
+ );
+ }
+ if (typeof duration === 'function') {
+ duration = duration(dataIndex);
+ }
+
+ duration > 0
+ ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb)
+ : (el.stopAnimation(), el.attr(props), cb && cb());
+ }
+ else {
+ el.stopAnimation();
+ el.attr(props);
+ cb && cb();
+ }
+ }
+
+ /**
+ * Update graphic element properties with or without animation according to the configuration in series
+ * @param {module:zrender/Element} el
+ * @param {Object} props
+ * @param {module:echarts/model/Model} [animatableModel]
+ * @param {number} [dataIndex]
+ * @param {Function} [cb]
+ * @example
+ * graphic.updateProps(el, {
+ * position: [100, 100]
+ * }, seriesModel, dataIndex, function () { console.log('Animation done!'); });
+ * // Or
+ * graphic.updateProps(el, {
+ * position: [100, 100]
+ * }, seriesModel, function () { console.log('Animation done!'); });
+ */
+ graphic.updateProps = function (el, props, animatableModel, dataIndex, cb) {
+ animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);
+ };
+
+ /**
+ * Init graphic element properties with or without animation according to the configuration in series
+ * @param {module:zrender/Element} el
+ * @param {Object} props
+ * @param {module:echarts/model/Model} [animatableModel]
+ * @param {number} [dataIndex]
+ * @param {Function} cb
+ */
+ graphic.initProps = function (el, props, animatableModel, dataIndex, cb) {
+ animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);
+ };
+
+ /**
+ * Get transform matrix of target (param target),
+ * in coordinate of its ancestor (param ancestor)
+ *
+ * @param {module:zrender/mixin/Transformable} target
+ * @param {module:zrender/mixin/Transformable} [ancestor]
+ */
+ graphic.getTransform = function (target, ancestor) {
+ var mat = matrix.identity([]);
+
+ while (target && target !== ancestor) {
+ matrix.mul(mat, target.getLocalTransform(), mat);
+ target = target.parent;
+ }
+
+ return mat;
+ };
+
+ /**
+ * Apply transform to an vertex.
+ * @param {Array.} target [x, y]
+ * @param {Array.|TypedArray.|Object} transform Can be:
+ * + Transform matrix: like [1, 0, 0, 1, 0, 0]
+ * + {position, rotation, scale}, the same as `zrender/Transformable`.
+ * @param {boolean=} invert Whether use invert matrix.
+ * @return {Array.} [x, y]
+ */
+ graphic.applyTransform = function (target, transform, invert) {
+ if (transform && !zrUtil.isArrayLike(transform)) {
+ transform = Transformable.getLocalTransform(transform);
+ }
+
+ if (invert) {
+ transform = matrix.invert([], transform);
+ }
+ return vector.applyTransform([], target, transform);
+ };
+
+ /**
+ * @param {string} direction 'left' 'right' 'top' 'bottom'
+ * @param {Array.} transform Transform matrix: like [1, 0, 0, 1, 0, 0]
+ * @param {boolean=} invert Whether use invert matrix.
+ * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'
+ */
+ graphic.transformDirection = function (direction, transform, invert) {
+
+ // Pick a base, ensure that transform result will not be (0, 0).
+ var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)
+ ? 1 : Math.abs(2 * transform[4] / transform[0]);
+ var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)
+ ? 1 : Math.abs(2 * transform[4] / transform[2]);
+
+ var vertex = [
+ direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,
+ direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0
+ ];
+
+ vertex = graphic.applyTransform(vertex, transform, invert);
+
+ return Math.abs(vertex[0]) > Math.abs(vertex[1])
+ ? (vertex[0] > 0 ? 'right' : 'left')
+ : (vertex[1] > 0 ? 'bottom' : 'top');
+ };
+
+ /**
+ * Apply group transition animation from g1 to g2.
+ * If no animatableModel, no animation.
+ */
+ graphic.groupTransition = function (g1, g2, animatableModel, cb) {
+ if (!g1 || !g2) {
+ return;
+ }
+
+ function getElMap(g) {
+ var elMap = {};
+ g.traverse(function (el) {
+ if (!el.isGroup && el.anid) {
+ elMap[el.anid] = el;
+ }
+ });
+ return elMap;
+ }
+ function getAnimatableProps(el) {
+ var obj = {
+ position: vector.clone(el.position),
+ rotation: el.rotation
+ };
+ if (el.shape) {
+ obj.shape = zrUtil.extend({}, el.shape);
+ }
+ return obj;
+ }
+ var elMap1 = getElMap(g1);
+
+ g2.traverse(function (el) {
+ if (!el.isGroup && el.anid) {
+ var oldEl = elMap1[el.anid];
+ if (oldEl) {
+ var newProp = getAnimatableProps(el);
+ el.attr(getAnimatableProps(oldEl));
+ graphic.updateProps(el, newProp, animatableModel, el.dataIndex);
+ }
+ // else {
+ // if (el.previousProps) {
+ // graphic.updateProps
+ // }
+ // }
+ }
+ });
+ };
+
+ /**
+ * @param {Array.>} points Like: [[23, 44], [53, 66], ...]
+ * @param {Object} rect {x, y, width, height}
+ * @return {Array.>} A new clipped points.
+ */
+ graphic.clipPointsByRect = function (points, rect) {
+ return zrUtil.map(points, function (point) {
+ var x = point[0];
+ x = mathMax(x, rect.x);
+ x = mathMin(x, rect.x + rect.width);
+ var y = point[1];
+ y = mathMax(y, rect.y);
+ y = mathMin(y, rect.y + rect.height);
+ return [x, y];
+ });
+ };
+
+ /**
+ * @param {Object} targetRect {x, y, width, height}
+ * @param {Object} rect {x, y, width, height}
+ * @return {Object} A new clipped rect. If rect size are negative, return undefined.
+ */
+ graphic.clipRectByRect = function (targetRect, rect) {
+ var x = mathMax(targetRect.x, rect.x);
+ var x2 = mathMin(targetRect.x + targetRect.width, rect.x + rect.width);
+ var y = mathMax(targetRect.y, rect.y);
+ var y2 = mathMin(targetRect.y + targetRect.height, rect.y + rect.height);
+
+ if (x2 >= x && y2 >= y) {
+ return {
+ x: x,
+ y: y,
+ width: x2 - x,
+ height: y2 - y
+ };
+ }
+ };
+
+ module.exports = graphic;
+
+
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var Path = __webpack_require__(20);
+ var PathProxy = __webpack_require__(36);
+ var transformPath = __webpack_require__(47);
+
+ // command chars
+ var cc = [
+ 'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',
+ 'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'
+ ];
+
+ var mathSqrt = Math.sqrt;
+ var mathSin = Math.sin;
+ var mathCos = Math.cos;
+ var PI = Math.PI;
+
+ var vMag = function(v) {
+ return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
+ };
+ var vRatio = function(u, v) {
+ return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
+ };
+ var vAngle = function(u, v) {
+ return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)
+ * Math.acos(vRatio(u, v));
+ };
+
+ function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
+ var psi = psiDeg * (PI / 180.0);
+ var xp = mathCos(psi) * (x1 - x2) / 2.0
+ + mathSin(psi) * (y1 - y2) / 2.0;
+ var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0
+ + mathCos(psi) * (y1 - y2) / 2.0;
+
+ var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
+
+ if (lambda > 1) {
+ rx *= mathSqrt(lambda);
+ ry *= mathSqrt(lambda);
+ }
+
+ var f = (fa === fs ? -1 : 1)
+ * mathSqrt((((rx * rx) * (ry * ry))
+ - ((rx * rx) * (yp * yp))
+ - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)
+ + (ry * ry) * (xp * xp))
+ ) || 0;
+
+ var cxp = f * rx * yp / ry;
+ var cyp = f * -ry * xp / rx;
+
+ var cx = (x1 + x2) / 2.0
+ + mathCos(psi) * cxp
+ - mathSin(psi) * cyp;
+ var cy = (y1 + y2) / 2.0
+ + mathSin(psi) * cxp
+ + mathCos(psi) * cyp;
+
+ var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);
+ var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];
+ var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];
+ var dTheta = vAngle(u, v);
+
+ if (vRatio(u, v) <= -1) {
+ dTheta = PI;
+ }
+ if (vRatio(u, v) >= 1) {
+ dTheta = 0;
+ }
+ if (fs === 0 && dTheta > 0) {
+ dTheta = dTheta - 2 * PI;
+ }
+ if (fs === 1 && dTheta < 0) {
+ dTheta = dTheta + 2 * PI;
+ }
+
+ path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
+ }
+
+ function createPathProxyFromString(data) {
+ if (!data) {
+ return [];
+ }
+
+ // command string
+ var cs = data.replace(/-/g, ' -')
+ .replace(/ /g, ' ')
+ .replace(/ /g, ',')
+ .replace(/,,/g, ',');
+
+ var n;
+ // create pipes so that we can split the data
+ for (n = 0; n < cc.length; n++) {
+ cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
+ }
+
+ // create array
+ var arr = cs.split('|');
+ // init context point
+ var cpx = 0;
+ var cpy = 0;
+
+ var path = new PathProxy();
+ var CMD = PathProxy.CMD;
+
+ var prevCmd;
+ for (n = 1; n < arr.length; n++) {
+ var str = arr[n];
+ var c = str.charAt(0);
+ var off = 0;
+ var p = str.slice(1).replace(/e,-/g, 'e-').split(',');
+ var cmd;
+
+ if (p.length > 0 && p[0] === '') {
+ p.shift();
+ }
+
+ for (var i = 0; i < p.length; i++) {
+ p[i] = parseFloat(p[i]);
+ }
+ while (off < p.length && !isNaN(p[off])) {
+ if (isNaN(p[0])) {
+ break;
+ }
+ var ctlPtx;
+ var ctlPty;
+
+ var rx;
+ var ry;
+ var psi;
+ var fa;
+ var fs;
+
+ var x1 = cpx;
+ var y1 = cpy;
+
+ // convert l, H, h, V, and v to L
+ switch (c) {
+ case 'l':
+ cpx += p[off++];
+ cpy += p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'L':
+ cpx = p[off++];
+ cpy = p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'm':
+ cpx += p[off++];
+ cpy += p[off++];
+ cmd = CMD.M;
+ path.addData(cmd, cpx, cpy);
+ c = 'l';
+ break;
+ case 'M':
+ cpx = p[off++];
+ cpy = p[off++];
+ cmd = CMD.M;
+ path.addData(cmd, cpx, cpy);
+ c = 'L';
+ break;
+ case 'h':
+ cpx += p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'H':
+ cpx = p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'v':
+ cpy += p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'V':
+ cpy = p[off++];
+ cmd = CMD.L;
+ path.addData(cmd, cpx, cpy);
+ break;
+ case 'C':
+ cmd = CMD.C;
+ path.addData(
+ cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]
+ );
+ cpx = p[off - 2];
+ cpy = p[off - 1];
+ break;
+ case 'c':
+ cmd = CMD.C;
+ path.addData(
+ cmd,
+ p[off++] + cpx, p[off++] + cpy,
+ p[off++] + cpx, p[off++] + cpy,
+ p[off++] + cpx, p[off++] + cpy
+ );
+ cpx += p[off - 2];
+ cpy += p[off - 1];
+ break;
+ case 'S':
+ ctlPtx = cpx;
+ ctlPty = cpy;
+ var len = path.len();
+ var pathData = path.data;
+ if (prevCmd === CMD.C) {
+ ctlPtx += cpx - pathData[len - 4];
+ ctlPty += cpy - pathData[len - 3];
+ }
+ cmd = CMD.C;
+ x1 = p[off++];
+ y1 = p[off++];
+ cpx = p[off++];
+ cpy = p[off++];
+ path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
+ break;
+ case 's':
+ ctlPtx = cpx;
+ ctlPty = cpy;
+ var len = path.len();
+ var pathData = path.data;
+ if (prevCmd === CMD.C) {
+ ctlPtx += cpx - pathData[len - 4];
+ ctlPty += cpy - pathData[len - 3];
+ }
+ cmd = CMD.C;
+ x1 = cpx + p[off++];
+ y1 = cpy + p[off++];
+ cpx += p[off++];
+ cpy += p[off++];
+ path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
+ break;
+ case 'Q':
+ x1 = p[off++];
+ y1 = p[off++];
+ cpx = p[off++];
+ cpy = p[off++];
+ cmd = CMD.Q;
+ path.addData(cmd, x1, y1, cpx, cpy);
+ break;
+ case 'q':
+ x1 = p[off++] + cpx;
+ y1 = p[off++] + cpy;
+ cpx += p[off++];
+ cpy += p[off++];
+ cmd = CMD.Q;
+ path.addData(cmd, x1, y1, cpx, cpy);
+ break;
+ case 'T':
+ ctlPtx = cpx;
+ ctlPty = cpy;
+ var len = path.len();
+ var pathData = path.data;
+ if (prevCmd === CMD.Q) {
+ ctlPtx += cpx - pathData[len - 4];
+ ctlPty += cpy - pathData[len - 3];
+ }
+ cpx = p[off++];
+ cpy = p[off++];
+ cmd = CMD.Q;
+ path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
+ break;
+ case 't':
+ ctlPtx = cpx;
+ ctlPty = cpy;
+ var len = path.len();
+ var pathData = path.data;
+ if (prevCmd === CMD.Q) {
+ ctlPtx += cpx - pathData[len - 4];
+ ctlPty += cpy - pathData[len - 3];
+ }
+ cpx += p[off++];
+ cpy += p[off++];
+ cmd = CMD.Q;
+ path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
+ break;
+ case 'A':
+ rx = p[off++];
+ ry = p[off++];
+ psi = p[off++];
+ fa = p[off++];
+ fs = p[off++];
+
+ x1 = cpx, y1 = cpy;
+ cpx = p[off++];
+ cpy = p[off++];
+ cmd = CMD.A;
+ processArc(
+ x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
+ );
+ break;
+ case 'a':
+ rx = p[off++];
+ ry = p[off++];
+ psi = p[off++];
+ fa = p[off++];
+ fs = p[off++];
+
+ x1 = cpx, y1 = cpy;
+ cpx += p[off++];
+ cpy += p[off++];
+ cmd = CMD.A;
+ processArc(
+ x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
+ );
+ break;
+ }
+ }
+
+ if (c === 'z' || c === 'Z') {
+ cmd = CMD.Z;
+ path.addData(cmd);
+ }
+
+ prevCmd = cmd;
+ }
+
+ path.toStatic();
+
+ return path;
+ }
+
+ // TODO Optimize double memory cost problem
+ function createPathOptions(str, opts) {
+ var pathProxy = createPathProxyFromString(str);
+ opts = opts || {};
+ opts.buildPath = function (path) {
+ if (path.setData) {
+ path.setData(pathProxy.data);
+ // Svg and vml renderer don't have context
+ var ctx = path.getContext();
+ if (ctx) {
+ path.rebuildPath(ctx);
+ }
+ }
+ else {
+ var ctx = path;
+ pathProxy.rebuildPath(ctx);
+ }
+ };
+
+ opts.applyTransform = function (m) {
+ transformPath(pathProxy, m);
+
+ this.dirty(true);
+ };
+
+ return opts;
+ }
+
+ module.exports = {
+ /**
+ * Create a Path object from path string data
+ * http://www.w3.org/TR/SVG/paths.html#PathData
+ * @param {Object} opts Other options
+ */
+ createFromString: function (str, opts) {
+ return new Path(createPathOptions(str, opts));
+ },
+
+ /**
+ * Create a Path class from path string data
+ * @param {string} str
+ * @param {Object} opts Other options
+ */
+ extendFromString: function (str, opts) {
+ return Path.extend(createPathOptions(str, opts));
+ },
+
+ /**
+ * Merge multiple paths
+ */
+ // TODO Apply transform
+ // TODO stroke dash
+ // TODO Optimize double memory cost problem
+ mergePath: function (pathEls, opts) {
+ var pathList = [];
+ var len = pathEls.length;
+ for (var i = 0; i < len; i++) {
+ var pathEl = pathEls[i];
+ if (!pathEl.path) {
+ pathEl.createPathProxy();
+ }
+ if (pathEl.__dirtyPath) {
+ pathEl.buildPath(pathEl.path, pathEl.shape, true);
+ }
+ pathList.push(pathEl.path);
+ }
+
+ var pathBundle = new Path(opts);
+ // Need path proxy.
+ pathBundle.createPathProxy();
+ pathBundle.buildPath = function (path) {
+ path.appendPath(pathList);
+ // Svg and vml renderer don't have context
+ var ctx = path.getContext();
+ if (ctx) {
+ path.rebuildPath(ctx);
+ }
+ };
+
+ return pathBundle;
+ }
+ };
+
+
+/***/ },
+/* 20 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Path element
+ * @module zrender/graphic/Path
+ */
+
+
+
+ var Displayable = __webpack_require__(21);
+ var zrUtil = __webpack_require__(4);
+ var PathProxy = __webpack_require__(36);
+ var pathContain = __webpack_require__(39);
+
+ var Pattern = __webpack_require__(46);
+ var getCanvasPattern = Pattern.prototype.getCanvasPattern;
+
+ var abs = Math.abs;
+
+ var pathProxyForDraw = new PathProxy(true);
+ /**
+ * @alias module:zrender/graphic/Path
+ * @extends module:zrender/graphic/Displayable
+ * @constructor
+ * @param {Object} opts
+ */
+ function Path(opts) {
+ Displayable.call(this, opts);
+
+ /**
+ * @type {module:zrender/core/PathProxy}
+ * @readOnly
+ */
+ this.path = null;
+ }
+
+ Path.prototype = {
+
+ constructor: Path,
+
+ type: 'path',
+
+ __dirtyPath: true,
+
+ strokeContainThreshold: 5,
+
+ brush: function (ctx, prevEl) {
+ var style = this.style;
+ var path = this.path || pathProxyForDraw;
+ var hasStroke = style.hasStroke();
+ var hasFill = style.hasFill();
+ var fill = style.fill;
+ var stroke = style.stroke;
+ var hasFillGradient = hasFill && !!(fill.colorStops);
+ var hasStrokeGradient = hasStroke && !!(stroke.colorStops);
+ var hasFillPattern = hasFill && !!(fill.image);
+ var hasStrokePattern = hasStroke && !!(stroke.image);
+
+ style.bind(ctx, this, prevEl);
+ this.setTransform(ctx);
+
+ if (this.__dirty) {
+ var rect;
+ // Update gradient because bounding rect may changed
+ if (hasFillGradient) {
+ rect = rect || this.getBoundingRect();
+ this._fillGradient = style.getGradient(ctx, fill, rect);
+ }
+ if (hasStrokeGradient) {
+ rect = rect || this.getBoundingRect();
+ this._strokeGradient = style.getGradient(ctx, stroke, rect);
+ }
+ }
+ // Use the gradient or pattern
+ if (hasFillGradient) {
+ // PENDING If may have affect the state
+ ctx.fillStyle = this._fillGradient;
+ }
+ else if (hasFillPattern) {
+ ctx.fillStyle = getCanvasPattern.call(fill, ctx);
+ }
+ if (hasStrokeGradient) {
+ ctx.strokeStyle = this._strokeGradient;
+ }
+ else if (hasStrokePattern) {
+ ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);
+ }
+
+ var lineDash = style.lineDash;
+ var lineDashOffset = style.lineDashOffset;
+
+ var ctxLineDash = !!ctx.setLineDash;
+
+ // Update path sx, sy
+ var scale = this.getGlobalScale();
+ path.setScale(scale[0], scale[1]);
+
+ // Proxy context
+ // Rebuild path in following 2 cases
+ // 1. Path is dirty
+ // 2. Path needs javascript implemented lineDash stroking.
+ // In this case, lineDash information will not be saved in PathProxy
+ if (this.__dirtyPath
+ || (lineDash && !ctxLineDash && hasStroke)
+ ) {
+ path.beginPath(ctx);
+
+ // Setting line dash before build path
+ if (lineDash && !ctxLineDash) {
+ path.setLineDash(lineDash);
+ path.setLineDashOffset(lineDashOffset);
+ }
+
+ this.buildPath(path, this.shape, false);
+
+ // Clear path dirty flag
+ if (this.path) {
+ this.__dirtyPath = false;
+ }
+ }
+ else {
+ // Replay path building
+ ctx.beginPath();
+ this.path.rebuildPath(ctx);
+ }
+
+ hasFill && path.fill(ctx);
+
+ if (lineDash && ctxLineDash) {
+ ctx.setLineDash(lineDash);
+ ctx.lineDashOffset = lineDashOffset;
+ }
+
+ hasStroke && path.stroke(ctx);
+
+ if (lineDash && ctxLineDash) {
+ // PENDING
+ // Remove lineDash
+ ctx.setLineDash([]);
+ }
+
+
+ this.restoreTransform(ctx);
+
+ // Draw rect text
+ if (style.text != null) {
+ this.drawRectText(ctx, this.getBoundingRect());
+ }
+ },
+
+ // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath
+ // Like in circle
+ buildPath: function (ctx, shapeCfg, inBundle) {},
+
+ createPathProxy: function () {
+ this.path = new PathProxy();
+ },
+
+ getBoundingRect: function () {
+ var rect = this._rect;
+ var style = this.style;
+ var needsUpdateRect = !rect;
+ if (needsUpdateRect) {
+ var path = this.path;
+ if (!path) {
+ // Create path on demand.
+ path = this.path = new PathProxy();
+ }
+ if (this.__dirtyPath) {
+ path.beginPath();
+ this.buildPath(path, this.shape, false);
+ }
+ rect = path.getBoundingRect();
+ }
+ this._rect = rect;
+
+ if (style.hasStroke()) {
+ // Needs update rect with stroke lineWidth when
+ // 1. Element changes scale or lineWidth
+ // 2. Shape is changed
+ var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());
+ if (this.__dirty || needsUpdateRect) {
+ rectWithStroke.copy(rect);
+ // FIXME Must after updateTransform
+ var w = style.lineWidth;
+ // PENDING, Min line width is needed when line is horizontal or vertical
+ var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
+
+ // Only add extra hover lineWidth when there are no fill
+ if (!style.hasFill()) {
+ w = Math.max(w, this.strokeContainThreshold || 4);
+ }
+ // Consider line width
+ // Line scale can't be 0;
+ if (lineScale > 1e-10) {
+ rectWithStroke.width += w / lineScale;
+ rectWithStroke.height += w / lineScale;
+ rectWithStroke.x -= w / lineScale / 2;
+ rectWithStroke.y -= w / lineScale / 2;
+ }
+ }
+
+ // Return rect with stroke
+ return rectWithStroke;
+ }
+
+ return rect;
+ },
+
+ contain: function (x, y) {
+ var localPos = this.transformCoordToLocal(x, y);
+ var rect = this.getBoundingRect();
+ var style = this.style;
+ x = localPos[0];
+ y = localPos[1];
+
+ if (rect.contain(x, y)) {
+ var pathData = this.path.data;
+ if (style.hasStroke()) {
+ var lineWidth = style.lineWidth;
+ var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
+ // Line scale can't be 0;
+ if (lineScale > 1e-10) {
+ // Only add extra hover lineWidth when there are no fill
+ if (!style.hasFill()) {
+ lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
+ }
+ if (pathContain.containStroke(
+ pathData, lineWidth / lineScale, x, y
+ )) {
+ return true;
+ }
+ }
+ }
+ if (style.hasFill()) {
+ return pathContain.contain(pathData, x, y);
+ }
+ }
+ return false;
+ },
+
+ /**
+ * @param {boolean} dirtyPath
+ */
+ dirty: function (dirtyPath) {
+ if (dirtyPath == null) {
+ dirtyPath = true;
+ }
+ // Only mark dirty, not mark clean
+ if (dirtyPath) {
+ this.__dirtyPath = dirtyPath;
+ this._rect = null;
+ }
+
+ this.__dirty = true;
+
+ this.__zr && this.__zr.refresh();
+
+ // Used as a clipping path
+ if (this.__clipTarget) {
+ this.__clipTarget.dirty();
+ }
+ },
+
+ /**
+ * Alias for animate('shape')
+ * @param {boolean} loop
+ */
+ animateShape: function (loop) {
+ return this.animate('shape', loop);
+ },
+
+ // Overwrite attrKV
+ attrKV: function (key, value) {
+ // FIXME
+ if (key === 'shape') {
+ this.setShape(value);
+ this.__dirtyPath = true;
+ this._rect = null;
+ }
+ else {
+ Displayable.prototype.attrKV.call(this, key, value);
+ }
+ },
+
+ /**
+ * @param {Object|string} key
+ * @param {*} value
+ */
+ setShape: function (key, value) {
+ var shape = this.shape;
+ // Path from string may not have shape
+ if (shape) {
+ if (zrUtil.isObject(key)) {
+ for (var name in key) {
+ if (key.hasOwnProperty(name)) {
+ shape[name] = key[name];
+ }
+ }
+ }
+ else {
+ shape[key] = value;
+ }
+ this.dirty(true);
+ }
+ return this;
+ },
+
+ getLineScale: function () {
+ var m = this.transform;
+ // Get the line scale.
+ // Determinant of `m` means how much the area is enlarged by the
+ // transformation. So its square root can be used as a scale factor
+ // for width.
+ return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10
+ ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))
+ : 1;
+ }
+ };
+
+ /**
+ * 扩展一个 Path element, 比如星形,圆等。
+ * Extend a path element
+ * @param {Object} props
+ * @param {string} props.type Path type
+ * @param {Function} props.init Initialize
+ * @param {Function} props.buildPath Overwrite buildPath method
+ * @param {Object} [props.style] Extended default style config
+ * @param {Object} [props.shape] Extended default shape config
+ */
+ Path.extend = function (defaults) {
+ var Sub = function (opts) {
+ Path.call(this, opts);
+
+ if (defaults.style) {
+ // Extend default style
+ this.style.extendFrom(defaults.style, false);
+ }
+
+ // Extend default shape
+ var defaultShape = defaults.shape;
+ if (defaultShape) {
+ this.shape = this.shape || {};
+ var thisShape = this.shape;
+ for (var name in defaultShape) {
+ if (
+ ! thisShape.hasOwnProperty(name)
+ && defaultShape.hasOwnProperty(name)
+ ) {
+ thisShape[name] = defaultShape[name];
+ }
+ }
+ }
+
+ defaults.init && defaults.init.call(this, opts);
+ };
+
+ zrUtil.inherits(Sub, Path);
+
+ // FIXME 不能 extend position, rotation 等引用对象
+ for (var name in defaults) {
+ // Extending prototype values and methods
+ if (name !== 'style' && name !== 'shape') {
+ Sub.prototype[name] = defaults[name];
+ }
+ }
+
+ return Sub;
+ };
+
+ zrUtil.inherits(Path, Displayable);
+
+ module.exports = Path;
+
+
+/***/ },
+/* 21 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 可绘制的图形基类
+ * Base class of all displayable graphic objects
+ * @module zrender/graphic/Displayable
+ */
+
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var Style = __webpack_require__(22);
+
+ var Element = __webpack_require__(23);
+ var RectText = __webpack_require__(35);
+ // var Stateful = require('./mixin/Stateful');
+
+ /**
+ * @alias module:zrender/graphic/Displayable
+ * @extends module:zrender/Element
+ * @extends module:zrender/graphic/mixin/RectText
+ */
+ function Displayable(opts) {
+
+ opts = opts || {};
+
+ Element.call(this, opts);
+
+ // Extend properties
+ for (var name in opts) {
+ if (
+ opts.hasOwnProperty(name) &&
+ name !== 'style'
+ ) {
+ this[name] = opts[name];
+ }
+ }
+
+ /**
+ * @type {module:zrender/graphic/Style}
+ */
+ this.style = new Style(opts.style);
+
+ this._rect = null;
+ // Shapes for cascade clipping.
+ this.__clipPaths = [];
+
+ // FIXME Stateful must be mixined after style is setted
+ // Stateful.call(this, opts);
+ }
+
+ Displayable.prototype = {
+
+ constructor: Displayable,
+
+ type: 'displayable',
+
+ /**
+ * Displayable 是否为脏,Painter 中会根据该标记判断是否需要是否需要重新绘制
+ * Dirty flag. From which painter will determine if this displayable object needs brush
+ * @name module:zrender/graphic/Displayable#__dirty
+ * @type {boolean}
+ */
+ __dirty: true,
+
+ /**
+ * 图形是否可见,为true时不绘制图形,但是仍能触发鼠标事件
+ * If ignore drawing of the displayable object. Mouse event will still be triggered
+ * @name module:/zrender/graphic/Displayable#invisible
+ * @type {boolean}
+ * @default false
+ */
+ invisible: false,
+
+ /**
+ * @name module:/zrender/graphic/Displayable#z
+ * @type {number}
+ * @default 0
+ */
+ z: 0,
+
+ /**
+ * @name module:/zrender/graphic/Displayable#z
+ * @type {number}
+ * @default 0
+ */
+ z2: 0,
+
+ /**
+ * z层level,决定绘画在哪层canvas中
+ * @name module:/zrender/graphic/Displayable#zlevel
+ * @type {number}
+ * @default 0
+ */
+ zlevel: 0,
+
+ /**
+ * 是否可拖拽
+ * @name module:/zrender/graphic/Displayable#draggable
+ * @type {boolean}
+ * @default false
+ */
+ draggable: false,
+
+ /**
+ * 是否正在拖拽
+ * @name module:/zrender/graphic/Displayable#draggable
+ * @type {boolean}
+ * @default false
+ */
+ dragging: false,
+
+ /**
+ * 是否相应鼠标事件
+ * @name module:/zrender/graphic/Displayable#silent
+ * @type {boolean}
+ * @default false
+ */
+ silent: false,
+
+ /**
+ * If enable culling
+ * @type {boolean}
+ * @default false
+ */
+ culling: false,
+
+ /**
+ * Mouse cursor when hovered
+ * @name module:/zrender/graphic/Displayable#cursor
+ * @type {string}
+ */
+ cursor: 'pointer',
+
+ /**
+ * If hover area is bounding rect
+ * @name module:/zrender/graphic/Displayable#rectHover
+ * @type {string}
+ */
+ rectHover: false,
+
+ /**
+ * Render the element progressively when the value >= 0,
+ * usefull for large data.
+ * @type {number}
+ */
+ progressive: -1,
+
+ beforeBrush: function (ctx) {},
+
+ afterBrush: function (ctx) {},
+
+ /**
+ * 图形绘制方法
+ * @param {Canvas2DRenderingContext} ctx
+ */
+ // Interface
+ brush: function (ctx, prevEl) {},
+
+ /**
+ * 获取最小包围盒
+ * @return {module:zrender/core/BoundingRect}
+ */
+ // Interface
+ getBoundingRect: function () {},
+
+ /**
+ * 判断坐标 x, y 是否在图形上
+ * If displayable element contain coord x, y
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ contain: function (x, y) {
+ return this.rectContain(x, y);
+ },
+
+ /**
+ * @param {Function} cb
+ * @param {} context
+ */
+ traverse: function (cb, context) {
+ cb.call(context, this);
+ },
+
+ /**
+ * 判断坐标 x, y 是否在图形的包围盒上
+ * If bounding rect of element contain coord x, y
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ rectContain: function (x, y) {
+ var coord = this.transformCoordToLocal(x, y);
+ var rect = this.getBoundingRect();
+ return rect.contain(coord[0], coord[1]);
+ },
+
+ /**
+ * 标记图形元素为脏,并且在下一帧重绘
+ * Mark displayable element dirty and refresh next frame
+ */
+ dirty: function () {
+ this.__dirty = true;
+
+ this._rect = null;
+
+ this.__zr && this.__zr.refresh();
+ },
+
+ /**
+ * 图形是否会触发事件
+ * If displayable object binded any event
+ * @return {boolean}
+ */
+ // TODO, 通过 bind 绑定的事件
+ // isSilent: function () {
+ // return !(
+ // this.hoverable || this.draggable
+ // || this.onmousemove || this.onmouseover || this.onmouseout
+ // || this.onmousedown || this.onmouseup || this.onclick
+ // || this.ondragenter || this.ondragover || this.ondragleave
+ // || this.ondrop
+ // );
+ // },
+ /**
+ * Alias for animate('style')
+ * @param {boolean} loop
+ */
+ animateStyle: function (loop) {
+ return this.animate('style', loop);
+ },
+
+ attrKV: function (key, value) {
+ if (key !== 'style') {
+ Element.prototype.attrKV.call(this, key, value);
+ }
+ else {
+ this.style.set(value);
+ }
+ },
+
+ /**
+ * @param {Object|string} key
+ * @param {*} value
+ */
+ setStyle: function (key, value) {
+ this.style.set(key, value);
+ this.dirty(false);
+ return this;
+ },
+
+ /**
+ * Use given style object
+ * @param {Object} obj
+ */
+ useStyle: function (obj) {
+ this.style = new Style(obj);
+ this.dirty(false);
+ return this;
+ }
+ };
+
+ zrUtil.inherits(Displayable, Element);
+
+ zrUtil.mixin(Displayable, RectText);
+ // zrUtil.mixin(Displayable, Stateful);
+
+ module.exports = Displayable;
+
+
+/***/ },
+/* 22 */
+/***/ function(module, exports) {
+
+ /**
+ * @module zrender/graphic/Style
+ */
+
+
+ var STYLE_COMMON_PROPS = [
+ ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],
+ ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]
+ ];
+
+ // var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);
+ // var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);
+
+ var Style = function (opts) {
+ this.extendFrom(opts);
+ };
+
+ function createLinearGradient(ctx, obj, rect) {
+ var x = obj.x == null ? 0 : obj.x;
+ var x2 = obj.x2 == null ? 1 : obj.x2;
+ var y = obj.y == null ? 0 : obj.y;
+ var y2 = obj.y2 == null ? 0 : obj.y2;
+
+ if (!obj.global) {
+ x = x * rect.width + rect.x;
+ x2 = x2 * rect.width + rect.x;
+ y = y * rect.height + rect.y;
+ y2 = y2 * rect.height + rect.y;
+ }
+
+ var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
+
+ return canvasGradient;
+ }
+
+ function createRadialGradient(ctx, obj, rect) {
+ var width = rect.width;
+ var height = rect.height;
+ var min = Math.min(width, height);
+
+ var x = obj.x == null ? 0.5 : obj.x;
+ var y = obj.y == null ? 0.5 : obj.y;
+ var r = obj.r == null ? 0.5 : obj.r;
+ if (!obj.global) {
+ x = x * width + rect.x;
+ y = y * height + rect.y;
+ r = r * min;
+ }
+
+ var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
+
+ return canvasGradient;
+ }
+
+
+ Style.prototype = {
+
+ constructor: Style,
+
+ /**
+ * @type {string}
+ */
+ fill: '#000000',
+
+ /**
+ * @type {string}
+ */
+ stroke: null,
+
+ /**
+ * @type {number}
+ */
+ opacity: 1,
+
+ /**
+ * @type {Array.}
+ */
+ lineDash: null,
+
+ /**
+ * @type {number}
+ */
+ lineDashOffset: 0,
+
+ /**
+ * @type {number}
+ */
+ shadowBlur: 0,
+
+ /**
+ * @type {number}
+ */
+ shadowOffsetX: 0,
+
+ /**
+ * @type {number}
+ */
+ shadowOffsetY: 0,
+
+ /**
+ * @type {number}
+ */
+ lineWidth: 1,
+
+ /**
+ * If stroke ignore scale
+ * @type {Boolean}
+ */
+ strokeNoScale: false,
+
+ // Bounding rect text configuration
+ // Not affected by element transform
+ /**
+ * @type {string}
+ */
+ text: null,
+
+ /**
+ * @type {string}
+ */
+ textFill: '#000',
+
+ /**
+ * @type {string}
+ */
+ textStroke: null,
+
+ /**
+ * 'inside', 'left', 'right', 'top', 'bottom'
+ * [x, y]
+ * @type {string|Array.}
+ * @default 'inside'
+ */
+ textPosition: 'inside',
+
+ /**
+ * If not specified, use the boundingRect of a `displayable`.
+ * @type {Object}
+ */
+ textPositionRect: null,
+
+ /**
+ * [x, y]
+ * @type {Array.}
+ */
+ textOffset: null,
+
+ /**
+ * @type {string}
+ */
+ textBaseline: null,
+
+ /**
+ * @type {string}
+ */
+ textAlign: null,
+
+ /**
+ * @type {string}
+ */
+ textVerticalAlign: null,
+
+ /**
+ * Only useful in Path and Image element
+ * @type {number}
+ */
+ textDistance: 5,
+
+ /**
+ * Only useful in Path and Image element
+ * @type {number}
+ */
+ textShadowBlur: 0,
+
+ /**
+ * Only useful in Path and Image element
+ * @type {number}
+ */
+ textShadowOffsetX: 0,
+
+ /**
+ * Only useful in Path and Image element
+ * @type {number}
+ */
+ textShadowOffsetY: 0,
+
+ /**
+ * If transform text
+ * Only useful in Path and Image element
+ * @type {boolean}
+ */
+ textTransform: false,
+
+ /**
+ * Text rotate around position of Path or Image
+ * Only useful in Path and Image element and textTransform is false.
+ */
+ textRotation: 0,
+
+ /**
+ * @type {string}
+ * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
+ */
+ blend: null,
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ */
+ bind: function (ctx, el, prevEl) {
+ var style = this;
+ var prevStyle = prevEl && prevEl.style;
+ var firstDraw = !prevStyle;
+
+ for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
+ var prop = STYLE_COMMON_PROPS[i];
+ var styleName = prop[0];
+
+ if (firstDraw || style[styleName] !== prevStyle[styleName]) {
+ // FIXME Invalid property value will cause style leak from previous element.
+ ctx[styleName] = style[styleName] || prop[1];
+ }
+ }
+
+ if ((firstDraw || style.fill !== prevStyle.fill)) {
+ ctx.fillStyle = style.fill;
+ }
+ if ((firstDraw || style.stroke !== prevStyle.stroke)) {
+ ctx.strokeStyle = style.stroke;
+ }
+ if ((firstDraw || style.opacity !== prevStyle.opacity)) {
+ ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;
+ }
+
+ if ((firstDraw || style.blend !== prevStyle.blend)) {
+ ctx.globalCompositeOperation = style.blend || 'source-over';
+ }
+ if (this.hasStroke()) {
+ var lineWidth = style.lineWidth;
+ ctx.lineWidth = lineWidth / (
+ (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1
+ );
+ }
+ },
+
+ hasFill: function () {
+ var fill = this.fill;
+ return fill != null && fill !== 'none';
+ },
+
+ hasStroke: function () {
+ var stroke = this.stroke;
+ return stroke != null && stroke !== 'none' && this.lineWidth > 0;
+ },
+
+ /**
+ * Extend from other style
+ * @param {zrender/graphic/Style} otherStyle
+ * @param {boolean} overwrite
+ */
+ extendFrom: function (otherStyle, overwrite) {
+ if (otherStyle) {
+ var target = this;
+ for (var name in otherStyle) {
+ if (otherStyle.hasOwnProperty(name)
+ && (overwrite || ! target.hasOwnProperty(name))
+ ) {
+ target[name] = otherStyle[name];
+ }
+ }
+ }
+ },
+
+ /**
+ * Batch setting style with a given object
+ * @param {Object|string} obj
+ * @param {*} [obj]
+ */
+ set: function (obj, value) {
+ if (typeof obj === 'string') {
+ this[obj] = value;
+ }
+ else {
+ this.extendFrom(obj, true);
+ }
+ },
+
+ /**
+ * Clone
+ * @return {zrender/graphic/Style} [description]
+ */
+ clone: function () {
+ var newStyle = new this.constructor();
+ newStyle.extendFrom(this, true);
+ return newStyle;
+ },
+
+ getGradient: function (ctx, obj, rect) {
+ var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;
+ var canvasGradient = method(ctx, obj, rect);
+ var colorStops = obj.colorStops;
+ for (var i = 0; i < colorStops.length; i++) {
+ canvasGradient.addColorStop(
+ colorStops[i].offset, colorStops[i].color
+ );
+ }
+ return canvasGradient;
+ }
+ };
+
+ var styleProto = Style.prototype;
+ for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
+ var prop = STYLE_COMMON_PROPS[i];
+ if (!(prop[0] in styleProto)) {
+ styleProto[prop[0]] = prop[1];
+ }
+ }
+
+ // Provide for others
+ Style.getGradient = styleProto.getGradient;
+
+ module.exports = Style;
+
+
+/***/ },
+/* 23 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * @module zrender/Element
+ */
+
+
+ var guid = __webpack_require__(24);
+ var Eventful = __webpack_require__(25);
+ var Transformable = __webpack_require__(26);
+ var Animatable = __webpack_require__(27);
+ var zrUtil = __webpack_require__(4);
+
+ /**
+ * @alias module:zrender/Element
+ * @constructor
+ * @extends {module:zrender/mixin/Animatable}
+ * @extends {module:zrender/mixin/Transformable}
+ * @extends {module:zrender/mixin/Eventful}
+ */
+ var Element = function (opts) {
+
+ Transformable.call(this, opts);
+ Eventful.call(this, opts);
+ Animatable.call(this, opts);
+
+ /**
+ * 画布元素ID
+ * @type {string}
+ */
+ this.id = opts.id || guid();
+ };
+
+ Element.prototype = {
+
+ /**
+ * 元素类型
+ * Element type
+ * @type {string}
+ */
+ type: 'element',
+
+ /**
+ * 元素名字
+ * Element name
+ * @type {string}
+ */
+ name: '',
+
+ /**
+ * ZRender 实例对象,会在 element 添加到 zrender 实例中后自动赋值
+ * ZRender instance will be assigned when element is associated with zrender
+ * @name module:/zrender/Element#__zr
+ * @type {module:zrender/ZRender}
+ */
+ __zr: null,
+
+ /**
+ * 图形是否忽略,为true时忽略图形的绘制以及事件触发
+ * If ignore drawing and events of the element object
+ * @name module:/zrender/Element#ignore
+ * @type {boolean}
+ * @default false
+ */
+ ignore: false,
+
+ /**
+ * 用于裁剪的路径(shape),所有 Group 内的路径在绘制时都会被这个路径裁剪
+ * 该路径会继承被裁减对象的变换
+ * @type {module:zrender/graphic/Path}
+ * @see http://www.w3.org/TR/2dcontext/#clipping-region
+ * @readOnly
+ */
+ clipPath: null,
+
+ /**
+ * Drift element
+ * @param {number} dx dx on the global space
+ * @param {number} dy dy on the global space
+ */
+ drift: function (dx, dy) {
+ switch (this.draggable) {
+ case 'horizontal':
+ dy = 0;
+ break;
+ case 'vertical':
+ dx = 0;
+ break;
+ }
+
+ var m = this.transform;
+ if (!m) {
+ m = this.transform = [1, 0, 0, 1, 0, 0];
+ }
+ m[4] += dx;
+ m[5] += dy;
+
+ this.decomposeTransform();
+ this.dirty(false);
+ },
+
+ /**
+ * Hook before update
+ */
+ beforeUpdate: function () {},
+ /**
+ * Hook after update
+ */
+ afterUpdate: function () {},
+ /**
+ * Update each frame
+ */
+ update: function () {
+ this.updateTransform();
+ },
+
+ /**
+ * @param {Function} cb
+ * @param {} context
+ */
+ traverse: function (cb, context) {},
+
+ /**
+ * @protected
+ */
+ attrKV: function (key, value) {
+ if (key === 'position' || key === 'scale' || key === 'origin') {
+ // Copy the array
+ if (value) {
+ var target = this[key];
+ if (!target) {
+ target = this[key] = [];
+ }
+ target[0] = value[0];
+ target[1] = value[1];
+ }
+ }
+ else {
+ this[key] = value;
+ }
+ },
+
+ /**
+ * Hide the element
+ */
+ hide: function () {
+ this.ignore = true;
+ this.__zr && this.__zr.refresh();
+ },
+
+ /**
+ * Show the element
+ */
+ show: function () {
+ this.ignore = false;
+ this.__zr && this.__zr.refresh();
+ },
+
+ /**
+ * @param {string|Object} key
+ * @param {*} value
+ */
+ attr: function (key, value) {
+ if (typeof key === 'string') {
+ this.attrKV(key, value);
+ }
+ else if (zrUtil.isObject(key)) {
+ for (var name in key) {
+ if (key.hasOwnProperty(name)) {
+ this.attrKV(name, key[name]);
+ }
+ }
+ }
+
+ this.dirty(false);
+
+ return this;
+ },
+
+ /**
+ * @param {module:zrender/graphic/Path} clipPath
+ */
+ setClipPath: function (clipPath) {
+ var zr = this.__zr;
+ if (zr) {
+ clipPath.addSelfToZr(zr);
+ }
+
+ // Remove previous clip path
+ if (this.clipPath && this.clipPath !== clipPath) {
+ this.removeClipPath();
+ }
+
+ this.clipPath = clipPath;
+ clipPath.__zr = zr;
+ clipPath.__clipTarget = this;
+
+ this.dirty(false);
+ },
+
+ /**
+ */
+ removeClipPath: function () {
+ var clipPath = this.clipPath;
+ if (clipPath) {
+ if (clipPath.__zr) {
+ clipPath.removeSelfFromZr(clipPath.__zr);
+ }
+
+ clipPath.__zr = null;
+ clipPath.__clipTarget = null;
+ this.clipPath = null;
+
+ this.dirty(false);
+ }
+ },
+
+ /**
+ * Add self from zrender instance.
+ * Not recursively because it will be invoked when element added to storage.
+ * @param {module:zrender/ZRender} zr
+ */
+ addSelfToZr: function (zr) {
+ this.__zr = zr;
+ // 添加动画
+ var animators = this.animators;
+ if (animators) {
+ for (var i = 0; i < animators.length; i++) {
+ zr.animation.addAnimator(animators[i]);
+ }
+ }
+
+ if (this.clipPath) {
+ this.clipPath.addSelfToZr(zr);
+ }
+ },
+
+ /**
+ * Remove self from zrender instance.
+ * Not recursively because it will be invoked when element added to storage.
+ * @param {module:zrender/ZRender} zr
+ */
+ removeSelfFromZr: function (zr) {
+ this.__zr = null;
+ // 移除动画
+ var animators = this.animators;
+ if (animators) {
+ for (var i = 0; i < animators.length; i++) {
+ zr.animation.removeAnimator(animators[i]);
+ }
+ }
+
+ if (this.clipPath) {
+ this.clipPath.removeSelfFromZr(zr);
+ }
+ }
+ };
+
+ zrUtil.mixin(Element, Animatable);
+ zrUtil.mixin(Element, Transformable);
+ zrUtil.mixin(Element, Eventful);
+
+ module.exports = Element;
+
+
+/***/ },
+/* 24 */
+/***/ function(module, exports) {
+
+ /**
+ * zrender: 生成唯一id
+ *
+ * @author errorrik (errorrik@gmail.com)
+ */
+
+
+ var idStart = 0x0907;
+
+ module.exports = function () {
+ return idStart++;
+ };
+
+
+
+/***/ },
+/* 25 */
+/***/ function(module, exports) {
+
+ /**
+ * 事件扩展
+ * @module zrender/mixin/Eventful
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * pissang (https://www.github.com/pissang)
+ */
+
+
+ var arrySlice = Array.prototype.slice;
+
+ /**
+ * 事件分发器
+ * @alias module:zrender/mixin/Eventful
+ * @constructor
+ */
+ var Eventful = function () {
+ this._$handlers = {};
+ };
+
+ Eventful.prototype = {
+
+ constructor: Eventful,
+
+ /**
+ * 单次触发绑定,trigger后销毁
+ *
+ * @param {string} event 事件名
+ * @param {Function} handler 响应函数
+ * @param {Object} context
+ */
+ one: function (event, handler, context) {
+ var _h = this._$handlers;
+
+ if (!handler || !event) {
+ return this;
+ }
+
+ if (!_h[event]) {
+ _h[event] = [];
+ }
+
+ for (var i = 0; i < _h[event].length; i++) {
+ if (_h[event][i].h === handler) {
+ return this;
+ }
+ }
+
+ _h[event].push({
+ h: handler,
+ one: true,
+ ctx: context || this
+ });
+
+ return this;
+ },
+
+ /**
+ * 绑定事件
+ * @param {string} event 事件名
+ * @param {Function} handler 事件处理函数
+ * @param {Object} [context]
+ */
+ on: function (event, handler, context) {
+ var _h = this._$handlers;
+
+ if (!handler || !event) {
+ return this;
+ }
+
+ if (!_h[event]) {
+ _h[event] = [];
+ }
+
+ for (var i = 0; i < _h[event].length; i++) {
+ if (_h[event][i].h === handler) {
+ return this;
+ }
+ }
+
+ _h[event].push({
+ h: handler,
+ one: false,
+ ctx: context || this
+ });
+
+ return this;
+ },
+
+ /**
+ * 是否绑定了事件
+ * @param {string} event
+ * @return {boolean}
+ */
+ isSilent: function (event) {
+ var _h = this._$handlers;
+ return _h[event] && _h[event].length;
+ },
+
+ /**
+ * 解绑事件
+ * @param {string} event 事件名
+ * @param {Function} [handler] 事件处理函数
+ */
+ off: function (event, handler) {
+ var _h = this._$handlers;
+
+ if (!event) {
+ this._$handlers = {};
+ return this;
+ }
+
+ if (handler) {
+ if (_h[event]) {
+ var newList = [];
+ for (var i = 0, l = _h[event].length; i < l; i++) {
+ if (_h[event][i]['h'] != handler) {
+ newList.push(_h[event][i]);
+ }
+ }
+ _h[event] = newList;
+ }
+
+ if (_h[event] && _h[event].length === 0) {
+ delete _h[event];
+ }
+ }
+ else {
+ delete _h[event];
+ }
+
+ return this;
+ },
+
+ /**
+ * 事件分发
+ *
+ * @param {string} type 事件类型
+ */
+ trigger: function (type) {
+ if (this._$handlers[type]) {
+ var args = arguments;
+ var argLen = args.length;
+
+ if (argLen > 3) {
+ args = arrySlice.call(args, 1);
+ }
+
+ var _h = this._$handlers[type];
+ var len = _h.length;
+ for (var i = 0; i < len;) {
+ // Optimize advise from backbone
+ switch (argLen) {
+ case 1:
+ _h[i]['h'].call(_h[i]['ctx']);
+ break;
+ case 2:
+
+ _h[i]['h'].call(_h[i]['ctx'], args[1]);
+ break;
+ case 3:
+ _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]);
+ break;
+ default:
+ // have more than 2 given arguments
+ _h[i]['h'].apply(_h[i]['ctx'], args);
+ break;
+ }
+
+ if (_h[i]['one']) {
+ _h.splice(i, 1);
+ len--;
+ }
+ else {
+ i++;
+ }
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * 带有context的事件分发, 最后一个参数是事件回调的context
+ * @param {string} type 事件类型
+ */
+ triggerWithContext: function (type) {
+ if (this._$handlers[type]) {
+ var args = arguments;
+ var argLen = args.length;
+
+ if (argLen > 4) {
+ args = arrySlice.call(args, 1, args.length - 1);
+ }
+ var ctx = args[args.length - 1];
+
+ var _h = this._$handlers[type];
+ var len = _h.length;
+ for (var i = 0; i < len;) {
+ // Optimize advise from backbone
+ switch (argLen) {
+ case 1:
+ _h[i]['h'].call(ctx);
+ break;
+ case 2:
+ _h[i]['h'].call(ctx, args[1]);
+ break;
+ case 3:
+ _h[i]['h'].call(ctx, args[1], args[2]);
+ break;
+ default:
+ // have more than 2 given arguments
+ _h[i]['h'].apply(ctx, args);
+ break;
+ }
+
+ if (_h[i]['one']) {
+ _h.splice(i, 1);
+ len--;
+ }
+ else {
+ i++;
+ }
+ }
+ }
+
+ return this;
+ }
+ };
+
+ // 对象可以通过 onxxxx 绑定事件
+ /**
+ * @event module:zrender/mixin/Eventful#onclick
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmouseover
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmouseout
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmousemove
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmousewheel
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmousedown
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#onmouseup
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondrag
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondragstart
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondragend
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondragenter
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondragleave
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondragover
+ * @type {Function}
+ * @default null
+ */
+ /**
+ * @event module:zrender/mixin/Eventful#ondrop
+ * @type {Function}
+ * @default null
+ */
+
+ module.exports = Eventful;
+
+
+
+/***/ },
+/* 26 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 提供变换扩展
+ * @module zrender/mixin/Transformable
+ * @author pissang (https://www.github.com/pissang)
+ */
+
+
+ var matrix = __webpack_require__(11);
+ var vector = __webpack_require__(10);
+ var mIdentity = matrix.identity;
+
+ var EPSILON = 5e-5;
+
+ function isNotAroundZero(val) {
+ return val > EPSILON || val < -EPSILON;
+ }
+
+ /**
+ * @alias module:zrender/mixin/Transformable
+ * @constructor
+ */
+ var Transformable = function (opts) {
+ opts = opts || {};
+ // If there are no given position, rotation, scale
+ if (!opts.position) {
+ /**
+ * 平移
+ * @type {Array.}
+ * @default [0, 0]
+ */
+ this.position = [0, 0];
+ }
+ if (opts.rotation == null) {
+ /**
+ * 旋转
+ * @type {Array.}
+ * @default 0
+ */
+ this.rotation = 0;
+ }
+ if (!opts.scale) {
+ /**
+ * 缩放
+ * @type {Array.}
+ * @default [1, 1]
+ */
+ this.scale = [1, 1];
+ }
+ /**
+ * 旋转和缩放的原点
+ * @type {Array.}
+ * @default null
+ */
+ this.origin = this.origin || null;
+ };
+
+ var transformableProto = Transformable.prototype;
+ transformableProto.transform = null;
+
+ /**
+ * 判断是否需要有坐标变换
+ * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵
+ */
+ transformableProto.needLocalTransform = function () {
+ return isNotAroundZero(this.rotation)
+ || isNotAroundZero(this.position[0])
+ || isNotAroundZero(this.position[1])
+ || isNotAroundZero(this.scale[0] - 1)
+ || isNotAroundZero(this.scale[1] - 1);
+ };
+
+ transformableProto.updateTransform = function () {
+ var parent = this.parent;
+ var parentHasTransform = parent && parent.transform;
+ var needLocalTransform = this.needLocalTransform();
+
+ var m = this.transform;
+ if (!(needLocalTransform || parentHasTransform)) {
+ m && mIdentity(m);
+ return;
+ }
+
+ m = m || matrix.create();
+
+ if (needLocalTransform) {
+ this.getLocalTransform(m);
+ }
+ else {
+ mIdentity(m);
+ }
+
+ // 应用父节点变换
+ if (parentHasTransform) {
+ if (needLocalTransform) {
+ matrix.mul(m, parent.transform, m);
+ }
+ else {
+ matrix.copy(m, parent.transform);
+ }
+ }
+ // 保存这个变换矩阵
+ this.transform = m;
+
+ this.invTransform = this.invTransform || matrix.create();
+ matrix.invert(this.invTransform, m);
+ };
+
+ transformableProto.getLocalTransform = function (m) {
+ return Transformable.getLocalTransform(this, m);
+ };
+
+ /**
+ * 将自己的transform应用到context上
+ * @param {Context2D} ctx
+ */
+ transformableProto.setTransform = function (ctx) {
+ var m = this.transform;
+ var dpr = ctx.dpr || 1;
+ if (m) {
+ ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
+ }
+ else {
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ }
+ };
+
+ transformableProto.restoreTransform = function (ctx) {
+ var dpr = ctx.dpr || 1;
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ };
+
+ var tmpTransform = [];
+
+ /**
+ * 分解`transform`矩阵到`position`, `rotation`, `scale`
+ */
+ transformableProto.decomposeTransform = function () {
+ if (!this.transform) {
+ return;
+ }
+ var parent = this.parent;
+ var m = this.transform;
+ if (parent && parent.transform) {
+ // Get local transform and decompose them to position, scale, rotation
+ matrix.mul(tmpTransform, parent.invTransform, m);
+ m = tmpTransform;
+ }
+ var sx = m[0] * m[0] + m[1] * m[1];
+ var sy = m[2] * m[2] + m[3] * m[3];
+ var position = this.position;
+ var scale = this.scale;
+ if (isNotAroundZero(sx - 1)) {
+ sx = Math.sqrt(sx);
+ }
+ if (isNotAroundZero(sy - 1)) {
+ sy = Math.sqrt(sy);
+ }
+ if (m[0] < 0) {
+ sx = -sx;
+ }
+ if (m[3] < 0) {
+ sy = -sy;
+ }
+ position[0] = m[4];
+ position[1] = m[5];
+ scale[0] = sx;
+ scale[1] = sy;
+ this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
+ };
+
+ /**
+ * Get global scale
+ * @return {Array.}
+ */
+ transformableProto.getGlobalScale = function () {
+ var m = this.transform;
+ if (!m) {
+ return [1, 1];
+ }
+ var sx = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
+ var sy = Math.sqrt(m[2] * m[2] + m[3] * m[3]);
+ if (m[0] < 0) {
+ sx = -sx;
+ }
+ if (m[3] < 0) {
+ sy = -sy;
+ }
+ return [sx, sy];
+ };
+ /**
+ * 变换坐标位置到 shape 的局部坐标空间
+ * @method
+ * @param {number} x
+ * @param {number} y
+ * @return {Array.}
+ */
+ transformableProto.transformCoordToLocal = function (x, y) {
+ var v2 = [x, y];
+ var invTransform = this.invTransform;
+ if (invTransform) {
+ vector.applyTransform(v2, v2, invTransform);
+ }
+ return v2;
+ };
+
+ /**
+ * 变换局部坐标位置到全局坐标空间
+ * @method
+ * @param {number} x
+ * @param {number} y
+ * @return {Array.}
+ */
+ transformableProto.transformCoordToGlobal = function (x, y) {
+ var v2 = [x, y];
+ var transform = this.transform;
+ if (transform) {
+ vector.applyTransform(v2, v2, transform);
+ }
+ return v2;
+ };
+
+ /**
+ * @static
+ * @param {Object} target
+ * @param {Array.} target.origin
+ * @param {number} target.rotation
+ * @param {Array.} target.position
+ * @param {Array.} [m]
+ */
+ Transformable.getLocalTransform = function (target, m) {
+ m = m || [];
+ mIdentity(m);
+
+ var origin = target.origin;
+ var scale = target.scale || [1, 1];
+ var rotation = target.rotation || 0;
+ var position = target.position || [0, 0];
+
+ if (origin) {
+ // Translate to origin
+ m[4] -= origin[0];
+ m[5] -= origin[1];
+ }
+ matrix.scale(m, m, scale);
+ if (rotation) {
+ matrix.rotate(m, m, rotation);
+ }
+ if (origin) {
+ // Translate back from origin
+ m[4] += origin[0];
+ m[5] += origin[1];
+ }
+
+ m[4] += position[0];
+ m[5] += position[1];
+
+ return m;
+ };
+
+ module.exports = Transformable;
+
+
+
+/***/ },
+/* 27 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * @module zrender/mixin/Animatable
+ */
+
+
+ var Animator = __webpack_require__(28);
+ var util = __webpack_require__(4);
+ var isString = util.isString;
+ var isFunction = util.isFunction;
+ var isObject = util.isObject;
+ var log = __webpack_require__(33);
+
+ /**
+ * @alias modue:zrender/mixin/Animatable
+ * @constructor
+ */
+ var Animatable = function () {
+
+ /**
+ * @type {Array.}
+ * @readOnly
+ */
+ this.animators = [];
+ };
+
+ Animatable.prototype = {
+
+ constructor: Animatable,
+
+ /**
+ * 动画
+ *
+ * @param {string} path 需要添加动画的属性获取路径,可以通过a.b.c来获取深层的属性
+ * @param {boolean} [loop] 动画是否循环
+ * @return {module:zrender/animation/Animator}
+ * @example:
+ * el.animate('style', false)
+ * .when(1000, {x: 10} )
+ * .done(function(){ // Animation done })
+ * .start()
+ */
+ animate: function (path, loop) {
+ var target;
+ var animatingShape = false;
+ var el = this;
+ var zr = this.__zr;
+ if (path) {
+ var pathSplitted = path.split('.');
+ var prop = el;
+ // If animating shape
+ animatingShape = pathSplitted[0] === 'shape';
+ for (var i = 0, l = pathSplitted.length; i < l; i++) {
+ if (!prop) {
+ continue;
+ }
+ prop = prop[pathSplitted[i]];
+ }
+ if (prop) {
+ target = prop;
+ }
+ }
+ else {
+ target = el;
+ }
+
+ if (!target) {
+ log(
+ 'Property "'
+ + path
+ + '" is not existed in element '
+ + el.id
+ );
+ return;
+ }
+
+ var animators = el.animators;
+
+ var animator = new Animator(target, loop);
+
+ animator.during(function (target) {
+ el.dirty(animatingShape);
+ })
+ .done(function () {
+ // FIXME Animator will not be removed if use `Animator#stop` to stop animation
+ animators.splice(util.indexOf(animators, animator), 1);
+ });
+
+ animators.push(animator);
+
+ // If animate after added to the zrender
+ if (zr) {
+ zr.animation.addAnimator(animator);
+ }
+
+ return animator;
+ },
+
+ /**
+ * 停止动画
+ * @param {boolean} forwardToLast If move to last frame before stop
+ */
+ stopAnimation: function (forwardToLast) {
+ var animators = this.animators;
+ var len = animators.length;
+ for (var i = 0; i < len; i++) {
+ animators[i].stop(forwardToLast);
+ }
+ animators.length = 0;
+
+ return this;
+ },
+
+ /**
+ * @param {Object} target
+ * @param {number} [time=500] Time in ms
+ * @param {string} [easing='linear']
+ * @param {number} [delay=0]
+ * @param {Function} [callback]
+ *
+ * @example
+ * // Animate position
+ * el.animateTo({
+ * position: [10, 10]
+ * }, function () { // done })
+ *
+ * // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing
+ * el.animateTo({
+ * shape: {
+ * width: 500
+ * },
+ * style: {
+ * fill: 'red'
+ * }
+ * position: [10, 10]
+ * }, 100, 100, 'cubicOut', function () { // done })
+ */
+ // TODO Return animation key
+ animateTo: function (target, time, delay, easing, callback) {
+ // animateTo(target, time, easing, callback);
+ if (isString(delay)) {
+ callback = easing;
+ easing = delay;
+ delay = 0;
+ }
+ // animateTo(target, time, delay, callback);
+ else if (isFunction(easing)) {
+ callback = easing;
+ easing = 'linear';
+ delay = 0;
+ }
+ // animateTo(target, time, callback);
+ else if (isFunction(delay)) {
+ callback = delay;
+ delay = 0;
+ }
+ // animateTo(target, callback)
+ else if (isFunction(time)) {
+ callback = time;
+ time = 500;
+ }
+ // animateTo(target)
+ else if (!time) {
+ time = 500;
+ }
+ // Stop all previous animations
+ this.stopAnimation();
+ this._animateToShallow('', this, target, time, delay, easing, callback);
+
+ // Animators may be removed immediately after start
+ // if there is nothing to animate
+ var animators = this.animators.slice();
+ var count = animators.length;
+ function done() {
+ count--;
+ if (!count) {
+ callback && callback();
+ }
+ }
+
+ // No animators. This should be checked before animators[i].start(),
+ // because 'done' may be executed immediately if no need to animate.
+ if (!count) {
+ callback && callback();
+ }
+ // Start after all animators created
+ // Incase any animator is done immediately when all animation properties are not changed
+ for (var i = 0; i < animators.length; i++) {
+ animators[i]
+ .done(done)
+ .start(easing);
+ }
+ },
+
+ /**
+ * @private
+ * @param {string} path=''
+ * @param {Object} source=this
+ * @param {Object} target
+ * @param {number} [time=500]
+ * @param {number} [delay=0]
+ *
+ * @example
+ * // Animate position
+ * el._animateToShallow({
+ * position: [10, 10]
+ * })
+ *
+ * // Animate shape, style and position in 100ms, delayed 100ms
+ * el._animateToShallow({
+ * shape: {
+ * width: 500
+ * },
+ * style: {
+ * fill: 'red'
+ * }
+ * position: [10, 10]
+ * }, 100, 100)
+ */
+ _animateToShallow: function (path, source, target, time, delay) {
+ var objShallow = {};
+ var propertyCount = 0;
+ for (var name in target) {
+ if (!target.hasOwnProperty(name)) {
+ continue;
+ }
+
+ if (source[name] != null) {
+ if (isObject(target[name]) && !util.isArrayLike(target[name])) {
+ this._animateToShallow(
+ path ? path + '.' + name : name,
+ source[name],
+ target[name],
+ time,
+ delay
+ );
+ }
+ else {
+ objShallow[name] = target[name];
+ propertyCount++;
+ }
+ }
+ else if (target[name] != null) {
+ // Attr directly if not has property
+ // FIXME, if some property not needed for element ?
+ if (!path) {
+ this.attr(name, target[name]);
+ }
+ else { // Shape or style
+ var props = {};
+ props[path] = {};
+ props[path][name] = target[name];
+ this.attr(props);
+ }
+ }
+ }
+
+ if (propertyCount > 0) {
+ this.animate(path, false)
+ .when(time == null ? 500 : time, objShallow)
+ .delay(delay || 0);
+ }
+
+ return this;
+ }
+ };
+
+ module.exports = Animatable;
+
+
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @module echarts/animation/Animator
+ */
+
+
+ var Clip = __webpack_require__(29);
+ var color = __webpack_require__(31);
+ var util = __webpack_require__(4);
+ var isArrayLike = util.isArrayLike;
+
+ var arraySlice = Array.prototype.slice;
+
+ function defaultGetter(target, key) {
+ return target[key];
+ }
+
+ function defaultSetter(target, key, value) {
+ target[key] = value;
+ }
+
+ /**
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} percent
+ * @return {number}
+ */
+ function interpolateNumber(p0, p1, percent) {
+ return (p1 - p0) * percent + p0;
+ }
+
+ /**
+ * @param {string} p0
+ * @param {string} p1
+ * @param {number} percent
+ * @return {string}
+ */
+ function interpolateString(p0, p1, percent) {
+ return percent > 0.5 ? p1 : p0;
+ }
+
+ /**
+ * @param {Array} p0
+ * @param {Array} p1
+ * @param {number} percent
+ * @param {Array} out
+ * @param {number} arrDim
+ */
+ function interpolateArray(p0, p1, percent, out, arrDim) {
+ var len = p0.length;
+ if (arrDim == 1) {
+ for (var i = 0; i < len; i++) {
+ out[i] = interpolateNumber(p0[i], p1[i], percent);
+ }
+ }
+ else {
+ var len2 = len && p0[0].length;
+ for (var i = 0; i < len; i++) {
+ for (var j = 0; j < len2; j++) {
+ out[i][j] = interpolateNumber(
+ p0[i][j], p1[i][j], percent
+ );
+ }
+ }
+ }
+ }
+
+ // arr0 is source array, arr1 is target array.
+ // Do some preprocess to avoid error happened when interpolating from arr0 to arr1
+ function fillArr(arr0, arr1, arrDim) {
+ var arr0Len = arr0.length;
+ var arr1Len = arr1.length;
+ if (arr0Len !== arr1Len) {
+ // FIXME Not work for TypedArray
+ var isPreviousLarger = arr0Len > arr1Len;
+ if (isPreviousLarger) {
+ // Cut the previous
+ arr0.length = arr1Len;
+ }
+ else {
+ // Fill the previous
+ for (var i = arr0Len; i < arr1Len; i++) {
+ arr0.push(
+ arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])
+ );
+ }
+ }
+ }
+ // Handling NaN value
+ var len2 = arr0[0] && arr0[0].length;
+ for (var i = 0; i < arr0.length; i++) {
+ if (arrDim === 1) {
+ if (isNaN(arr0[i])) {
+ arr0[i] = arr1[i];
+ }
+ }
+ else {
+ for (var j = 0; j < len2; j++) {
+ if (isNaN(arr0[i][j])) {
+ arr0[i][j] = arr1[i][j];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param {Array} arr0
+ * @param {Array} arr1
+ * @param {number} arrDim
+ * @return {boolean}
+ */
+ function isArraySame(arr0, arr1, arrDim) {
+ if (arr0 === arr1) {
+ return true;
+ }
+ var len = arr0.length;
+ if (len !== arr1.length) {
+ return false;
+ }
+ if (arrDim === 1) {
+ for (var i = 0; i < len; i++) {
+ if (arr0[i] !== arr1[i]) {
+ return false;
+ }
+ }
+ }
+ else {
+ var len2 = arr0[0].length;
+ for (var i = 0; i < len; i++) {
+ for (var j = 0; j < len2; j++) {
+ if (arr0[i][j] !== arr1[i][j]) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Catmull Rom interpolate array
+ * @param {Array} p0
+ * @param {Array} p1
+ * @param {Array} p2
+ * @param {Array} p3
+ * @param {number} t
+ * @param {number} t2
+ * @param {number} t3
+ * @param {Array} out
+ * @param {number} arrDim
+ */
+ function catmullRomInterpolateArray(
+ p0, p1, p2, p3, t, t2, t3, out, arrDim
+ ) {
+ var len = p0.length;
+ if (arrDim == 1) {
+ for (var i = 0; i < len; i++) {
+ out[i] = catmullRomInterpolate(
+ p0[i], p1[i], p2[i], p3[i], t, t2, t3
+ );
+ }
+ }
+ else {
+ var len2 = p0[0].length;
+ for (var i = 0; i < len; i++) {
+ for (var j = 0; j < len2; j++) {
+ out[i][j] = catmullRomInterpolate(
+ p0[i][j], p1[i][j], p2[i][j], p3[i][j],
+ t, t2, t3
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Catmull Rom interpolate number
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {number} t
+ * @param {number} t2
+ * @param {number} t3
+ * @return {number}
+ */
+ function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
+ var v0 = (p2 - p0) * 0.5;
+ var v1 = (p3 - p1) * 0.5;
+ return (2 * (p1 - p2) + v0 + v1) * t3
+ + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
+ + v0 * t + p1;
+ }
+
+ function cloneValue(value) {
+ if (isArrayLike(value)) {
+ var len = value.length;
+ if (isArrayLike(value[0])) {
+ var ret = [];
+ for (var i = 0; i < len; i++) {
+ ret.push(arraySlice.call(value[i]));
+ }
+ return ret;
+ }
+
+ return arraySlice.call(value);
+ }
+
+ return value;
+ }
+
+ function rgba2String(rgba) {
+ rgba[0] = Math.floor(rgba[0]);
+ rgba[1] = Math.floor(rgba[1]);
+ rgba[2] = Math.floor(rgba[2]);
+
+ return 'rgba(' + rgba.join(',') + ')';
+ }
+
+ function getArrayDim(keyframes) {
+ var lastValue = keyframes[keyframes.length - 1].value;
+ return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;
+ }
+
+ function createTrackClip (animator, easing, oneTrackDone, keyframes, propName) {
+ var getter = animator._getter;
+ var setter = animator._setter;
+ var useSpline = easing === 'spline';
+
+ var trackLen = keyframes.length;
+ if (!trackLen) {
+ return;
+ }
+ // Guess data type
+ var firstVal = keyframes[0].value;
+ var isValueArray = isArrayLike(firstVal);
+ var isValueColor = false;
+ var isValueString = false;
+
+ // For vertices morphing
+ var arrDim = isValueArray ? getArrayDim(keyframes) : 0;
+
+ var trackMaxTime;
+ // Sort keyframe as ascending
+ keyframes.sort(function(a, b) {
+ return a.time - b.time;
+ });
+
+ trackMaxTime = keyframes[trackLen - 1].time;
+ // Percents of each keyframe
+ var kfPercents = [];
+ // Value of each keyframe
+ var kfValues = [];
+ var prevValue = keyframes[0].value;
+ var isAllValueEqual = true;
+ for (var i = 0; i < trackLen; i++) {
+ kfPercents.push(keyframes[i].time / trackMaxTime);
+ // Assume value is a color when it is a string
+ var value = keyframes[i].value;
+
+ // Check if value is equal, deep check if value is array
+ if (!((isValueArray && isArraySame(value, prevValue, arrDim))
+ || (!isValueArray && value === prevValue))) {
+ isAllValueEqual = false;
+ }
+ prevValue = value;
+
+ // Try converting a string to a color array
+ if (typeof value == 'string') {
+ var colorArray = color.parse(value);
+ if (colorArray) {
+ value = colorArray;
+ isValueColor = true;
+ }
+ else {
+ isValueString = true;
+ }
+ }
+ kfValues.push(value);
+ }
+ if (isAllValueEqual) {
+ return;
+ }
+
+ var lastValue = kfValues[trackLen - 1];
+ // Polyfill array and NaN value
+ for (var i = 0; i < trackLen - 1; i++) {
+ if (isValueArray) {
+ fillArr(kfValues[i], lastValue, arrDim);
+ }
+ else {
+ if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {
+ kfValues[i] = lastValue;
+ }
+ }
+ }
+ isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);
+
+ // Cache the key of last frame to speed up when
+ // animation playback is sequency
+ var lastFrame = 0;
+ var lastFramePercent = 0;
+ var start;
+ var w;
+ var p0;
+ var p1;
+ var p2;
+ var p3;
+
+ if (isValueColor) {
+ var rgba = [0, 0, 0, 0];
+ }
+
+ var onframe = function (target, percent) {
+ // Find the range keyframes
+ // kf1-----kf2---------current--------kf3
+ // find kf2 and kf3 and do interpolation
+ var frame;
+ // In the easing function like elasticOut, percent may less than 0
+ if (percent < 0) {
+ frame = 0;
+ }
+ else if (percent < lastFramePercent) {
+ // Start from next key
+ // PENDING start from lastFrame ?
+ start = Math.min(lastFrame + 1, trackLen - 1);
+ for (frame = start; frame >= 0; frame--) {
+ if (kfPercents[frame] <= percent) {
+ break;
+ }
+ }
+ // PENDING really need to do this ?
+ frame = Math.min(frame, trackLen - 2);
+ }
+ else {
+ for (frame = lastFrame; frame < trackLen; frame++) {
+ if (kfPercents[frame] > percent) {
+ break;
+ }
+ }
+ frame = Math.min(frame - 1, trackLen - 2);
+ }
+ lastFrame = frame;
+ lastFramePercent = percent;
+
+ var range = (kfPercents[frame + 1] - kfPercents[frame]);
+ if (range === 0) {
+ return;
+ }
+ else {
+ w = (percent - kfPercents[frame]) / range;
+ }
+ if (useSpline) {
+ p1 = kfValues[frame];
+ p0 = kfValues[frame === 0 ? frame : frame - 1];
+ p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];
+ p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];
+ if (isValueArray) {
+ catmullRomInterpolateArray(
+ p0, p1, p2, p3, w, w * w, w * w * w,
+ getter(target, propName),
+ arrDim
+ );
+ }
+ else {
+ var value;
+ if (isValueColor) {
+ value = catmullRomInterpolateArray(
+ p0, p1, p2, p3, w, w * w, w * w * w,
+ rgba, 1
+ );
+ value = rgba2String(rgba);
+ }
+ else if (isValueString) {
+ // String is step(0.5)
+ return interpolateString(p1, p2, w);
+ }
+ else {
+ value = catmullRomInterpolate(
+ p0, p1, p2, p3, w, w * w, w * w * w
+ );
+ }
+ setter(
+ target,
+ propName,
+ value
+ );
+ }
+ }
+ else {
+ if (isValueArray) {
+ interpolateArray(
+ kfValues[frame], kfValues[frame + 1], w,
+ getter(target, propName),
+ arrDim
+ );
+ }
+ else {
+ var value;
+ if (isValueColor) {
+ interpolateArray(
+ kfValues[frame], kfValues[frame + 1], w,
+ rgba, 1
+ );
+ value = rgba2String(rgba);
+ }
+ else if (isValueString) {
+ // String is step(0.5)
+ return interpolateString(kfValues[frame], kfValues[frame + 1], w);
+ }
+ else {
+ value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);
+ }
+ setter(
+ target,
+ propName,
+ value
+ );
+ }
+ }
+ };
+
+ var clip = new Clip({
+ target: animator._target,
+ life: trackMaxTime,
+ loop: animator._loop,
+ delay: animator._delay,
+ onframe: onframe,
+ ondestroy: oneTrackDone
+ });
+
+ if (easing && easing !== 'spline') {
+ clip.easing = easing;
+ }
+
+ return clip;
+ }
+
+ /**
+ * @alias module:zrender/animation/Animator
+ * @constructor
+ * @param {Object} target
+ * @param {boolean} loop
+ * @param {Function} getter
+ * @param {Function} setter
+ */
+ var Animator = function(target, loop, getter, setter) {
+ this._tracks = {};
+ this._target = target;
+
+ this._loop = loop || false;
+
+ this._getter = getter || defaultGetter;
+ this._setter = setter || defaultSetter;
+
+ this._clipCount = 0;
+
+ this._delay = 0;
+
+ this._doneList = [];
+
+ this._onframeList = [];
+
+ this._clipList = [];
+ };
+
+ Animator.prototype = {
+ /**
+ * 设置动画关键帧
+ * @param {number} time 关键帧时间,单位是ms
+ * @param {Object} props 关键帧的属性值,key-value表示
+ * @return {module:zrender/animation/Animator}
+ */
+ when: function(time /* ms */, props) {
+ var tracks = this._tracks;
+ for (var propName in props) {
+ if (!props.hasOwnProperty(propName)) {
+ continue;
+ }
+
+ if (!tracks[propName]) {
+ tracks[propName] = [];
+ // Invalid value
+ var value = this._getter(this._target, propName);
+ if (value == null) {
+ // zrLog('Invalid property ' + propName);
+ continue;
+ }
+ // If time is 0
+ // Then props is given initialize value
+ // Else
+ // Initialize value from current prop value
+ if (time !== 0) {
+ tracks[propName].push({
+ time: 0,
+ value: cloneValue(value)
+ });
+ }
+ }
+ tracks[propName].push({
+ time: time,
+ value: props[propName]
+ });
+ }
+ return this;
+ },
+ /**
+ * 添加动画每一帧的回调函数
+ * @param {Function} callback
+ * @return {module:zrender/animation/Animator}
+ */
+ during: function (callback) {
+ this._onframeList.push(callback);
+ return this;
+ },
+
+ pause: function () {
+ for (var i = 0; i < this._clipList.length; i++) {
+ this._clipList[i].pause();
+ }
+ this._paused = true;
+ },
+
+ resume: function () {
+ for (var i = 0; i < this._clipList.length; i++) {
+ this._clipList[i].resume();
+ }
+ this._paused = false;
+ },
+
+ isPaused: function () {
+ return !!this._paused;
+ },
+
+ _doneCallback: function () {
+ // Clear all tracks
+ this._tracks = {};
+ // Clear all clips
+ this._clipList.length = 0;
+
+ var doneList = this._doneList;
+ var len = doneList.length;
+ for (var i = 0; i < len; i++) {
+ doneList[i].call(this);
+ }
+ },
+ /**
+ * 开始执行动画
+ * @param {string|Function} easing
+ * 动画缓动函数,详见{@link module:zrender/animation/easing}
+ * @return {module:zrender/animation/Animator}
+ */
+ start: function (easing) {
+
+ var self = this;
+ var clipCount = 0;
+
+ var oneTrackDone = function() {
+ clipCount--;
+ if (!clipCount) {
+ self._doneCallback();
+ }
+ };
+
+ var lastClip;
+ for (var propName in this._tracks) {
+ if (!this._tracks.hasOwnProperty(propName)) {
+ continue;
+ }
+ var clip = createTrackClip(
+ this, easing, oneTrackDone,
+ this._tracks[propName], propName
+ );
+ if (clip) {
+ this._clipList.push(clip);
+ clipCount++;
+
+ // If start after added to animation
+ if (this.animation) {
+ this.animation.addClip(clip);
+ }
+
+ lastClip = clip;
+ }
+ }
+
+ // Add during callback on the last clip
+ if (lastClip) {
+ var oldOnFrame = lastClip.onframe;
+ lastClip.onframe = function (target, percent) {
+ oldOnFrame(target, percent);
+
+ for (var i = 0; i < self._onframeList.length; i++) {
+ self._onframeList[i](target, percent);
+ }
+ };
+ }
+
+ if (!clipCount) {
+ this._doneCallback();
+ }
+ return this;
+ },
+ /**
+ * 停止动画
+ * @param {boolean} forwardToLast If move to last frame before stop
+ */
+ stop: function (forwardToLast) {
+ var clipList = this._clipList;
+ var animation = this.animation;
+ for (var i = 0; i < clipList.length; i++) {
+ var clip = clipList[i];
+ if (forwardToLast) {
+ // Move to last frame before stop
+ clip.onframe(this._target, 1);
+ }
+ animation && animation.removeClip(clip);
+ }
+ clipList.length = 0;
+ },
+ /**
+ * 设置动画延迟开始的时间
+ * @param {number} time 单位ms
+ * @return {module:zrender/animation/Animator}
+ */
+ delay: function (time) {
+ this._delay = time;
+ return this;
+ },
+ /**
+ * 添加动画结束的回调
+ * @param {Function} cb
+ * @return {module:zrender/animation/Animator}
+ */
+ done: function(cb) {
+ if (cb) {
+ this._doneList.push(cb);
+ }
+ return this;
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getClips: function () {
+ return this._clipList;
+ }
+ };
+
+ module.exports = Animator;
+
+
+/***/ },
+/* 29 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 动画主控制器
+ * @config target 动画对象,可以是数组,如果是数组的话会批量分发onframe等事件
+ * @config life(1000) 动画时长
+ * @config delay(0) 动画延迟时间
+ * @config loop(true)
+ * @config gap(0) 循环的间隔时间
+ * @config onframe
+ * @config easing(optional)
+ * @config ondestroy(optional)
+ * @config onrestart(optional)
+ *
+ * TODO pause
+ */
+
+
+ var easingFuncs = __webpack_require__(30);
+
+ function Clip(options) {
+
+ this._target = options.target;
+
+ // 生命周期
+ this._life = options.life || 1000;
+ // 延时
+ this._delay = options.delay || 0;
+ // 开始时间
+ // this._startTime = new Date().getTime() + this._delay;// 单位毫秒
+ this._initialized = false;
+
+ // 是否循环
+ this.loop = options.loop == null ? false : options.loop;
+
+ this.gap = options.gap || 0;
+
+ this.easing = options.easing || 'Linear';
+
+ this.onframe = options.onframe;
+ this.ondestroy = options.ondestroy;
+ this.onrestart = options.onrestart;
+
+ this._pausedTime = 0;
+ this._paused = false;
+ }
+
+ Clip.prototype = {
+
+ constructor: Clip,
+
+ step: function (globalTime, deltaTime) {
+ // Set startTime on first step, or _startTime may has milleseconds different between clips
+ // PENDING
+ if (!this._initialized) {
+ this._startTime = globalTime + this._delay;
+ this._initialized = true;
+ }
+
+ if (this._paused) {
+ this._pausedTime += deltaTime;
+ return;
+ }
+
+ var percent = (globalTime - this._startTime - this._pausedTime) / this._life;
+
+ // 还没开始
+ if (percent < 0) {
+ return;
+ }
+
+ percent = Math.min(percent, 1);
+
+ var easing = this.easing;
+ var easingFunc = typeof easing == 'string' ? easingFuncs[easing] : easing;
+ var schedule = typeof easingFunc === 'function'
+ ? easingFunc(percent)
+ : percent;
+
+ this.fire('frame', schedule);
+
+ // 结束
+ if (percent == 1) {
+ if (this.loop) {
+ this.restart (globalTime);
+ // 重新开始周期
+ // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件
+ return 'restart';
+ }
+
+ // 动画完成将这个控制器标识为待删除
+ // 在Animation.update中进行批量删除
+ this._needsRemove = true;
+ return 'destroy';
+ }
+
+ return null;
+ },
+
+ restart: function (globalTime) {
+ var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
+ this._startTime = globalTime - remainder + this.gap;
+ this._pausedTime = 0;
+
+ this._needsRemove = false;
+ },
+
+ fire: function (eventType, arg) {
+ eventType = 'on' + eventType;
+ if (this[eventType]) {
+ this[eventType](this._target, arg);
+ }
+ },
+
+ pause: function () {
+ this._paused = true;
+ },
+
+ resume: function () {
+ this._paused = false;
+ }
+ };
+
+ module.exports = Clip;
+
+
+
+/***/ },
+/* 30 */
+/***/ function(module, exports) {
+
+ /**
+ * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js
+ * @see http://sole.github.io/tween.js/examples/03_graphs.html
+ * @exports zrender/animation/easing
+ */
+
+ var easing = {
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ linear: function (k) {
+ return k;
+ },
+
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quadraticIn: function (k) {
+ return k * k;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quadraticOut: function (k) {
+ return k * (2 - k);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quadraticInOut: function (k) {
+ if ((k *= 2) < 1) {
+ return 0.5 * k * k;
+ }
+ return -0.5 * (--k * (k - 2) - 1);
+ },
+
+ // 三次方的缓动(t^3)
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ cubicIn: function (k) {
+ return k * k * k;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ cubicOut: function (k) {
+ return --k * k * k + 1;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ cubicInOut: function (k) {
+ if ((k *= 2) < 1) {
+ return 0.5 * k * k * k;
+ }
+ return 0.5 * ((k -= 2) * k * k + 2);
+ },
+
+ // 四次方的缓动(t^4)
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quarticIn: function (k) {
+ return k * k * k * k;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quarticOut: function (k) {
+ return 1 - (--k * k * k * k);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quarticInOut: function (k) {
+ if ((k *= 2) < 1) {
+ return 0.5 * k * k * k * k;
+ }
+ return -0.5 * ((k -= 2) * k * k * k - 2);
+ },
+
+ // 五次方的缓动(t^5)
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quinticIn: function (k) {
+ return k * k * k * k * k;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quinticOut: function (k) {
+ return --k * k * k * k * k + 1;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ quinticInOut: function (k) {
+ if ((k *= 2) < 1) {
+ return 0.5 * k * k * k * k * k;
+ }
+ return 0.5 * ((k -= 2) * k * k * k * k + 2);
+ },
+
+ // 正弦曲线的缓动(sin(t))
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ sinusoidalIn: function (k) {
+ return 1 - Math.cos(k * Math.PI / 2);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ sinusoidalOut: function (k) {
+ return Math.sin(k * Math.PI / 2);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ sinusoidalInOut: function (k) {
+ return 0.5 * (1 - Math.cos(Math.PI * k));
+ },
+
+ // 指数曲线的缓动(2^t)
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ exponentialIn: function (k) {
+ return k === 0 ? 0 : Math.pow(1024, k - 1);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ exponentialOut: function (k) {
+ return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ exponentialInOut: function (k) {
+ if (k === 0) {
+ return 0;
+ }
+ if (k === 1) {
+ return 1;
+ }
+ if ((k *= 2) < 1) {
+ return 0.5 * Math.pow(1024, k - 1);
+ }
+ return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
+ },
+
+ // 圆形曲线的缓动(sqrt(1-t^2))
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ circularIn: function (k) {
+ return 1 - Math.sqrt(1 - k * k);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ circularOut: function (k) {
+ return Math.sqrt(1 - (--k * k));
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ circularInOut: function (k) {
+ if ((k *= 2) < 1) {
+ return -0.5 * (Math.sqrt(1 - k * k) - 1);
+ }
+ return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
+ },
+
+ // 创建类似于弹簧在停止前来回振荡的动画
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ elasticIn: function (k) {
+ var s;
+ var a = 0.1;
+ var p = 0.4;
+ if (k === 0) {
+ return 0;
+ }
+ if (k === 1) {
+ return 1;
+ }
+ if (!a || a < 1) {
+ a = 1; s = p / 4;
+ }
+ else {
+ s = p * Math.asin(1 / a) / (2 * Math.PI);
+ }
+ return -(a * Math.pow(2, 10 * (k -= 1)) *
+ Math.sin((k - s) * (2 * Math.PI) / p));
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ elasticOut: function (k) {
+ var s;
+ var a = 0.1;
+ var p = 0.4;
+ if (k === 0) {
+ return 0;
+ }
+ if (k === 1) {
+ return 1;
+ }
+ if (!a || a < 1) {
+ a = 1; s = p / 4;
+ }
+ else {
+ s = p * Math.asin(1 / a) / (2 * Math.PI);
+ }
+ return (a * Math.pow(2, -10 * k) *
+ Math.sin((k - s) * (2 * Math.PI) / p) + 1);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ elasticInOut: function (k) {
+ var s;
+ var a = 0.1;
+ var p = 0.4;
+ if (k === 0) {
+ return 0;
+ }
+ if (k === 1) {
+ return 1;
+ }
+ if (!a || a < 1) {
+ a = 1; s = p / 4;
+ }
+ else {
+ s = p * Math.asin(1 / a) / (2 * Math.PI);
+ }
+ if ((k *= 2) < 1) {
+ return -0.5 * (a * Math.pow(2, 10 * (k -= 1))
+ * Math.sin((k - s) * (2 * Math.PI) / p));
+ }
+ return a * Math.pow(2, -10 * (k -= 1))
+ * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
+
+ },
+
+ // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ backIn: function (k) {
+ var s = 1.70158;
+ return k * k * ((s + 1) * k - s);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ backOut: function (k) {
+ var s = 1.70158;
+ return --k * k * ((s + 1) * k + s) + 1;
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ backInOut: function (k) {
+ var s = 1.70158 * 1.525;
+ if ((k *= 2) < 1) {
+ return 0.5 * (k * k * ((s + 1) * k - s));
+ }
+ return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
+ },
+
+ // 创建弹跳效果
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ bounceIn: function (k) {
+ return 1 - easing.bounceOut(1 - k);
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ bounceOut: function (k) {
+ if (k < (1 / 2.75)) {
+ return 7.5625 * k * k;
+ }
+ else if (k < (2 / 2.75)) {
+ return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
+ }
+ else if (k < (2.5 / 2.75)) {
+ return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
+ }
+ else {
+ return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
+ }
+ },
+ /**
+ * @param {number} k
+ * @return {number}
+ */
+ bounceInOut: function (k) {
+ if (k < 0.5) {
+ return easing.bounceIn(k * 2) * 0.5;
+ }
+ return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
+ }
+ };
+
+ module.exports = easing;
+
+
+
+
+/***/ },
+/* 31 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @module zrender/tool/color
+ */
+
+
+ var LRU = __webpack_require__(32);
+
+ var kCSSColorTable = {
+ 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1],
+ 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1],
+ 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1],
+ 'beige': [245,245,220,1], 'bisque': [255,228,196,1],
+ 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1],
+ 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1],
+ 'brown': [165,42,42,1], 'burlywood': [222,184,135,1],
+ 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1],
+ 'chocolate': [210,105,30,1], 'coral': [255,127,80,1],
+ 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1],
+ 'crimson': [220,20,60,1], 'cyan': [0,255,255,1],
+ 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1],
+ 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1],
+ 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1],
+ 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1],
+ 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1],
+ 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1],
+ 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1],
+ 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1],
+ 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1],
+ 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1],
+ 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1],
+ 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1],
+ 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1],
+ 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1],
+ 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1],
+ 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1],
+ 'gray': [128,128,128,1], 'green': [0,128,0,1],
+ 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1],
+ 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1],
+ 'indianred': [205,92,92,1], 'indigo': [75,0,130,1],
+ 'ivory': [255,255,240,1], 'khaki': [240,230,140,1],
+ 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1],
+ 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1],
+ 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1],
+ 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1],
+ 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1],
+ 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1],
+ 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1],
+ 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1],
+ 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1],
+ 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1],
+ 'limegreen': [50,205,50,1], 'linen': [250,240,230,1],
+ 'magenta': [255,0,255,1], 'maroon': [128,0,0,1],
+ 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1],
+ 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1],
+ 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1],
+ 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1],
+ 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1],
+ 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1],
+ 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1],
+ 'navy': [0,0,128,1], 'oldlace': [253,245,230,1],
+ 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1],
+ 'orange': [255,165,0,1], 'orangered': [255,69,0,1],
+ 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1],
+ 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1],
+ 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1],
+ 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1],
+ 'pink': [255,192,203,1], 'plum': [221,160,221,1],
+ 'powderblue': [176,224,230,1], 'purple': [128,0,128,1],
+ 'red': [255,0,0,1], 'rosybrown': [188,143,143,1],
+ 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1],
+ 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1],
+ 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1],
+ 'sienna': [160,82,45,1], 'silver': [192,192,192,1],
+ 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1],
+ 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1],
+ 'snow': [255,250,250,1], 'springgreen': [0,255,127,1],
+ 'steelblue': [70,130,180,1], 'tan': [210,180,140,1],
+ 'teal': [0,128,128,1], 'thistle': [216,191,216,1],
+ 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1],
+ 'violet': [238,130,238,1], 'wheat': [245,222,179,1],
+ 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1],
+ 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1]
+ };
+
+ function clampCssByte(i) { // Clamp to integer 0 .. 255.
+ i = Math.round(i); // Seems to be what Chrome does (vs truncation).
+ return i < 0 ? 0 : i > 255 ? 255 : i;
+ }
+
+ function clampCssAngle(i) { // Clamp to integer 0 .. 360.
+ i = Math.round(i); // Seems to be what Chrome does (vs truncation).
+ return i < 0 ? 0 : i > 360 ? 360 : i;
+ }
+
+ function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0.
+ return f < 0 ? 0 : f > 1 ? 1 : f;
+ }
+
+ function parseCssInt(str) { // int or percentage.
+ if (str.length && str.charAt(str.length - 1) === '%') {
+ return clampCssByte(parseFloat(str) / 100 * 255);
+ }
+ return clampCssByte(parseInt(str, 10));
+ }
+
+ function parseCssFloat(str) { // float or percentage.
+ if (str.length && str.charAt(str.length - 1) === '%') {
+ return clampCssFloat(parseFloat(str) / 100);
+ }
+ return clampCssFloat(parseFloat(str));
+ }
+
+ function cssHueToRgb(m1, m2, h) {
+ if (h < 0) {
+ h += 1;
+ }
+ else if (h > 1) {
+ h -= 1;
+ }
+
+ if (h * 6 < 1) {
+ return m1 + (m2 - m1) * h * 6;
+ }
+ if (h * 2 < 1) {
+ return m2;
+ }
+ if (h * 3 < 2) {
+ return m1 + (m2 - m1) * (2/3 - h) * 6;
+ }
+ return m1;
+ }
+
+ function lerp(a, b, p) {
+ return a + (b - a) * p;
+ }
+
+ function setRgba(out, r, g, b, a) {
+ out[0] = r; out[1] = g; out[2] = b; out[3] = a;
+ return out;
+ }
+ function copyRgba(out, a) {
+ out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];
+ return out;
+ }
+ var colorCache = new LRU(20);
+ var lastRemovedArr = null;
+ function putToCache(colorStr, rgbaArr) {
+ // Reuse removed array
+ if (lastRemovedArr) {
+ copyRgba(lastRemovedArr, rgbaArr);
+ }
+ lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));
+ }
+ /**
+ * @param {string} colorStr
+ * @param {Array.} out
+ * @return {Array.}
+ * @memberOf module:zrender/util/color
+ */
+ function parse(colorStr, rgbaArr) {
+ if (!colorStr) {
+ return;
+ }
+ rgbaArr = rgbaArr || [];
+
+ var cached = colorCache.get(colorStr);
+ if (cached) {
+ return copyRgba(rgbaArr, cached);
+ }
+
+ // colorStr may be not string
+ colorStr = colorStr + '';
+ // Remove all whitespace, not compliant, but should just be more accepting.
+ var str = colorStr.replace(/ /g, '').toLowerCase();
+
+ // Color keywords (and transparent) lookup.
+ if (str in kCSSColorTable) {
+ copyRgba(rgbaArr, kCSSColorTable[str]);
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ }
+
+ // #abc and #abc123 syntax.
+ if (str.charAt(0) === '#') {
+ if (str.length === 4) {
+ var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
+ if (!(iv >= 0 && iv <= 0xfff)) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return; // Covers NaN.
+ }
+ setRgba(rgbaArr,
+ ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
+ (iv & 0xf0) | ((iv & 0xf0) >> 4),
+ (iv & 0xf) | ((iv & 0xf) << 4),
+ 1
+ );
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ }
+ else if (str.length === 7) {
+ var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
+ if (!(iv >= 0 && iv <= 0xffffff)) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return; // Covers NaN.
+ }
+ setRgba(rgbaArr,
+ (iv & 0xff0000) >> 16,
+ (iv & 0xff00) >> 8,
+ iv & 0xff,
+ 1
+ );
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ }
+
+ return;
+ }
+ var op = str.indexOf('('), ep = str.indexOf(')');
+ if (op !== -1 && ep + 1 === str.length) {
+ var fname = str.substr(0, op);
+ var params = str.substr(op + 1, ep - (op + 1)).split(',');
+ var alpha = 1; // To allow case fallthrough.
+ switch (fname) {
+ case 'rgba':
+ if (params.length !== 4) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return;
+ }
+ alpha = parseCssFloat(params.pop()); // jshint ignore:line
+ // Fall through.
+ case 'rgb':
+ if (params.length !== 3) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return;
+ }
+ setRgba(rgbaArr,
+ parseCssInt(params[0]),
+ parseCssInt(params[1]),
+ parseCssInt(params[2]),
+ alpha
+ );
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ case 'hsla':
+ if (params.length !== 4) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return;
+ }
+ params[3] = parseCssFloat(params[3]);
+ hsla2rgba(params, rgbaArr);
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ case 'hsl':
+ if (params.length !== 3) {
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return;
+ }
+ hsla2rgba(params, rgbaArr);
+ putToCache(colorStr, rgbaArr);
+ return rgbaArr;
+ default:
+ return;
+ }
+ }
+
+ setRgba(rgbaArr, 0, 0, 0, 1);
+ return;
+ }
+
+ /**
+ * @param {Array.} hsla
+ * @param {Array.} rgba
+ * @return {Array.} rgba
+ */
+ function hsla2rgba(hsla, rgba) {
+ var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1
+ // NOTE(deanm): According to the CSS spec s/l should only be
+ // percentages, but we don't bother and let float or percentage.
+ var s = parseCssFloat(hsla[1]);
+ var l = parseCssFloat(hsla[2]);
+ var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
+ var m1 = l * 2 - m2;
+
+ rgba = rgba || [];
+ setRgba(rgba,
+ clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),
+ clampCssByte(cssHueToRgb(m1, m2, h) * 255),
+ clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),
+ 1
+ );
+
+ if (hsla.length === 4) {
+ rgba[3] = hsla[3];
+ }
+
+ return rgba;
+ }
+
+ /**
+ * @param {Array.} rgba
+ * @return {Array.} hsla
+ */
+ function rgba2hsla(rgba) {
+ if (!rgba) {
+ return;
+ }
+
+ // RGB from 0 to 255
+ var R = rgba[0] / 255;
+ var G = rgba[1] / 255;
+ var B = rgba[2] / 255;
+
+ var vMin = Math.min(R, G, B); // Min. value of RGB
+ var vMax = Math.max(R, G, B); // Max. value of RGB
+ var delta = vMax - vMin; // Delta RGB value
+
+ var L = (vMax + vMin) / 2;
+ var H;
+ var S;
+ // HSL results from 0 to 1
+ if (delta === 0) {
+ H = 0;
+ S = 0;
+ }
+ else {
+ if (L < 0.5) {
+ S = delta / (vMax + vMin);
+ }
+ else {
+ S = delta / (2 - vMax - vMin);
+ }
+
+ var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
+ var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
+ var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
+
+ if (R === vMax) {
+ H = deltaB - deltaG;
+ }
+ else if (G === vMax) {
+ H = (1 / 3) + deltaR - deltaB;
+ }
+ else if (B === vMax) {
+ H = (2 / 3) + deltaG - deltaR;
+ }
+
+ if (H < 0) {
+ H += 1;
+ }
+
+ if (H > 1) {
+ H -= 1;
+ }
+ }
+
+ var hsla = [H * 360, S, L];
+
+ if (rgba[3] != null) {
+ hsla.push(rgba[3]);
+ }
+
+ return hsla;
+ }
+
+ /**
+ * @param {string} color
+ * @param {number} level
+ * @return {string}
+ * @memberOf module:zrender/util/color
+ */
+ function lift(color, level) {
+ var colorArr = parse(color);
+ if (colorArr) {
+ for (var i = 0; i < 3; i++) {
+ if (level < 0) {
+ colorArr[i] = colorArr[i] * (1 - level) | 0;
+ }
+ else {
+ colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
+ }
+ }
+ return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
+ }
+ }
+
+ /**
+ * @param {string} color
+ * @return {string}
+ * @memberOf module:zrender/util/color
+ */
+ function toHex(color, level) {
+ var colorArr = parse(color);
+ if (colorArr) {
+ return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
+ }
+ }
+
+ /**
+ * Map value to color. Faster than mapToColor methods because color is represented by rgba array.
+ * @param {number} normalizedValue A float between 0 and 1.
+ * @param {Array.>} colors List of rgba color array
+ * @param {Array.} [out] Mapped gba color array
+ * @return {Array.} will be null/undefined if input illegal.
+ */
+ function fastMapToColor(normalizedValue, colors, out) {
+ if (!(colors && colors.length)
+ || !(normalizedValue >= 0 && normalizedValue <= 1)
+ ) {
+ return;
+ }
+
+ out = out || [];
+
+ var value = normalizedValue * (colors.length - 1);
+ var leftIndex = Math.floor(value);
+ var rightIndex = Math.ceil(value);
+ var leftColor = colors[leftIndex];
+ var rightColor = colors[rightIndex];
+ var dv = value - leftIndex;
+ out[0] = clampCssByte(lerp(leftColor[0], rightColor[0], dv));
+ out[1] = clampCssByte(lerp(leftColor[1], rightColor[1], dv));
+ out[2] = clampCssByte(lerp(leftColor[2], rightColor[2], dv));
+ out[3] = clampCssFloat(lerp(leftColor[3], rightColor[3], dv));
+
+ return out;
+ }
+ /**
+ * @param {number} normalizedValue A float between 0 and 1.
+ * @param {Array.} colors Color list.
+ * @param {boolean=} fullOutput Default false.
+ * @return {(string|Object)} Result color. If fullOutput,
+ * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},
+ * @memberOf module:zrender/util/color
+ */
+ function mapToColor(normalizedValue, colors, fullOutput) {
+ if (!(colors && colors.length)
+ || !(normalizedValue >= 0 && normalizedValue <= 1)
+ ) {
+ return;
+ }
+
+ var value = normalizedValue * (colors.length - 1);
+ var leftIndex = Math.floor(value);
+ var rightIndex = Math.ceil(value);
+ var leftColor = parse(colors[leftIndex]);
+ var rightColor = parse(colors[rightIndex]);
+ var dv = value - leftIndex;
+
+ var color = stringify(
+ [
+ clampCssByte(lerp(leftColor[0], rightColor[0], dv)),
+ clampCssByte(lerp(leftColor[1], rightColor[1], dv)),
+ clampCssByte(lerp(leftColor[2], rightColor[2], dv)),
+ clampCssFloat(lerp(leftColor[3], rightColor[3], dv))
+ ],
+ 'rgba'
+ );
+
+ return fullOutput
+ ? {
+ color: color,
+ leftIndex: leftIndex,
+ rightIndex: rightIndex,
+ value: value
+ }
+ : color;
+ }
+
+ /**
+ * @param {string} color
+ * @param {number=} h 0 ~ 360, ignore when null.
+ * @param {number=} s 0 ~ 1, ignore when null.
+ * @param {number=} l 0 ~ 1, ignore when null.
+ * @return {string} Color string in rgba format.
+ * @memberOf module:zrender/util/color
+ */
+ function modifyHSL(color, h, s, l) {
+ color = parse(color);
+
+ if (color) {
+ color = rgba2hsla(color);
+ h != null && (color[0] = clampCssAngle(h));
+ s != null && (color[1] = parseCssFloat(s));
+ l != null && (color[2] = parseCssFloat(l));
+
+ return stringify(hsla2rgba(color), 'rgba');
+ }
+ }
+
+ /**
+ * @param {string} color
+ * @param {number=} alpha 0 ~ 1
+ * @return {string} Color string in rgba format.
+ * @memberOf module:zrender/util/color
+ */
+ function modifyAlpha(color, alpha) {
+ color = parse(color);
+
+ if (color && alpha != null) {
+ color[3] = clampCssFloat(alpha);
+ return stringify(color, 'rgba');
+ }
+ }
+
+ /**
+ * @param {Array.} arrColor like [12,33,44,0.4]
+ * @param {string} type 'rgba', 'hsva', ...
+ * @return {string} Result color. (If input illegal, return undefined).
+ */
+ function stringify(arrColor, type) {
+ if (!arrColor || !arrColor.length) {
+ return;
+ }
+ var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
+ if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
+ colorStr += ',' + arrColor[3];
+ }
+ return type + '(' + colorStr + ')';
+ }
+
+ module.exports = {
+ parse: parse,
+ lift: lift,
+ toHex: toHex,
+ fastMapToColor: fastMapToColor,
+ mapToColor: mapToColor,
+ modifyHSL: modifyHSL,
+ modifyAlpha: modifyAlpha,
+ stringify: stringify
+ };
+
+
+
+
+/***/ },
+/* 32 */
+/***/ function(module, exports) {
+
+ // Simple LRU cache use doubly linked list
+ // @module zrender/core/LRU
+
+
+ /**
+ * Simple double linked list. Compared with array, it has O(1) remove operation.
+ * @constructor
+ */
+ var LinkedList = function () {
+
+ /**
+ * @type {module:zrender/core/LRU~Entry}
+ */
+ this.head = null;
+
+ /**
+ * @type {module:zrender/core/LRU~Entry}
+ */
+ this.tail = null;
+
+ this._len = 0;
+ };
+
+ var linkedListProto = LinkedList.prototype;
+ /**
+ * Insert a new value at the tail
+ * @param {} val
+ * @return {module:zrender/core/LRU~Entry}
+ */
+ linkedListProto.insert = function (val) {
+ var entry = new Entry(val);
+ this.insertEntry(entry);
+ return entry;
+ };
+
+ /**
+ * Insert an entry at the tail
+ * @param {module:zrender/core/LRU~Entry} entry
+ */
+ linkedListProto.insertEntry = function (entry) {
+ if (!this.head) {
+ this.head = this.tail = entry;
+ }
+ else {
+ this.tail.next = entry;
+ entry.prev = this.tail;
+ entry.next = null;
+ this.tail = entry;
+ }
+ this._len++;
+ };
+
+ /**
+ * Remove entry.
+ * @param {module:zrender/core/LRU~Entry} entry
+ */
+ linkedListProto.remove = function (entry) {
+ var prev = entry.prev;
+ var next = entry.next;
+ if (prev) {
+ prev.next = next;
+ }
+ else {
+ // Is head
+ this.head = next;
+ }
+ if (next) {
+ next.prev = prev;
+ }
+ else {
+ // Is tail
+ this.tail = prev;
+ }
+ entry.next = entry.prev = null;
+ this._len--;
+ };
+
+ /**
+ * @return {number}
+ */
+ linkedListProto.len = function () {
+ return this._len;
+ };
+
+ /**
+ * Clear list
+ */
+ linkedListProto.clear = function () {
+ this.head = this.tail = null;
+ this._len = 0;
+ };
+
+ /**
+ * @constructor
+ * @param {} val
+ */
+ var Entry = function (val) {
+ /**
+ * @type {}
+ */
+ this.value = val;
+
+ /**
+ * @type {module:zrender/core/LRU~Entry}
+ */
+ this.next;
+
+ /**
+ * @type {module:zrender/core/LRU~Entry}
+ */
+ this.prev;
+ };
+
+ /**
+ * LRU Cache
+ * @constructor
+ * @alias module:zrender/core/LRU
+ */
+ var LRU = function (maxSize) {
+
+ this._list = new LinkedList();
+
+ this._map = {};
+
+ this._maxSize = maxSize || 10;
+
+ this._lastRemovedEntry = null;
+ };
+
+ var LRUProto = LRU.prototype;
+
+ /**
+ * @param {string} key
+ * @param {} value
+ * @return {} Removed value
+ */
+ LRUProto.put = function (key, value) {
+ var list = this._list;
+ var map = this._map;
+ var removed = null;
+ if (map[key] == null) {
+ var len = list.len();
+ // Reuse last removed entry
+ var entry = this._lastRemovedEntry;
+
+ if (len >= this._maxSize && len > 0) {
+ // Remove the least recently used
+ var leastUsedEntry = list.head;
+ list.remove(leastUsedEntry);
+ delete map[leastUsedEntry.key];
+
+ removed = leastUsedEntry.value;
+ this._lastRemovedEntry = leastUsedEntry;
+ }
+
+ if (entry) {
+ entry.value = value;
+ }
+ else {
+ entry = new Entry(value);
+ }
+ entry.key = key;
+ list.insertEntry(entry);
+ map[key] = entry;
+ }
+
+ return removed;
+ };
+
+ /**
+ * @param {string} key
+ * @return {}
+ */
+ LRUProto.get = function (key) {
+ var entry = this._map[key];
+ var list = this._list;
+ if (entry != null) {
+ // Put the latest used entry in the tail
+ if (entry !== list.tail) {
+ list.remove(entry);
+ list.insertEntry(entry);
+ }
+
+ return entry.value;
+ }
+ };
+
+ /**
+ * Clear the cache
+ */
+ LRUProto.clear = function () {
+ this._list.clear();
+ this._map = {};
+ };
+
+ module.exports = LRU;
+
+
+/***/ },
+/* 33 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ var config = __webpack_require__(34);
+
+ /**
+ * @exports zrender/tool/log
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ */
+ module.exports = function() {
+ if (config.debugMode === 0) {
+ return;
+ }
+ else if (config.debugMode == 1) {
+ for (var k in arguments) {
+ throw new Error(arguments[k]);
+ }
+ }
+ else if (config.debugMode > 1) {
+ for (var k in arguments) {
+ console.log(arguments[k]);
+ }
+ }
+ };
+
+ /* for debug
+ return function(mes) {
+ document.getElementById('wrong-message').innerHTML =
+ mes + ' ' + (new Date() - 0)
+ + ' '
+ + document.getElementById('wrong-message').innerHTML;
+ };
+ */
+
+
+
+/***/ },
+/* 34 */
+/***/ function(module, exports) {
+
+
+ var dpr = 1;
+ // If in browser environment
+ if (typeof window !== 'undefined') {
+ dpr = Math.max(window.devicePixelRatio || 1, 1);
+ }
+ /**
+ * config默认配置项
+ * @exports zrender/config
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ */
+ var config = {
+ /**
+ * debug日志选项:catchBrushException为true下有效
+ * 0 : 不生成debug数据,发布用
+ * 1 : 异常抛出,调试用
+ * 2 : 控制台输出,调试用
+ */
+ debugMode: 0,
+
+ // retina 屏幕优化
+ devicePixelRatio: dpr
+ };
+ module.exports = config;
+
+
+
+
+/***/ },
+/* 35 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Mixin for drawing text in a element bounding rect
+ * @module zrender/mixin/RectText
+ */
+
+
+
+ var textContain = __webpack_require__(8);
+ var BoundingRect = __webpack_require__(9);
+
+ var tmpRect = new BoundingRect();
+
+ var RectText = function () {};
+
+ function parsePercent(value, maxValue) {
+ if (typeof value === 'string') {
+ if (value.lastIndexOf('%') >= 0) {
+ return parseFloat(value) / 100 * maxValue;
+ }
+ return parseFloat(value);
+ }
+ return value;
+ }
+
+ RectText.prototype = {
+
+ constructor: RectText,
+
+ /**
+ * Draw text in a rect with specified position.
+ * @param {CanvasRenderingContext} ctx
+ * @param {Object} rect Displayable rect
+ * @return {Object} textRect Alternative precalculated text bounding rect
+ */
+ drawRectText: function (ctx, rect, textRect) {
+ var style = this.style;
+ var text = style.text;
+ // Convert to string
+ text != null && (text += '');
+ if (!text) {
+ return;
+ }
+
+ // FIXME
+ ctx.save();
+
+ var x;
+ var y;
+ var textPosition = style.textPosition;
+ var textOffset = style.textOffset;
+ var distance = style.textDistance;
+ var align = style.textAlign;
+ var font = style.textFont || style.font;
+ var baseline = style.textBaseline;
+ var verticalAlign = style.textVerticalAlign;
+ rect = style.textPositionRect || rect;
+
+ textRect = textRect || textContain.getBoundingRect(text, font, align, baseline);
+
+ // Transform rect to view space
+ var transform = this.transform;
+ if (!style.textTransform) {
+ if (transform) {
+ tmpRect.copy(rect);
+ tmpRect.applyTransform(transform);
+ rect = tmpRect;
+ }
+ }
+ else {
+ this.setTransform(ctx);
+ }
+
+ // Text position represented by coord
+ if (textPosition instanceof Array) {
+ // Percent
+ x = rect.x + parsePercent(textPosition[0], rect.width);
+ y = rect.y + parsePercent(textPosition[1], rect.height);
+ align = align || 'left';
+ baseline = baseline || 'top';
+
+ if (verticalAlign) {
+ switch (verticalAlign) {
+ case 'middle':
+ y -= textRect.height / 2 - textRect.lineHeight / 2;
+ break;
+ case 'bottom':
+ y -= textRect.height - textRect.lineHeight / 2;
+ break;
+ default:
+ y += textRect.lineHeight / 2;
+ }
+ // Force bseline to be middle
+ baseline = 'middle';
+ }
+ }
+ else {
+ var res = textContain.adjustTextPositionOnRect(
+ textPosition, rect, textRect, distance
+ );
+ x = res.x;
+ y = res.y;
+ // Default align and baseline when has textPosition
+ align = align || res.textAlign;
+ baseline = baseline || res.textBaseline;
+ }
+
+ if (textOffset) {
+ x += textOffset[0];
+ y += textOffset[1];
+ }
+
+ // Use canvas default left textAlign. Giving invalid value will cause state not change
+ ctx.textAlign = align || 'left';
+ // Use canvas default alphabetic baseline
+ ctx.textBaseline = baseline || 'alphabetic';
+
+ var textFill = style.textFill;
+ var textStroke = style.textStroke;
+ textFill && (ctx.fillStyle = textFill);
+ textStroke && (ctx.strokeStyle = textStroke);
+
+ // TODO Invalid font
+ ctx.font = font || '12px sans-serif';
+
+ // Text shadow
+ // Always set shadowBlur and shadowOffset to avoid leak from displayable
+ ctx.shadowBlur = style.textShadowBlur;
+ ctx.shadowColor = style.textShadowColor || 'transparent';
+ ctx.shadowOffsetX = style.textShadowOffsetX;
+ ctx.shadowOffsetY = style.textShadowOffsetY;
+
+ var textLines = text.split('\n');
+
+ if (style.textRotation) {
+ transform && ctx.translate(transform[4], transform[5]);
+ ctx.rotate(style.textRotation);
+ transform && ctx.translate(-transform[4], -transform[5]);
+ }
+
+ for (var i = 0; i < textLines.length; i++) {
+ // Fill after stroke so the outline will not cover the main part.
+ textStroke && ctx.strokeText(textLines[i], x, y);
+ textFill && ctx.fillText(textLines[i], x, y);
+ y += textRect.lineHeight;
+ }
+
+ ctx.restore();
+ }
+ };
+
+ module.exports = RectText;
+
+
+/***/ },
+/* 36 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * Path 代理,可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中
+ * 可以用于 isInsidePath 判断以及获取boundingRect
+ *
+ * @module zrender/core/PathProxy
+ * @author Yi Shen (http://www.github.com/pissang)
+ */
+
+ // TODO getTotalLength, getPointAtLength
+
+
+ var curve = __webpack_require__(37);
+ var vec2 = __webpack_require__(10);
+ var bbox = __webpack_require__(38);
+ var BoundingRect = __webpack_require__(9);
+ var dpr = __webpack_require__(34).devicePixelRatio;
+
+ var CMD = {
+ M: 1,
+ L: 2,
+ C: 3,
+ Q: 4,
+ A: 5,
+ Z: 6,
+ // Rect
+ R: 7
+ };
+
+ // var CMD_MEM_SIZE = {
+ // M: 3,
+ // L: 3,
+ // C: 7,
+ // Q: 5,
+ // A: 9,
+ // R: 5,
+ // Z: 1
+ // };
+
+ var min = [];
+ var max = [];
+ var min2 = [];
+ var max2 = [];
+ var mathMin = Math.min;
+ var mathMax = Math.max;
+ var mathCos = Math.cos;
+ var mathSin = Math.sin;
+ var mathSqrt = Math.sqrt;
+ var mathAbs = Math.abs;
+
+ var hasTypedArray = typeof Float32Array != 'undefined';
+
+ /**
+ * @alias module:zrender/core/PathProxy
+ * @constructor
+ */
+ var PathProxy = function (notSaveData) {
+
+ this._saveData = !(notSaveData || false);
+
+ if (this._saveData) {
+ /**
+ * Path data. Stored as flat array
+ * @type {Array.}
+ */
+ this.data = [];
+ }
+
+ this._ctx = null;
+ };
+
+ /**
+ * 快速计算Path包围盒(并不是最小包围盒)
+ * @return {Object}
+ */
+ PathProxy.prototype = {
+
+ constructor: PathProxy,
+
+ _xi: 0,
+ _yi: 0,
+
+ _x0: 0,
+ _y0: 0,
+ // Unit x, Unit y. Provide for avoiding drawing that too short line segment
+ _ux: 0,
+ _uy: 0,
+
+ _len: 0,
+
+ _lineDash: null,
+
+ _dashOffset: 0,
+
+ _dashIdx: 0,
+
+ _dashSum: 0,
+
+ /**
+ * @readOnly
+ */
+ setScale: function (sx, sy) {
+ this._ux = mathAbs(1 / dpr / sx) || 0;
+ this._uy = mathAbs(1 / dpr / sy) || 0;
+ },
+
+ getContext: function () {
+ return this._ctx;
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ * @return {module:zrender/core/PathProxy}
+ */
+ beginPath: function (ctx) {
+
+ this._ctx = ctx;
+
+ ctx && ctx.beginPath();
+
+ ctx && (this.dpr = ctx.dpr);
+
+ // Reset
+ if (this._saveData) {
+ this._len = 0;
+ }
+
+ if (this._lineDash) {
+ this._lineDash = null;
+
+ this._dashOffset = 0;
+ }
+
+ return this;
+ },
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {module:zrender/core/PathProxy}
+ */
+ moveTo: function (x, y) {
+ this.addData(CMD.M, x, y);
+ this._ctx && this._ctx.moveTo(x, y);
+
+ // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用
+ // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。
+ // 有可能在 beginPath 之后直接调用 lineTo,这时候 x0, y0 需要
+ // 在 lineTo 方法中记录,这里先不考虑这种情况,dashed line 也只在 IE10- 中不支持
+ this._x0 = x;
+ this._y0 = y;
+
+ this._xi = x;
+ this._yi = y;
+
+ return this;
+ },
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {module:zrender/core/PathProxy}
+ */
+ lineTo: function (x, y) {
+ var exceedUnit = mathAbs(x - this._xi) > this._ux
+ || mathAbs(y - this._yi) > this._uy
+ // Force draw the first segment
+ || this._len < 5;
+
+ this.addData(CMD.L, x, y);
+
+ if (this._ctx && exceedUnit) {
+ this._needsDash() ? this._dashedLineTo(x, y)
+ : this._ctx.lineTo(x, y);
+ }
+ if (exceedUnit) {
+ this._xi = x;
+ this._yi = y;
+ }
+
+ return this;
+ },
+
+ /**
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} x3
+ * @param {number} y3
+ * @return {module:zrender/core/PathProxy}
+ */
+ bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {
+ this.addData(CMD.C, x1, y1, x2, y2, x3, y3);
+ if (this._ctx) {
+ this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
+ : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
+ }
+ this._xi = x3;
+ this._yi = y3;
+ return this;
+ },
+
+ /**
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @return {module:zrender/core/PathProxy}
+ */
+ quadraticCurveTo: function (x1, y1, x2, y2) {
+ this.addData(CMD.Q, x1, y1, x2, y2);
+ if (this._ctx) {
+ this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)
+ : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
+ }
+ this._xi = x2;
+ this._yi = y2;
+ return this;
+ },
+
+ /**
+ * @param {number} cx
+ * @param {number} cy
+ * @param {number} r
+ * @param {number} startAngle
+ * @param {number} endAngle
+ * @param {boolean} anticlockwise
+ * @return {module:zrender/core/PathProxy}
+ */
+ arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {
+ this.addData(
+ CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1
+ );
+ this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
+
+ this._xi = mathCos(endAngle) * r + cx;
+ this._yi = mathSin(endAngle) * r + cx;
+ return this;
+ },
+
+ // TODO
+ arcTo: function (x1, y1, x2, y2, radius) {
+ if (this._ctx) {
+ this._ctx.arcTo(x1, y1, x2, y2, radius);
+ }
+ return this;
+ },
+
+ // TODO
+ rect: function (x, y, w, h) {
+ this._ctx && this._ctx.rect(x, y, w, h);
+ this.addData(CMD.R, x, y, w, h);
+ return this;
+ },
+
+ /**
+ * @return {module:zrender/core/PathProxy}
+ */
+ closePath: function () {
+ this.addData(CMD.Z);
+
+ var ctx = this._ctx;
+ var x0 = this._x0;
+ var y0 = this._y0;
+ if (ctx) {
+ this._needsDash() && this._dashedLineTo(x0, y0);
+ ctx.closePath();
+ }
+
+ this._xi = x0;
+ this._yi = y0;
+ return this;
+ },
+
+ /**
+ * Context 从外部传入,因为有可能是 rebuildPath 完之后再 fill。
+ * stroke 同样
+ * @param {CanvasRenderingContext2D} ctx
+ * @return {module:zrender/core/PathProxy}
+ */
+ fill: function (ctx) {
+ ctx && ctx.fill();
+ this.toStatic();
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ * @return {module:zrender/core/PathProxy}
+ */
+ stroke: function (ctx) {
+ ctx && ctx.stroke();
+ this.toStatic();
+ },
+
+ /**
+ * 必须在其它绘制命令前调用
+ * Must be invoked before all other path drawing methods
+ * @return {module:zrender/core/PathProxy}
+ */
+ setLineDash: function (lineDash) {
+ if (lineDash instanceof Array) {
+ this._lineDash = lineDash;
+
+ this._dashIdx = 0;
+
+ var lineDashSum = 0;
+ for (var i = 0; i < lineDash.length; i++) {
+ lineDashSum += lineDash[i];
+ }
+ this._dashSum = lineDashSum;
+ }
+ return this;
+ },
+
+ /**
+ * 必须在其它绘制命令前调用
+ * Must be invoked before all other path drawing methods
+ * @return {module:zrender/core/PathProxy}
+ */
+ setLineDashOffset: function (offset) {
+ this._dashOffset = offset;
+ return this;
+ },
+
+ /**
+ *
+ * @return {boolean}
+ */
+ len: function () {
+ return this._len;
+ },
+
+ /**
+ * 直接设置 Path 数据
+ */
+ setData: function (data) {
+
+ var len = data.length;
+
+ if (! (this.data && this.data.length == len) && hasTypedArray) {
+ this.data = new Float32Array(len);
+ }
+
+ for (var i = 0; i < len; i++) {
+ this.data[i] = data[i];
+ }
+
+ this._len = len;
+ },
+
+ /**
+ * 添加子路径
+ * @param {module:zrender/core/PathProxy|Array.} path
+ */
+ appendPath: function (path) {
+ if (!(path instanceof Array)) {
+ path = [path];
+ }
+ var len = path.length;
+ var appendSize = 0;
+ var offset = this._len;
+ for (var i = 0; i < len; i++) {
+ appendSize += path[i].len();
+ }
+ if (hasTypedArray && (this.data instanceof Float32Array)) {
+ this.data = new Float32Array(offset + appendSize);
+ }
+ for (var i = 0; i < len; i++) {
+ var appendPathData = path[i].data;
+ for (var k = 0; k < appendPathData.length; k++) {
+ this.data[offset++] = appendPathData[k];
+ }
+ }
+ this._len = offset;
+ },
+
+ /**
+ * 填充 Path 数据。
+ * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。
+ */
+ addData: function (cmd) {
+ if (!this._saveData) {
+ return;
+ }
+
+ var data = this.data;
+ if (this._len + arguments.length > data.length) {
+ // 因为之前的数组已经转换成静态的 Float32Array
+ // 所以不够用时需要扩展一个新的动态数组
+ this._expandData();
+ data = this.data;
+ }
+ for (var i = 0; i < arguments.length; i++) {
+ data[this._len++] = arguments[i];
+ }
+
+ this._prevCmd = cmd;
+ },
+
+ _expandData: function () {
+ // Only if data is Float32Array
+ if (!(this.data instanceof Array)) {
+ var newData = [];
+ for (var i = 0; i < this._len; i++) {
+ newData[i] = this.data[i];
+ }
+ this.data = newData;
+ }
+ },
+
+ /**
+ * If needs js implemented dashed line
+ * @return {boolean}
+ * @private
+ */
+ _needsDash: function () {
+ return this._lineDash;
+ },
+
+ _dashedLineTo: function (x1, y1) {
+ var dashSum = this._dashSum;
+ var offset = this._dashOffset;
+ var lineDash = this._lineDash;
+ var ctx = this._ctx;
+
+ var x0 = this._xi;
+ var y0 = this._yi;
+ var dx = x1 - x0;
+ var dy = y1 - y0;
+ var dist = mathSqrt(dx * dx + dy * dy);
+ var x = x0;
+ var y = y0;
+ var dash;
+ var nDash = lineDash.length;
+ var idx;
+ dx /= dist;
+ dy /= dist;
+
+ if (offset < 0) {
+ // Convert to positive offset
+ offset = dashSum + offset;
+ }
+ offset %= dashSum;
+ x -= offset * dx;
+ y -= offset * dy;
+
+ while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)
+ || (dx == 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {
+ idx = this._dashIdx;
+ dash = lineDash[idx];
+ x += dx * dash;
+ y += dy * dash;
+ this._dashIdx = (idx + 1) % nDash;
+ // Skip positive offset
+ if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {
+ continue;
+ }
+ ctx[idx % 2 ? 'moveTo' : 'lineTo'](
+ dx >= 0 ? mathMin(x, x1) : mathMax(x, x1),
+ dy >= 0 ? mathMin(y, y1) : mathMax(y, y1)
+ );
+ }
+ // Offset for next lineTo
+ dx = x - x1;
+ dy = y - y1;
+ this._dashOffset = -mathSqrt(dx * dx + dy * dy);
+ },
+
+ // Not accurate dashed line to
+ _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {
+ var dashSum = this._dashSum;
+ var offset = this._dashOffset;
+ var lineDash = this._lineDash;
+ var ctx = this._ctx;
+
+ var x0 = this._xi;
+ var y0 = this._yi;
+ var t;
+ var dx;
+ var dy;
+ var cubicAt = curve.cubicAt;
+ var bezierLen = 0;
+ var idx = this._dashIdx;
+ var nDash = lineDash.length;
+
+ var x;
+ var y;
+
+ var tmpLen = 0;
+
+ if (offset < 0) {
+ // Convert to positive offset
+ offset = dashSum + offset;
+ }
+ offset %= dashSum;
+ // Bezier approx length
+ for (t = 0; t < 1; t += 0.1) {
+ dx = cubicAt(x0, x1, x2, x3, t + 0.1)
+ - cubicAt(x0, x1, x2, x3, t);
+ dy = cubicAt(y0, y1, y2, y3, t + 0.1)
+ - cubicAt(y0, y1, y2, y3, t);
+ bezierLen += mathSqrt(dx * dx + dy * dy);
+ }
+
+ // Find idx after add offset
+ for (; idx < nDash; idx++) {
+ tmpLen += lineDash[idx];
+ if (tmpLen > offset) {
+ break;
+ }
+ }
+ t = (tmpLen - offset) / bezierLen;
+
+ while (t <= 1) {
+
+ x = cubicAt(x0, x1, x2, x3, t);
+ y = cubicAt(y0, y1, y2, y3, t);
+
+ // Use line to approximate dashed bezier
+ // Bad result if dash is long
+ idx % 2 ? ctx.moveTo(x, y)
+ : ctx.lineTo(x, y);
+
+ t += lineDash[idx] / bezierLen;
+
+ idx = (idx + 1) % nDash;
+ }
+
+ // Finish the last segment and calculate the new offset
+ (idx % 2 !== 0) && ctx.lineTo(x3, y3);
+ dx = x3 - x;
+ dy = y3 - y;
+ this._dashOffset = -mathSqrt(dx * dx + dy * dy);
+ },
+
+ _dashedQuadraticTo: function (x1, y1, x2, y2) {
+ // Convert quadratic to cubic using degree elevation
+ var x3 = x2;
+ var y3 = y2;
+ x2 = (x2 + 2 * x1) / 3;
+ y2 = (y2 + 2 * y1) / 3;
+ x1 = (this._xi + 2 * x1) / 3;
+ y1 = (this._yi + 2 * y1) / 3;
+
+ this._dashedBezierTo(x1, y1, x2, y2, x3, y3);
+ },
+
+ /**
+ * 转成静态的 Float32Array 减少堆内存占用
+ * Convert dynamic array to static Float32Array
+ */
+ toStatic: function () {
+ var data = this.data;
+ if (data instanceof Array) {
+ data.length = this._len;
+ if (hasTypedArray) {
+ this.data = new Float32Array(data);
+ }
+ }
+ },
+
+ /**
+ * @return {module:zrender/core/BoundingRect}
+ */
+ getBoundingRect: function () {
+ min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE;
+ max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
+
+ var data = this.data;
+ var xi = 0;
+ var yi = 0;
+ var x0 = 0;
+ var y0 = 0;
+
+ for (var i = 0; i < data.length;) {
+ var cmd = data[i++];
+
+ if (i == 1) {
+ // 如果第一个命令是 L, C, Q
+ // 则 previous point 同绘制命令的第一个 point
+ //
+ // 第一个命令为 Arc 的情况下会在后面特殊处理
+ xi = data[i];
+ yi = data[i + 1];
+
+ x0 = xi;
+ y0 = yi;
+ }
+
+ switch (cmd) {
+ case CMD.M:
+ // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
+ // 在 closePath 的时候使用
+ x0 = data[i++];
+ y0 = data[i++];
+ xi = x0;
+ yi = y0;
+ min2[0] = x0;
+ min2[1] = y0;
+ max2[0] = x0;
+ max2[1] = y0;
+ break;
+ case CMD.L:
+ bbox.fromLine(xi, yi, data[i], data[i + 1], min2, max2);
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.C:
+ bbox.fromCubic(
+ xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
+ min2, max2
+ );
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.Q:
+ bbox.fromQuadratic(
+ xi, yi, data[i++], data[i++], data[i], data[i + 1],
+ min2, max2
+ );
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.A:
+ // TODO Arc 判断的开销比较大
+ var cx = data[i++];
+ var cy = data[i++];
+ var rx = data[i++];
+ var ry = data[i++];
+ var startAngle = data[i++];
+ var endAngle = data[i++] + startAngle;
+ // TODO Arc 旋转
+ var psi = data[i++];
+ var anticlockwise = 1 - data[i++];
+
+ if (i == 1) {
+ // 直接使用 arc 命令
+ // 第一个命令起点还未定义
+ x0 = mathCos(startAngle) * rx + cx;
+ y0 = mathSin(startAngle) * ry + cy;
+ }
+
+ bbox.fromArc(
+ cx, cy, rx, ry, startAngle, endAngle,
+ anticlockwise, min2, max2
+ );
+
+ xi = mathCos(endAngle) * rx + cx;
+ yi = mathSin(endAngle) * ry + cy;
+ break;
+ case CMD.R:
+ x0 = xi = data[i++];
+ y0 = yi = data[i++];
+ var width = data[i++];
+ var height = data[i++];
+ // Use fromLine
+ bbox.fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
+ break;
+ case CMD.Z:
+ xi = x0;
+ yi = y0;
+ break;
+ }
+
+ // Union
+ vec2.min(min, min, min2);
+ vec2.max(max, max, max2);
+ }
+
+ // No data
+ if (i === 0) {
+ min[0] = min[1] = max[0] = max[1] = 0;
+ }
+
+ return new BoundingRect(
+ min[0], min[1], max[0] - min[0], max[1] - min[1]
+ );
+ },
+
+ /**
+ * Rebuild path from current data
+ * Rebuild path will not consider javascript implemented line dash.
+ * @param {CanvasRenderingContext} ctx
+ */
+ rebuildPath: function (ctx) {
+ var d = this.data;
+ var x0, y0;
+ var xi, yi;
+ var x, y;
+ var ux = this._ux;
+ var uy = this._uy;
+ var len = this._len;
+ for (var i = 0; i < len;) {
+ var cmd = d[i++];
+
+ if (i == 1) {
+ // 如果第一个命令是 L, C, Q
+ // 则 previous point 同绘制命令的第一个 point
+ //
+ // 第一个命令为 Arc 的情况下会在后面特殊处理
+ xi = d[i];
+ yi = d[i + 1];
+
+ x0 = xi;
+ y0 = yi;
+ }
+ switch (cmd) {
+ case CMD.M:
+ x0 = xi = d[i++];
+ y0 = yi = d[i++];
+ ctx.moveTo(xi, yi);
+ break;
+ case CMD.L:
+ x = d[i++];
+ y = d[i++];
+ // Not draw too small seg between
+ if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len - 1) {
+ ctx.lineTo(x, y);
+ xi = x;
+ yi = y;
+ }
+ break;
+ case CMD.C:
+ ctx.bezierCurveTo(
+ d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]
+ );
+ xi = d[i - 2];
+ yi = d[i - 1];
+ break;
+ case CMD.Q:
+ ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);
+ xi = d[i - 2];
+ yi = d[i - 1];
+ break;
+ case CMD.A:
+ var cx = d[i++];
+ var cy = d[i++];
+ var rx = d[i++];
+ var ry = d[i++];
+ var theta = d[i++];
+ var dTheta = d[i++];
+ var psi = d[i++];
+ var fs = d[i++];
+ var r = (rx > ry) ? rx : ry;
+ var scaleX = (rx > ry) ? 1 : rx / ry;
+ var scaleY = (rx > ry) ? ry / rx : 1;
+ var isEllipse = Math.abs(rx - ry) > 1e-3;
+ var endAngle = theta + dTheta;
+ if (isEllipse) {
+ ctx.translate(cx, cy);
+ ctx.rotate(psi);
+ ctx.scale(scaleX, scaleY);
+ ctx.arc(0, 0, r, theta, endAngle, 1 - fs);
+ ctx.scale(1 / scaleX, 1 / scaleY);
+ ctx.rotate(-psi);
+ ctx.translate(-cx, -cy);
+ }
+ else {
+ ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);
+ }
+
+ if (i == 1) {
+ // 直接使用 arc 命令
+ // 第一个命令起点还未定义
+ x0 = mathCos(theta) * rx + cx;
+ y0 = mathSin(theta) * ry + cy;
+ }
+ xi = mathCos(endAngle) * rx + cx;
+ yi = mathSin(endAngle) * ry + cy;
+ break;
+ case CMD.R:
+ x0 = xi = d[i];
+ y0 = yi = d[i + 1];
+ ctx.rect(d[i++], d[i++], d[i++], d[i++]);
+ break;
+ case CMD.Z:
+ ctx.closePath();
+ xi = x0;
+ yi = y0;
+ }
+ }
+ }
+ };
+
+ PathProxy.CMD = CMD;
+
+ module.exports = PathProxy;
+
+
+/***/ },
+/* 37 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 曲线辅助模块
+ * @module zrender/core/curve
+ * @author pissang(https://www.github.com/pissang)
+ */
+
+
+ var vec2 = __webpack_require__(10);
+ var v2Create = vec2.create;
+ var v2DistSquare = vec2.distSquare;
+ var mathPow = Math.pow;
+ var mathSqrt = Math.sqrt;
+
+ var EPSILON = 1e-8;
+ var EPSILON_NUMERIC = 1e-4;
+
+ var THREE_SQRT = mathSqrt(3);
+ var ONE_THIRD = 1 / 3;
+
+ // 临时变量
+ var _v0 = v2Create();
+ var _v1 = v2Create();
+ var _v2 = v2Create();
+ // var _v3 = vec2.create();
+
+ function isAroundZero(val) {
+ return val > -EPSILON && val < EPSILON;
+ }
+ function isNotAroundZero(val) {
+ return val > EPSILON || val < -EPSILON;
+ }
+ /**
+ * 计算三次贝塞尔值
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {number} t
+ * @return {number}
+ */
+ function cubicAt(p0, p1, p2, p3, t) {
+ var onet = 1 - t;
+ return onet * onet * (onet * p0 + 3 * t * p1)
+ + t * t * (t * p3 + 3 * onet * p2);
+ }
+
+ /**
+ * 计算三次贝塞尔导数值
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {number} t
+ * @return {number}
+ */
+ function cubicDerivativeAt(p0, p1, p2, p3, t) {
+ var onet = 1 - t;
+ return 3 * (
+ ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet
+ + (p3 - p2) * t * t
+ );
+ }
+
+ /**
+ * 计算三次贝塞尔方程根,使用盛金公式
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {number} val
+ * @param {Array.} roots
+ * @return {number} 有效根数目
+ */
+ function cubicRootAt(p0, p1, p2, p3, val, roots) {
+ // Evaluate roots of cubic functions
+ var a = p3 + 3 * (p1 - p2) - p0;
+ var b = 3 * (p2 - p1 * 2 + p0);
+ var c = 3 * (p1 - p0);
+ var d = p0 - val;
+
+ var A = b * b - 3 * a * c;
+ var B = b * c - 9 * a * d;
+ var C = c * c - 3 * b * d;
+
+ var n = 0;
+
+ if (isAroundZero(A) && isAroundZero(B)) {
+ if (isAroundZero(b)) {
+ roots[0] = 0;
+ }
+ else {
+ var t1 = -c / b; //t1, t2, t3, b is not zero
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ }
+ }
+ else {
+ var disc = B * B - 4 * A * C;
+
+ if (isAroundZero(disc)) {
+ var K = B / A;
+ var t1 = -b / a + K; // t1, a is not zero
+ var t2 = -K / 2; // t2, t3
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ if (t2 >= 0 && t2 <= 1) {
+ roots[n++] = t2;
+ }
+ }
+ else if (disc > 0) {
+ var discSqrt = mathSqrt(disc);
+ var Y1 = A * b + 1.5 * a * (-B + discSqrt);
+ var Y2 = A * b + 1.5 * a * (-B - discSqrt);
+ if (Y1 < 0) {
+ Y1 = -mathPow(-Y1, ONE_THIRD);
+ }
+ else {
+ Y1 = mathPow(Y1, ONE_THIRD);
+ }
+ if (Y2 < 0) {
+ Y2 = -mathPow(-Y2, ONE_THIRD);
+ }
+ else {
+ Y2 = mathPow(Y2, ONE_THIRD);
+ }
+ var t1 = (-b - (Y1 + Y2)) / (3 * a);
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ }
+ else {
+ var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A));
+ var theta = Math.acos(T) / 3;
+ var ASqrt = mathSqrt(A);
+ var tmp = Math.cos(theta);
+
+ var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
+ var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
+ var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ if (t2 >= 0 && t2 <= 1) {
+ roots[n++] = t2;
+ }
+ if (t3 >= 0 && t3 <= 1) {
+ roots[n++] = t3;
+ }
+ }
+ }
+ return n;
+ }
+
+ /**
+ * 计算三次贝塞尔方程极限值的位置
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {Array.} extrema
+ * @return {number} 有效数目
+ */
+ function cubicExtrema(p0, p1, p2, p3, extrema) {
+ var b = 6 * p2 - 12 * p1 + 6 * p0;
+ var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
+ var c = 3 * p1 - 3 * p0;
+
+ var n = 0;
+ if (isAroundZero(a)) {
+ if (isNotAroundZero(b)) {
+ var t1 = -c / b;
+ if (t1 >= 0 && t1 <=1) {
+ extrema[n++] = t1;
+ }
+ }
+ }
+ else {
+ var disc = b * b - 4 * a * c;
+ if (isAroundZero(disc)) {
+ extrema[0] = -b / (2 * a);
+ }
+ else if (disc > 0) {
+ var discSqrt = mathSqrt(disc);
+ var t1 = (-b + discSqrt) / (2 * a);
+ var t2 = (-b - discSqrt) / (2 * a);
+ if (t1 >= 0 && t1 <= 1) {
+ extrema[n++] = t1;
+ }
+ if (t2 >= 0 && t2 <= 1) {
+ extrema[n++] = t2;
+ }
+ }
+ }
+ return n;
+ }
+
+ /**
+ * 细分三次贝塞尔曲线
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} p3
+ * @param {number} t
+ * @param {Array.} out
+ */
+ function cubicSubdivide(p0, p1, p2, p3, t, out) {
+ var p01 = (p1 - p0) * t + p0;
+ var p12 = (p2 - p1) * t + p1;
+ var p23 = (p3 - p2) * t + p2;
+
+ var p012 = (p12 - p01) * t + p01;
+ var p123 = (p23 - p12) * t + p12;
+
+ var p0123 = (p123 - p012) * t + p012;
+ // Seg0
+ out[0] = p0;
+ out[1] = p01;
+ out[2] = p012;
+ out[3] = p0123;
+ // Seg1
+ out[4] = p0123;
+ out[5] = p123;
+ out[6] = p23;
+ out[7] = p3;
+ }
+
+ /**
+ * 投射点到三次贝塞尔曲线上,返回投射距离。
+ * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} x3
+ * @param {number} y3
+ * @param {number} x
+ * @param {number} y
+ * @param {Array.} [out] 投射点
+ * @return {number}
+ */
+ function cubicProjectPoint(
+ x0, y0, x1, y1, x2, y2, x3, y3,
+ x, y, out
+ ) {
+ // http://pomax.github.io/bezierinfo/#projections
+ var t;
+ var interval = 0.005;
+ var d = Infinity;
+ var prev;
+ var next;
+ var d1;
+ var d2;
+
+ _v0[0] = x;
+ _v0[1] = y;
+
+ // 先粗略估计一下可能的最小距离的 t 值
+ // PENDING
+ for (var _t = 0; _t < 1; _t += 0.05) {
+ _v1[0] = cubicAt(x0, x1, x2, x3, _t);
+ _v1[1] = cubicAt(y0, y1, y2, y3, _t);
+ d1 = v2DistSquare(_v0, _v1);
+ if (d1 < d) {
+ t = _t;
+ d = d1;
+ }
+ }
+ d = Infinity;
+
+ // At most 32 iteration
+ for (var i = 0; i < 32; i++) {
+ if (interval < EPSILON_NUMERIC) {
+ break;
+ }
+ prev = t - interval;
+ next = t + interval;
+ // t - interval
+ _v1[0] = cubicAt(x0, x1, x2, x3, prev);
+ _v1[1] = cubicAt(y0, y1, y2, y3, prev);
+
+ d1 = v2DistSquare(_v1, _v0);
+
+ if (prev >= 0 && d1 < d) {
+ t = prev;
+ d = d1;
+ }
+ else {
+ // t + interval
+ _v2[0] = cubicAt(x0, x1, x2, x3, next);
+ _v2[1] = cubicAt(y0, y1, y2, y3, next);
+ d2 = v2DistSquare(_v2, _v0);
+
+ if (next <= 1 && d2 < d) {
+ t = next;
+ d = d2;
+ }
+ else {
+ interval *= 0.5;
+ }
+ }
+ }
+ // t
+ if (out) {
+ out[0] = cubicAt(x0, x1, x2, x3, t);
+ out[1] = cubicAt(y0, y1, y2, y3, t);
+ }
+ // console.log(interval, i);
+ return mathSqrt(d);
+ }
+
+ /**
+ * 计算二次方贝塞尔值
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} t
+ * @return {number}
+ */
+ function quadraticAt(p0, p1, p2, t) {
+ var onet = 1 - t;
+ return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
+ }
+
+ /**
+ * 计算二次方贝塞尔导数值
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} t
+ * @return {number}
+ */
+ function quadraticDerivativeAt(p0, p1, p2, t) {
+ return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
+ }
+
+ /**
+ * 计算二次方贝塞尔方程根
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} t
+ * @param {Array.} roots
+ * @return {number} 有效根数目
+ */
+ function quadraticRootAt(p0, p1, p2, val, roots) {
+ var a = p0 - 2 * p1 + p2;
+ var b = 2 * (p1 - p0);
+ var c = p0 - val;
+
+ var n = 0;
+ if (isAroundZero(a)) {
+ if (isNotAroundZero(b)) {
+ var t1 = -c / b;
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ }
+ }
+ else {
+ var disc = b * b - 4 * a * c;
+ if (isAroundZero(disc)) {
+ var t1 = -b / (2 * a);
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ }
+ else if (disc > 0) {
+ var discSqrt = mathSqrt(disc);
+ var t1 = (-b + discSqrt) / (2 * a);
+ var t2 = (-b - discSqrt) / (2 * a);
+ if (t1 >= 0 && t1 <= 1) {
+ roots[n++] = t1;
+ }
+ if (t2 >= 0 && t2 <= 1) {
+ roots[n++] = t2;
+ }
+ }
+ }
+ return n;
+ }
+
+ /**
+ * 计算二次贝塞尔方程极限值
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @return {number}
+ */
+ function quadraticExtremum(p0, p1, p2) {
+ var divider = p0 + p2 - 2 * p1;
+ if (divider === 0) {
+ // p1 is center of p0 and p2
+ return 0.5;
+ }
+ else {
+ return (p0 - p1) / divider;
+ }
+ }
+
+ /**
+ * 细分二次贝塞尔曲线
+ * @memberOf module:zrender/core/curve
+ * @param {number} p0
+ * @param {number} p1
+ * @param {number} p2
+ * @param {number} t
+ * @param {Array.} out
+ */
+ function quadraticSubdivide(p0, p1, p2, t, out) {
+ var p01 = (p1 - p0) * t + p0;
+ var p12 = (p2 - p1) * t + p1;
+ var p012 = (p12 - p01) * t + p01;
+
+ // Seg0
+ out[0] = p0;
+ out[1] = p01;
+ out[2] = p012;
+
+ // Seg1
+ out[3] = p012;
+ out[4] = p12;
+ out[5] = p2;
+ }
+
+ /**
+ * 投射点到二次贝塞尔曲线上,返回投射距离。
+ * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} x
+ * @param {number} y
+ * @param {Array.} out 投射点
+ * @return {number}
+ */
+ function quadraticProjectPoint(
+ x0, y0, x1, y1, x2, y2,
+ x, y, out
+ ) {
+ // http://pomax.github.io/bezierinfo/#projections
+ var t;
+ var interval = 0.005;
+ var d = Infinity;
+
+ _v0[0] = x;
+ _v0[1] = y;
+
+ // 先粗略估计一下可能的最小距离的 t 值
+ // PENDING
+ for (var _t = 0; _t < 1; _t += 0.05) {
+ _v1[0] = quadraticAt(x0, x1, x2, _t);
+ _v1[1] = quadraticAt(y0, y1, y2, _t);
+ var d1 = v2DistSquare(_v0, _v1);
+ if (d1 < d) {
+ t = _t;
+ d = d1;
+ }
+ }
+ d = Infinity;
+
+ // At most 32 iteration
+ for (var i = 0; i < 32; i++) {
+ if (interval < EPSILON_NUMERIC) {
+ break;
+ }
+ var prev = t - interval;
+ var next = t + interval;
+ // t - interval
+ _v1[0] = quadraticAt(x0, x1, x2, prev);
+ _v1[1] = quadraticAt(y0, y1, y2, prev);
+
+ var d1 = v2DistSquare(_v1, _v0);
+
+ if (prev >= 0 && d1 < d) {
+ t = prev;
+ d = d1;
+ }
+ else {
+ // t + interval
+ _v2[0] = quadraticAt(x0, x1, x2, next);
+ _v2[1] = quadraticAt(y0, y1, y2, next);
+ var d2 = v2DistSquare(_v2, _v0);
+ if (next <= 1 && d2 < d) {
+ t = next;
+ d = d2;
+ }
+ else {
+ interval *= 0.5;
+ }
+ }
+ }
+ // t
+ if (out) {
+ out[0] = quadraticAt(x0, x1, x2, t);
+ out[1] = quadraticAt(y0, y1, y2, t);
+ }
+ // console.log(interval, i);
+ return mathSqrt(d);
+ }
+
+ module.exports = {
+
+ cubicAt: cubicAt,
+
+ cubicDerivativeAt: cubicDerivativeAt,
+
+ cubicRootAt: cubicRootAt,
+
+ cubicExtrema: cubicExtrema,
+
+ cubicSubdivide: cubicSubdivide,
+
+ cubicProjectPoint: cubicProjectPoint,
+
+ quadraticAt: quadraticAt,
+
+ quadraticDerivativeAt: quadraticDerivativeAt,
+
+ quadraticRootAt: quadraticRootAt,
+
+ quadraticExtremum: quadraticExtremum,
+
+ quadraticSubdivide: quadraticSubdivide,
+
+ quadraticProjectPoint: quadraticProjectPoint
+ };
+
+
+/***/ },
+/* 38 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @author Yi Shen(https://github.com/pissang)
+ */
+
+
+ var vec2 = __webpack_require__(10);
+ var curve = __webpack_require__(37);
+
+ var bbox = {};
+ var mathMin = Math.min;
+ var mathMax = Math.max;
+ var mathSin = Math.sin;
+ var mathCos = Math.cos;
+
+ var start = vec2.create();
+ var end = vec2.create();
+ var extremity = vec2.create();
+
+ var PI2 = Math.PI * 2;
+ /**
+ * 从顶点数组中计算出最小包围盒,写入`min`和`max`中
+ * @module zrender/core/bbox
+ * @param {Array} points 顶点数组
+ * @param {number} min
+ * @param {number} max
+ */
+ bbox.fromPoints = function(points, min, max) {
+ if (points.length === 0) {
+ return;
+ }
+ var p = points[0];
+ var left = p[0];
+ var right = p[0];
+ var top = p[1];
+ var bottom = p[1];
+ var i;
+
+ for (i = 1; i < points.length; i++) {
+ p = points[i];
+ left = mathMin(left, p[0]);
+ right = mathMax(right, p[0]);
+ top = mathMin(top, p[1]);
+ bottom = mathMax(bottom, p[1]);
+ }
+
+ min[0] = left;
+ min[1] = top;
+ max[0] = right;
+ max[1] = bottom;
+ };
+
+ /**
+ * @memberOf module:zrender/core/bbox
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {Array.} min
+ * @param {Array.} max
+ */
+ bbox.fromLine = function (x0, y0, x1, y1, min, max) {
+ min[0] = mathMin(x0, x1);
+ min[1] = mathMin(y0, y1);
+ max[0] = mathMax(x0, x1);
+ max[1] = mathMax(y0, y1);
+ };
+
+ var xDim = [];
+ var yDim = [];
+ /**
+ * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中
+ * @memberOf module:zrender/core/bbox
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} x3
+ * @param {number} y3
+ * @param {Array.} min
+ * @param {Array.} max
+ */
+ bbox.fromCubic = function(
+ x0, y0, x1, y1, x2, y2, x3, y3, min, max
+ ) {
+ var cubicExtrema = curve.cubicExtrema;
+ var cubicAt = curve.cubicAt;
+ var i;
+ var n = cubicExtrema(x0, x1, x2, x3, xDim);
+ min[0] = Infinity;
+ min[1] = Infinity;
+ max[0] = -Infinity;
+ max[1] = -Infinity;
+
+ for (i = 0; i < n; i++) {
+ var x = cubicAt(x0, x1, x2, x3, xDim[i]);
+ min[0] = mathMin(x, min[0]);
+ max[0] = mathMax(x, max[0]);
+ }
+ n = cubicExtrema(y0, y1, y2, y3, yDim);
+ for (i = 0; i < n; i++) {
+ var y = cubicAt(y0, y1, y2, y3, yDim[i]);
+ min[1] = mathMin(y, min[1]);
+ max[1] = mathMax(y, max[1]);
+ }
+
+ min[0] = mathMin(x0, min[0]);
+ max[0] = mathMax(x0, max[0]);
+ min[0] = mathMin(x3, min[0]);
+ max[0] = mathMax(x3, max[0]);
+
+ min[1] = mathMin(y0, min[1]);
+ max[1] = mathMax(y0, max[1]);
+ min[1] = mathMin(y3, min[1]);
+ max[1] = mathMax(y3, max[1]);
+ };
+
+ /**
+ * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中
+ * @memberOf module:zrender/core/bbox
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {Array.} min
+ * @param {Array.} max
+ */
+ bbox.fromQuadratic = function(x0, y0, x1, y1, x2, y2, min, max) {
+ var quadraticExtremum = curve.quadraticExtremum;
+ var quadraticAt = curve.quadraticAt;
+ // Find extremities, where derivative in x dim or y dim is zero
+ var tx =
+ mathMax(
+ mathMin(quadraticExtremum(x0, x1, x2), 1), 0
+ );
+ var ty =
+ mathMax(
+ mathMin(quadraticExtremum(y0, y1, y2), 1), 0
+ );
+
+ var x = quadraticAt(x0, x1, x2, tx);
+ var y = quadraticAt(y0, y1, y2, ty);
+
+ min[0] = mathMin(x0, x2, x);
+ min[1] = mathMin(y0, y2, y);
+ max[0] = mathMax(x0, x2, x);
+ max[1] = mathMax(y0, y2, y);
+ };
+
+ /**
+ * 从圆弧中计算出最小包围盒,写入`min`和`max`中
+ * @method
+ * @memberOf module:zrender/core/bbox
+ * @param {number} x
+ * @param {number} y
+ * @param {number} rx
+ * @param {number} ry
+ * @param {number} startAngle
+ * @param {number} endAngle
+ * @param {number} anticlockwise
+ * @param {Array.} min
+ * @param {Array.} max
+ */
+ bbox.fromArc = function (
+ x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max
+ ) {
+ var vec2Min = vec2.min;
+ var vec2Max = vec2.max;
+
+ var diff = Math.abs(startAngle - endAngle);
+
+
+ if (diff % PI2 < 1e-4 && diff > 1e-4) {
+ // Is a circle
+ min[0] = x - rx;
+ min[1] = y - ry;
+ max[0] = x + rx;
+ max[1] = y + ry;
+ return;
+ }
+
+ start[0] = mathCos(startAngle) * rx + x;
+ start[1] = mathSin(startAngle) * ry + y;
+
+ end[0] = mathCos(endAngle) * rx + x;
+ end[1] = mathSin(endAngle) * ry + y;
+
+ vec2Min(min, start, end);
+ vec2Max(max, start, end);
+
+ // Thresh to [0, Math.PI * 2]
+ startAngle = startAngle % (PI2);
+ if (startAngle < 0) {
+ startAngle = startAngle + PI2;
+ }
+ endAngle = endAngle % (PI2);
+ if (endAngle < 0) {
+ endAngle = endAngle + PI2;
+ }
+
+ if (startAngle > endAngle && !anticlockwise) {
+ endAngle += PI2;
+ }
+ else if (startAngle < endAngle && anticlockwise) {
+ startAngle += PI2;
+ }
+ if (anticlockwise) {
+ var tmp = endAngle;
+ endAngle = startAngle;
+ startAngle = tmp;
+ }
+
+ // var number = 0;
+ // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;
+ for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
+ if (angle > startAngle) {
+ extremity[0] = mathCos(angle) * rx + x;
+ extremity[1] = mathSin(angle) * ry + y;
+
+ vec2Min(min, extremity, min);
+ vec2Max(max, extremity, max);
+ }
+ }
+ };
+
+ module.exports = bbox;
+
+
+
+/***/ },
+/* 39 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var CMD = __webpack_require__(36).CMD;
+ var line = __webpack_require__(40);
+ var cubic = __webpack_require__(41);
+ var quadratic = __webpack_require__(42);
+ var arc = __webpack_require__(43);
+ var normalizeRadian = __webpack_require__(44).normalizeRadian;
+ var curve = __webpack_require__(37);
+
+ var windingLine = __webpack_require__(45);
+
+ var containStroke = line.containStroke;
+
+ var PI2 = Math.PI * 2;
+
+ var EPSILON = 1e-4;
+
+ function isAroundEqual(a, b) {
+ return Math.abs(a - b) < EPSILON;
+ }
+
+ // 临时数组
+ var roots = [-1, -1, -1];
+ var extrema = [-1, -1];
+
+ function swapExtrema() {
+ var tmp = extrema[0];
+ extrema[0] = extrema[1];
+ extrema[1] = tmp;
+ }
+
+ function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
+ // Quick reject
+ if (
+ (y > y0 && y > y1 && y > y2 && y > y3)
+ || (y < y0 && y < y1 && y < y2 && y < y3)
+ ) {
+ return 0;
+ }
+ var nRoots = curve.cubicRootAt(y0, y1, y2, y3, y, roots);
+ if (nRoots === 0) {
+ return 0;
+ }
+ else {
+ var w = 0;
+ var nExtrema = -1;
+ var y0_, y1_;
+ for (var i = 0; i < nRoots; i++) {
+ var t = roots[i];
+
+ // Avoid winding error when intersection point is the connect point of two line of polygon
+ var unit = (t === 0 || t === 1) ? 0.5 : 1;
+
+ var x_ = curve.cubicAt(x0, x1, x2, x3, t);
+ if (x_ < x) { // Quick reject
+ continue;
+ }
+ if (nExtrema < 0) {
+ nExtrema = curve.cubicExtrema(y0, y1, y2, y3, extrema);
+ if (extrema[1] < extrema[0] && nExtrema > 1) {
+ swapExtrema();
+ }
+ y0_ = curve.cubicAt(y0, y1, y2, y3, extrema[0]);
+ if (nExtrema > 1) {
+ y1_ = curve.cubicAt(y0, y1, y2, y3, extrema[1]);
+ }
+ }
+ if (nExtrema == 2) {
+ // 分成三段单调函数
+ if (t < extrema[0]) {
+ w += y0_ < y0 ? unit : -unit;
+ }
+ else if (t < extrema[1]) {
+ w += y1_ < y0_ ? unit : -unit;
+ }
+ else {
+ w += y3 < y1_ ? unit : -unit;
+ }
+ }
+ else {
+ // 分成两段单调函数
+ if (t < extrema[0]) {
+ w += y0_ < y0 ? unit : -unit;
+ }
+ else {
+ w += y3 < y0_ ? unit : -unit;
+ }
+ }
+ }
+ return w;
+ }
+ }
+
+ function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
+ // Quick reject
+ if (
+ (y > y0 && y > y1 && y > y2)
+ || (y < y0 && y < y1 && y < y2)
+ ) {
+ return 0;
+ }
+ var nRoots = curve.quadraticRootAt(y0, y1, y2, y, roots);
+ if (nRoots === 0) {
+ return 0;
+ }
+ else {
+ var t = curve.quadraticExtremum(y0, y1, y2);
+ if (t >= 0 && t <= 1) {
+ var w = 0;
+ var y_ = curve.quadraticAt(y0, y1, y2, t);
+ for (var i = 0; i < nRoots; i++) {
+ // Remove one endpoint.
+ var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;
+
+ var x_ = curve.quadraticAt(x0, x1, x2, roots[i]);
+ if (x_ < x) { // Quick reject
+ continue;
+ }
+ if (roots[i] < t) {
+ w += y_ < y0 ? unit : -unit;
+ }
+ else {
+ w += y2 < y_ ? unit : -unit;
+ }
+ }
+ return w;
+ }
+ else {
+ // Remove one endpoint.
+ var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;
+
+ var x_ = curve.quadraticAt(x0, x1, x2, roots[0]);
+ if (x_ < x) { // Quick reject
+ return 0;
+ }
+ return y2 < y0 ? unit : -unit;
+ }
+ }
+ }
+
+ // TODO
+ // Arc 旋转
+ function windingArc(
+ cx, cy, r, startAngle, endAngle, anticlockwise, x, y
+ ) {
+ y -= cy;
+ if (y > r || y < -r) {
+ return 0;
+ }
+ var tmp = Math.sqrt(r * r - y * y);
+ roots[0] = -tmp;
+ roots[1] = tmp;
+
+ var diff = Math.abs(startAngle - endAngle);
+ if (diff < 1e-4) {
+ return 0;
+ }
+ if (diff % PI2 < 1e-4) {
+ // Is a circle
+ startAngle = 0;
+ endAngle = PI2;
+ var dir = anticlockwise ? 1 : -1;
+ if (x >= roots[0] + cx && x <= roots[1] + cx) {
+ return dir;
+ } else {
+ return 0;
+ }
+ }
+
+ if (anticlockwise) {
+ var tmp = startAngle;
+ startAngle = normalizeRadian(endAngle);
+ endAngle = normalizeRadian(tmp);
+ }
+ else {
+ startAngle = normalizeRadian(startAngle);
+ endAngle = normalizeRadian(endAngle);
+ }
+ if (startAngle > endAngle) {
+ endAngle += PI2;
+ }
+
+ var w = 0;
+ for (var i = 0; i < 2; i++) {
+ var x_ = roots[i];
+ if (x_ + cx > x) {
+ var angle = Math.atan2(y, x_);
+ var dir = anticlockwise ? 1 : -1;
+ if (angle < 0) {
+ angle = PI2 + angle;
+ }
+ if (
+ (angle >= startAngle && angle <= endAngle)
+ || (angle + PI2 >= startAngle && angle + PI2 <= endAngle)
+ ) {
+ if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
+ dir = -dir;
+ }
+ w += dir;
+ }
+ }
+ }
+ return w;
+ }
+
+ function containPath(data, lineWidth, isStroke, x, y) {
+ var w = 0;
+ var xi = 0;
+ var yi = 0;
+ var x0 = 0;
+ var y0 = 0;
+
+ for (var i = 0; i < data.length;) {
+ var cmd = data[i++];
+ // Begin a new subpath
+ if (cmd === CMD.M && i > 1) {
+ // Close previous subpath
+ if (!isStroke) {
+ w += windingLine(xi, yi, x0, y0, x, y);
+ }
+ // 如果被任何一个 subpath 包含
+ // if (w !== 0) {
+ // return true;
+ // }
+ }
+
+ if (i == 1) {
+ // 如果第一个命令是 L, C, Q
+ // 则 previous point 同绘制命令的第一个 point
+ //
+ // 第一个命令为 Arc 的情况下会在后面特殊处理
+ xi = data[i];
+ yi = data[i + 1];
+
+ x0 = xi;
+ y0 = yi;
+ }
+
+ switch (cmd) {
+ case CMD.M:
+ // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
+ // 在 closePath 的时候使用
+ x0 = data[i++];
+ y0 = data[i++];
+ xi = x0;
+ yi = y0;
+ break;
+ case CMD.L:
+ if (isStroke) {
+ if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
+ return true;
+ }
+ }
+ else {
+ // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN
+ w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
+ }
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.C:
+ if (isStroke) {
+ if (cubic.containStroke(xi, yi,
+ data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
+ lineWidth, x, y
+ )) {
+ return true;
+ }
+ }
+ else {
+ w += windingCubic(
+ xi, yi,
+ data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
+ x, y
+ ) || 0;
+ }
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.Q:
+ if (isStroke) {
+ if (quadratic.containStroke(xi, yi,
+ data[i++], data[i++], data[i], data[i + 1],
+ lineWidth, x, y
+ )) {
+ return true;
+ }
+ }
+ else {
+ w += windingQuadratic(
+ xi, yi,
+ data[i++], data[i++], data[i], data[i + 1],
+ x, y
+ ) || 0;
+ }
+ xi = data[i++];
+ yi = data[i++];
+ break;
+ case CMD.A:
+ // TODO Arc 判断的开销比较大
+ var cx = data[i++];
+ var cy = data[i++];
+ var rx = data[i++];
+ var ry = data[i++];
+ var theta = data[i++];
+ var dTheta = data[i++];
+ // TODO Arc 旋转
+ var psi = data[i++];
+ var anticlockwise = 1 - data[i++];
+ var x1 = Math.cos(theta) * rx + cx;
+ var y1 = Math.sin(theta) * ry + cy;
+ // 不是直接使用 arc 命令
+ if (i > 1) {
+ w += windingLine(xi, yi, x1, y1, x, y);
+ }
+ else {
+ // 第一个命令起点还未定义
+ x0 = x1;
+ y0 = y1;
+ }
+ // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放
+ var _x = (x - cx) * ry / rx + cx;
+ if (isStroke) {
+ if (arc.containStroke(
+ cx, cy, ry, theta, theta + dTheta, anticlockwise,
+ lineWidth, _x, y
+ )) {
+ return true;
+ }
+ }
+ else {
+ w += windingArc(
+ cx, cy, ry, theta, theta + dTheta, anticlockwise,
+ _x, y
+ );
+ }
+ xi = Math.cos(theta + dTheta) * rx + cx;
+ yi = Math.sin(theta + dTheta) * ry + cy;
+ break;
+ case CMD.R:
+ x0 = xi = data[i++];
+ y0 = yi = data[i++];
+ var width = data[i++];
+ var height = data[i++];
+ var x1 = x0 + width;
+ var y1 = y0 + height;
+ if (isStroke) {
+ if (containStroke(x0, y0, x1, y0, lineWidth, x, y)
+ || containStroke(x1, y0, x1, y1, lineWidth, x, y)
+ || containStroke(x1, y1, x0, y1, lineWidth, x, y)
+ || containStroke(x0, y1, x0, y0, lineWidth, x, y)
+ ) {
+ return true;
+ }
+ }
+ else {
+ // FIXME Clockwise ?
+ w += windingLine(x1, y0, x1, y1, x, y);
+ w += windingLine(x0, y1, x0, y0, x, y);
+ }
+ break;
+ case CMD.Z:
+ if (isStroke) {
+ if (containStroke(
+ xi, yi, x0, y0, lineWidth, x, y
+ )) {
+ return true;
+ }
+ }
+ else {
+ // Close a subpath
+ w += windingLine(xi, yi, x0, y0, x, y);
+ // 如果被任何一个 subpath 包含
+ // FIXME subpaths may overlap
+ // if (w !== 0) {
+ // return true;
+ // }
+ }
+ xi = x0;
+ yi = y0;
+ break;
+ }
+ }
+ if (!isStroke && !isAroundEqual(yi, y0)) {
+ w += windingLine(xi, yi, x0, y0, x, y) || 0;
+ }
+ return w !== 0;
+ }
+
+ module.exports = {
+ contain: function (pathData, x, y) {
+ return containPath(pathData, 0, false, x, y);
+ },
+
+ containStroke: function (pathData, lineWidth, x, y) {
+ return containPath(pathData, lineWidth, true, x, y);
+ }
+ };
+
+
+/***/ },
+/* 40 */
+/***/ function(module, exports) {
+
+
+ module.exports = {
+ /**
+ * 线段包含判断
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} lineWidth
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ containStroke: function (x0, y0, x1, y1, lineWidth, x, y) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ var _l = lineWidth;
+ var _a = 0;
+ var _b = x0;
+ // Quick reject
+ if (
+ (y > y0 + _l && y > y1 + _l)
+ || (y < y0 - _l && y < y1 - _l)
+ || (x > x0 + _l && x > x1 + _l)
+ || (x < x0 - _l && x < x1 - _l)
+ ) {
+ return false;
+ }
+
+ if (x0 !== x1) {
+ _a = (y0 - y1) / (x0 - x1);
+ _b = (x0 * y1 - x1 * y0) / (x0 - x1) ;
+ }
+ else {
+ return Math.abs(x - x0) <= _l / 2;
+ }
+ var tmp = _a * x - y + _b;
+ var _s = tmp * tmp / (_a * _a + 1);
+ return _s <= _l / 2 * _l / 2;
+ }
+ };
+
+
+/***/ },
+/* 41 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var curve = __webpack_require__(37);
+
+ module.exports = {
+ /**
+ * 三次贝塞尔曲线描边包含判断
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} x3
+ * @param {number} y3
+ * @param {number} lineWidth
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ containStroke: function(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ var _l = lineWidth;
+ // Quick reject
+ if (
+ (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)
+ || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)
+ || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)
+ || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)
+ ) {
+ return false;
+ }
+ var d = curve.cubicProjectPoint(
+ x0, y0, x1, y1, x2, y2, x3, y3,
+ x, y, null
+ );
+ return d <= _l / 2;
+ }
+ };
+
+
+/***/ },
+/* 42 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var curve = __webpack_require__(37);
+
+ module.exports = {
+ /**
+ * 二次贝塞尔曲线描边包含判断
+ * @param {number} x0
+ * @param {number} y0
+ * @param {number} x1
+ * @param {number} y1
+ * @param {number} x2
+ * @param {number} y2
+ * @param {number} lineWidth
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ containStroke: function (x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ var _l = lineWidth;
+ // Quick reject
+ if (
+ (y > y0 + _l && y > y1 + _l && y > y2 + _l)
+ || (y < y0 - _l && y < y1 - _l && y < y2 - _l)
+ || (x > x0 + _l && x > x1 + _l && x > x2 + _l)
+ || (x < x0 - _l && x < x1 - _l && x < x2 - _l)
+ ) {
+ return false;
+ }
+ var d = curve.quadraticProjectPoint(
+ x0, y0, x1, y1, x2, y2,
+ x, y, null
+ );
+ return d <= _l / 2;
+ }
+ };
+
+
+/***/ },
+/* 43 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var normalizeRadian = __webpack_require__(44).normalizeRadian;
+ var PI2 = Math.PI * 2;
+
+ module.exports = {
+ /**
+ * 圆弧描边包含判断
+ * @param {number} cx
+ * @param {number} cy
+ * @param {number} r
+ * @param {number} startAngle
+ * @param {number} endAngle
+ * @param {boolean} anticlockwise
+ * @param {number} lineWidth
+ * @param {number} x
+ * @param {number} y
+ * @return {Boolean}
+ */
+ containStroke: function (
+ cx, cy, r, startAngle, endAngle, anticlockwise,
+ lineWidth, x, y
+ ) {
+
+ if (lineWidth === 0) {
+ return false;
+ }
+ var _l = lineWidth;
+
+ x -= cx;
+ y -= cy;
+ var d = Math.sqrt(x * x + y * y);
+
+ if ((d - _l > r) || (d + _l < r)) {
+ return false;
+ }
+ if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) {
+ // Is a circle
+ return true;
+ }
+ if (anticlockwise) {
+ var tmp = startAngle;
+ startAngle = normalizeRadian(endAngle);
+ endAngle = normalizeRadian(tmp);
+ } else {
+ startAngle = normalizeRadian(startAngle);
+ endAngle = normalizeRadian(endAngle);
+ }
+ if (startAngle > endAngle) {
+ endAngle += PI2;
+ }
+
+ var angle = Math.atan2(y, x);
+ if (angle < 0) {
+ angle += PI2;
+ }
+ return (angle >= startAngle && angle <= endAngle)
+ || (angle + PI2 >= startAngle && angle + PI2 <= endAngle);
+ }
+ };
+
+
+/***/ },
+/* 44 */
+/***/ function(module, exports) {
+
+
+
+ var PI2 = Math.PI * 2;
+ module.exports = {
+ normalizeRadian: function(angle) {
+ angle %= PI2;
+ if (angle < 0) {
+ angle += PI2;
+ }
+ return angle;
+ }
+ };
+
+
+/***/ },
+/* 45 */
+/***/ function(module, exports) {
+
+
+ module.exports = function windingLine(x0, y0, x1, y1, x, y) {
+ if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
+ return 0;
+ }
+ // Ignore horizontal line
+ if (y1 === y0) {
+ return 0;
+ }
+ var dir = y1 < y0 ? 1 : -1;
+ var t = (y - y0) / (y1 - y0);
+
+ // Avoid winding error when intersection point is the connect point of two line of polygon
+ if (t === 1 || t === 0) {
+ dir = y1 < y0 ? 0.5 : -0.5;
+ }
+
+ var x_ = t * (x1 - x0) + x0;
+
+ return x_ > x ? dir : 0;
+ };
+
+
+/***/ },
+/* 46 */
+/***/ function(module, exports) {
+
+
+
+ var Pattern = function (image, repeat) {
+ // Should do nothing more in this constructor. Because gradient can be
+ // declard by `color: {image: ...}`, where this constructor will not be called.
+
+ this.image = image;
+ this.repeat = repeat;
+
+ // Can be cloned
+ this.type = 'pattern';
+ };
+
+ Pattern.prototype.getCanvasPattern = function (ctx) {
+ return ctx.createPattern(this.image, this.repeat || 'repeat');
+ };
+
+ module.exports = Pattern;
+
+
+/***/ },
+/* 47 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var CMD = __webpack_require__(36).CMD;
+ var vec2 = __webpack_require__(10);
+ var v2ApplyTransform = vec2.applyTransform;
+
+ var points = [[], [], []];
+ var mathSqrt = Math.sqrt;
+ var mathAtan2 = Math.atan2;
+ function transformPath(path, m) {
+ var data = path.data;
+ var cmd;
+ var nPoint;
+ var i;
+ var j;
+ var k;
+ var p;
+
+ var M = CMD.M;
+ var C = CMD.C;
+ var L = CMD.L;
+ var R = CMD.R;
+ var A = CMD.A;
+ var Q = CMD.Q;
+
+ for (i = 0, j = 0; i < data.length;) {
+ cmd = data[i++];
+ j = i;
+ nPoint = 0;
+
+ switch (cmd) {
+ case M:
+ nPoint = 1;
+ break;
+ case L:
+ nPoint = 1;
+ break;
+ case C:
+ nPoint = 3;
+ break;
+ case Q:
+ nPoint = 2;
+ break;
+ case A:
+ var x = m[4];
+ var y = m[5];
+ var sx = mathSqrt(m[0] * m[0] + m[1] * m[1]);
+ var sy = mathSqrt(m[2] * m[2] + m[3] * m[3]);
+ var angle = mathAtan2(-m[1] / sy, m[0] / sx);
+ // cx
+ data[i] *= sx;
+ data[i++] += x;
+ // cy
+ data[i] *= sy;
+ data[i++] += y;
+ // Scale rx and ry
+ // FIXME Assume psi is 0 here
+ data[i++] *= sx;
+ data[i++] *= sy;
+
+ // Start angle
+ data[i++] += angle;
+ // end angle
+ data[i++] += angle;
+ // FIXME psi
+ i += 2;
+ j = i;
+ break;
+ case R:
+ // x0, y0
+ p[0] = data[i++];
+ p[1] = data[i++];
+ v2ApplyTransform(p, p, m);
+ data[j++] = p[0];
+ data[j++] = p[1];
+ // x1, y1
+ p[0] += data[i++];
+ p[1] += data[i++];
+ v2ApplyTransform(p, p, m);
+ data[j++] = p[0];
+ data[j++] = p[1];
+ }
+
+ for (k = 0; k < nPoint; k++) {
+ var p = points[k];
+ p[0] = data[i++];
+ p[1] = data[i++];
+
+ v2ApplyTransform(p, p, m);
+ // Write back
+ data[j++] = p[0];
+ data[j++] = p[1];
+ }
+ }
+ }
+
+ module.exports = transformPath;
+
+
+/***/ },
+/* 48 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上
+ * @module zrender/graphic/Group
+ * @example
+ * var Group = require('zrender/lib/container/Group');
+ * var Circle = require('zrender/lib/graphic/shape/Circle');
+ * var g = new Group();
+ * g.position[0] = 100;
+ * g.position[1] = 100;
+ * g.add(new Circle({
+ * style: {
+ * x: 100,
+ * y: 100,
+ * r: 20,
+ * }
+ * }));
+ * zr.add(g);
+ */
+
+
+ var zrUtil = __webpack_require__(4);
+ var Element = __webpack_require__(23);
+ var BoundingRect = __webpack_require__(9);
+
+ /**
+ * @alias module:zrender/graphic/Group
+ * @constructor
+ * @extends module:zrender/mixin/Transformable
+ * @extends module:zrender/mixin/Eventful
+ */
+ var Group = function (opts) {
+
+ opts = opts || {};
+
+ Element.call(this, opts);
+
+ for (var key in opts) {
+ if (opts.hasOwnProperty(key)) {
+ this[key] = opts[key];
+ }
+ }
+
+ this._children = [];
+
+ this.__storage = null;
+
+ this.__dirty = true;
+ };
+
+ Group.prototype = {
+
+ constructor: Group,
+
+ isGroup: true,
+
+ /**
+ * @type {string}
+ */
+ type: 'group',
+
+ /**
+ * 所有子孙元素是否响应鼠标事件
+ * @name module:/zrender/container/Group#silent
+ * @type {boolean}
+ * @default false
+ */
+ silent: false,
+
+ /**
+ * @return {Array.}
+ */
+ children: function () {
+ return this._children.slice();
+ },
+
+ /**
+ * 获取指定 index 的儿子节点
+ * @param {number} idx
+ * @return {module:zrender/Element}
+ */
+ childAt: function (idx) {
+ return this._children[idx];
+ },
+
+ /**
+ * 获取指定名字的儿子节点
+ * @param {string} name
+ * @return {module:zrender/Element}
+ */
+ childOfName: function (name) {
+ var children = this._children;
+ for (var i = 0; i < children.length; i++) {
+ if (children[i].name === name) {
+ return children[i];
+ }
+ }
+ },
+
+ /**
+ * @return {number}
+ */
+ childCount: function () {
+ return this._children.length;
+ },
+
+ /**
+ * 添加子节点到最后
+ * @param {module:zrender/Element} child
+ */
+ add: function (child) {
+ if (child && child !== this && child.parent !== this) {
+
+ this._children.push(child);
+
+ this._doAdd(child);
+ }
+
+ return this;
+ },
+
+ /**
+ * 添加子节点在 nextSibling 之前
+ * @param {module:zrender/Element} child
+ * @param {module:zrender/Element} nextSibling
+ */
+ addBefore: function (child, nextSibling) {
+ if (child && child !== this && child.parent !== this
+ && nextSibling && nextSibling.parent === this) {
+
+ var children = this._children;
+ var idx = children.indexOf(nextSibling);
+
+ if (idx >= 0) {
+ children.splice(idx, 0, child);
+ this._doAdd(child);
+ }
+ }
+
+ return this;
+ },
+
+ _doAdd: function (child) {
+ if (child.parent) {
+ child.parent.remove(child);
+ }
+
+ child.parent = this;
+
+ var storage = this.__storage;
+ var zr = this.__zr;
+ if (storage && storage !== child.__storage) {
+
+ storage.addToStorage(child);
+
+ if (child instanceof Group) {
+ child.addChildrenToStorage(storage);
+ }
+ }
+
+ zr && zr.refresh();
+ },
+
+ /**
+ * 移除子节点
+ * @param {module:zrender/Element} child
+ */
+ remove: function (child) {
+ var zr = this.__zr;
+ var storage = this.__storage;
+ var children = this._children;
+
+ var idx = zrUtil.indexOf(children, child);
+ if (idx < 0) {
+ return this;
+ }
+ children.splice(idx, 1);
+
+ child.parent = null;
+
+ if (storage) {
+
+ storage.delFromStorage(child);
+
+ if (child instanceof Group) {
+ child.delChildrenFromStorage(storage);
+ }
+ }
+
+ zr && zr.refresh();
+
+ return this;
+ },
+
+ /**
+ * 移除所有子节点
+ */
+ removeAll: function () {
+ var children = this._children;
+ var storage = this.__storage;
+ var child;
+ var i;
+ for (i = 0; i < children.length; i++) {
+ child = children[i];
+ if (storage) {
+ storage.delFromStorage(child);
+ if (child instanceof Group) {
+ child.delChildrenFromStorage(storage);
+ }
+ }
+ child.parent = null;
+ }
+ children.length = 0;
+
+ return this;
+ },
+
+ /**
+ * 遍历所有子节点
+ * @param {Function} cb
+ * @param {} context
+ */
+ eachChild: function (cb, context) {
+ var children = this._children;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ cb.call(context, child, i);
+ }
+ return this;
+ },
+
+ /**
+ * 深度优先遍历所有子孙节点
+ * @param {Function} cb
+ * @param {} context
+ */
+ traverse: function (cb, context) {
+ for (var i = 0; i < this._children.length; i++) {
+ var child = this._children[i];
+ cb.call(context, child);
+
+ if (child.type === 'group') {
+ child.traverse(cb, context);
+ }
+ }
+ return this;
+ },
+
+ addChildrenToStorage: function (storage) {
+ for (var i = 0; i < this._children.length; i++) {
+ var child = this._children[i];
+ storage.addToStorage(child);
+ if (child instanceof Group) {
+ child.addChildrenToStorage(storage);
+ }
+ }
+ },
+
+ delChildrenFromStorage: function (storage) {
+ for (var i = 0; i < this._children.length; i++) {
+ var child = this._children[i];
+ storage.delFromStorage(child);
+ if (child instanceof Group) {
+ child.delChildrenFromStorage(storage);
+ }
+ }
+ },
+
+ dirty: function () {
+ this.__dirty = true;
+ this.__zr && this.__zr.refresh();
+ return this;
+ },
+
+ /**
+ * @return {module:zrender/core/BoundingRect}
+ */
+ getBoundingRect: function (includeChildren) {
+ // TODO Caching
+ var rect = null;
+ var tmpRect = new BoundingRect(0, 0, 0, 0);
+ var children = includeChildren || this._children;
+ var tmpMat = [];
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if (child.ignore || child.invisible) {
+ continue;
+ }
+
+ var childRect = child.getBoundingRect();
+ var transform = child.getLocalTransform(tmpMat);
+ // TODO
+ // The boundingRect cacluated by transforming original
+ // rect may be bigger than the actual bundingRect when rotation
+ // is used. (Consider a circle rotated aginst its center, where
+ // the actual boundingRect should be the same as that not be
+ // rotated.) But we can not find better approach to calculate
+ // actual boundingRect yet, considering performance.
+ if (transform) {
+ tmpRect.copy(childRect);
+ tmpRect.applyTransform(transform);
+ rect = rect || tmpRect.clone();
+ rect.union(tmpRect);
+ }
+ else {
+ rect = rect || childRect.clone();
+ rect.union(childRect);
+ }
+ }
+ return rect || tmpRect;
+ }
+ };
+
+ zrUtil.inherits(Group, Element);
+
+ module.exports = Group;
+
+
+/***/ },
+/* 49 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Image element
+ * @module zrender/graphic/Image
+ */
+
+
+
+ var Displayable = __webpack_require__(21);
+ var BoundingRect = __webpack_require__(9);
+ var zrUtil = __webpack_require__(4);
+
+ var LRU = __webpack_require__(32);
+ var globalImageCache = new LRU(50);
+ /**
+ * @alias zrender/graphic/Image
+ * @extends module:zrender/graphic/Displayable
+ * @constructor
+ * @param {Object} opts
+ */
+ function ZImage(opts) {
+ Displayable.call(this, opts);
+ }
+
+ ZImage.prototype = {
+
+ constructor: ZImage,
+
+ type: 'image',
+
+ brush: function (ctx, prevEl) {
+ var style = this.style;
+ var src = style.image;
+ var image;
+
+ // Must bind each time
+ style.bind(ctx, this, prevEl);
+ // style.image is a url string
+ if (typeof src === 'string') {
+ image = this._image;
+ }
+ // style.image is an HTMLImageElement or HTMLCanvasElement or Canvas
+ else {
+ image = src;
+ }
+ // FIXME Case create many images with src
+ if (!image && src) {
+ // Try get from global image cache
+ var cachedImgObj = globalImageCache.get(src);
+ if (!cachedImgObj) {
+ // Create a new image
+ image = new Image();
+ image.onload = function () {
+ image.onload = null;
+ for (var i = 0; i < cachedImgObj.pending.length; i++) {
+ cachedImgObj.pending[i].dirty();
+ }
+ };
+ cachedImgObj = {
+ image: image,
+ pending: [this]
+ };
+ image.src = src;
+ globalImageCache.put(src, cachedImgObj);
+ this._image = image;
+ return;
+ }
+ else {
+ image = cachedImgObj.image;
+ this._image = image;
+ // Image is not complete finish, add to pending list
+ if (!image.width || !image.height) {
+ cachedImgObj.pending.push(this);
+ return;
+ }
+ }
+ }
+
+ if (image) {
+ // 图片已经加载完成
+ // if (image.nodeName.toUpperCase() == 'IMG') {
+ // if (!image.complete) {
+ // return;
+ // }
+ // }
+ // Else is canvas
+
+ var x = style.x || 0;
+ var y = style.y || 0;
+ // 图片加载失败
+ if (!image.width || !image.height) {
+ return;
+ }
+ var width = style.width;
+ var height = style.height;
+ var aspect = image.width / image.height;
+ if (width == null && height != null) {
+ // Keep image/height ratio
+ width = height * aspect;
+ }
+ else if (height == null && width != null) {
+ height = width / aspect;
+ }
+ else if (width == null && height == null) {
+ width = image.width;
+ height = image.height;
+ }
+
+ // 设置transform
+ this.setTransform(ctx);
+
+ if (style.sWidth && style.sHeight) {
+ var sx = style.sx || 0;
+ var sy = style.sy || 0;
+ ctx.drawImage(
+ image,
+ sx, sy, style.sWidth, style.sHeight,
+ x, y, width, height
+ );
+ }
+ else if (style.sx && style.sy) {
+ var sx = style.sx;
+ var sy = style.sy;
+ var sWidth = width - sx;
+ var sHeight = height - sy;
+ ctx.drawImage(
+ image,
+ sx, sy, sWidth, sHeight,
+ x, y, width, height
+ );
+ }
+ else {
+ ctx.drawImage(image, x, y, width, height);
+ }
+
+ this.restoreTransform(ctx);
+
+ // Draw rect text
+ if (style.text != null) {
+ this.drawRectText(ctx, this.getBoundingRect());
+ }
+
+ }
+ },
+
+ getBoundingRect: function () {
+ var style = this.style;
+ if (! this._rect) {
+ this._rect = new BoundingRect(
+ style.x || 0, style.y || 0, style.width || 0, style.height || 0
+ );
+ }
+ return this._rect;
+ }
+ };
+
+ zrUtil.inherits(ZImage, Displayable);
+
+ module.exports = ZImage;
+
+
+/***/ },
+/* 50 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Text element
+ * @module zrender/graphic/Text
+ *
+ * TODO Wrapping
+ *
+ * Text not support gradient
+ */
+
+
+
+ var Displayable = __webpack_require__(21);
+ var zrUtil = __webpack_require__(4);
+ var textContain = __webpack_require__(8);
+
+ /**
+ * @alias zrender/graphic/Text
+ * @extends module:zrender/graphic/Displayable
+ * @constructor
+ * @param {Object} opts
+ */
+ var Text = function (opts) {
+ Displayable.call(this, opts);
+ };
+
+ Text.prototype = {
+
+ constructor: Text,
+
+ type: 'text',
+
+ brush: function (ctx, prevEl) {
+ var style = this.style;
+ var x = style.x || 0;
+ var y = style.y || 0;
+ // Convert to string
+ var text = style.text;
+
+ // Convert to string
+ text != null && (text += '');
+
+ // Always bind style
+ style.bind(ctx, this, prevEl);
+
+ if (text) {
+
+ this.setTransform(ctx);
+
+ var textBaseline;
+ var textAlign = style.textAlign;
+ var font = style.textFont || style.font;
+ if (style.textVerticalAlign) {
+ var rect = textContain.getBoundingRect(
+ text, font, style.textAlign, 'top'
+ );
+ // Ignore textBaseline
+ textBaseline = 'middle';
+ switch (style.textVerticalAlign) {
+ case 'middle':
+ y -= rect.height / 2 - rect.lineHeight / 2;
+ break;
+ case 'bottom':
+ y -= rect.height - rect.lineHeight / 2;
+ break;
+ default:
+ y += rect.lineHeight / 2;
+ }
+ }
+ else {
+ textBaseline = style.textBaseline;
+ }
+
+ // TODO Invalid font
+ ctx.font = font || '12px sans-serif';
+ ctx.textAlign = textAlign || 'left';
+ // Use canvas default left textAlign. Giving invalid value will cause state not change
+ if (ctx.textAlign !== textAlign) {
+ ctx.textAlign = 'left';
+ }
+ // FIXME in text contain default is top
+ ctx.textBaseline = textBaseline || 'alphabetic';
+ // Use canvas default alphabetic baseline
+ if (ctx.textBaseline !== textBaseline) {
+ ctx.textBaseline = 'alphabetic';
+ }
+
+ var lineHeight = textContain.measureText('国', ctx.font).width;
+
+ var textLines = text.split('\n');
+ for (var i = 0; i < textLines.length; i++) {
+ // Fill after stroke so the outline will not cover the main part.
+ style.hasStroke() && ctx.strokeText(textLines[i], x, y);
+ style.hasFill() && ctx.fillText(textLines[i], x, y);
+ y += lineHeight;
+ }
+
+ this.restoreTransform(ctx);
+ }
+ },
+
+ getBoundingRect: function () {
+ var style = this.style;
+ if (!this._rect) {
+ var textVerticalAlign = style.textVerticalAlign;
+ var rect = textContain.getBoundingRect(
+ style.text + '', style.textFont || style.font, style.textAlign,
+ textVerticalAlign ? 'top' : style.textBaseline
+ );
+ switch (textVerticalAlign) {
+ case 'middle':
+ rect.y -= rect.height / 2;
+ break;
+ case 'bottom':
+ rect.y -= rect.height;
+ break;
+ }
+ rect.x += style.x || 0;
+ rect.y += style.y || 0;
+ if (style.hasStroke()) {
+ var w = style.lineWidth;
+ rect.x -= w / 2;
+ rect.y -= w / 2;
+ rect.width += w;
+ rect.height += w;
+ }
+ this._rect = rect;
+ }
+
+ return this._rect;
+ }
+ };
+
+ zrUtil.inherits(Text, Displayable);
+
+ module.exports = Text;
+
+
+/***/ },
+/* 51 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 圆形
+ * @module zrender/shape/Circle
+ */
+
+
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'circle',
+
+ shape: {
+ cx: 0,
+ cy: 0,
+ r: 0
+ },
+
+
+ buildPath : function (ctx, shape, inBundle) {
+ // Better stroking in ShapeBundle
+ // Always do it may have performence issue ( fill may be 2x more cost)
+ if (inBundle) {
+ ctx.moveTo(shape.cx + shape.r, shape.cy);
+ }
+ // else {
+ // if (ctx.allocate && !ctx.data.length) {
+ // ctx.allocate(ctx.CMD_MEM_SIZE.A);
+ // }
+ // }
+ // Better stroking in ShapeBundle
+ // ctx.moveTo(shape.cx + shape.r, shape.cy);
+ ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);
+ }
+ });
+
+
+
+/***/ },
+/* 52 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 扇形
+ * @module zrender/graphic/shape/Sector
+ */
+
+
+
+ var env = __webpack_require__(2);
+ var Path = __webpack_require__(20);
+
+ var shadowTemp = [
+ ['shadowBlur', 0],
+ ['shadowColor', '#000'],
+ ['shadowOffsetX', 0],
+ ['shadowOffsetY', 0]
+ ];
+
+ module.exports = Path.extend({
+
+ type: 'sector',
+
+ shape: {
+
+ cx: 0,
+
+ cy: 0,
+
+ r0: 0,
+
+ r: 0,
+
+ startAngle: 0,
+
+ endAngle: Math.PI * 2,
+
+ clockwise: true
+ },
+
+ brush: (env.browser.ie && env.browser.version >= 11) // version: '11.0'
+ // Fix weird bug in some version of IE11 (like 11.0.9600.17801),
+ // where exception "unexpected call to method or property access"
+ // might be thrown when calling ctx.fill after a path whose area size
+ // is zero is drawn and ctx.clip() is called and shadowBlur is set.
+ // (e.g.,
+ // ctx.moveTo(10, 10);
+ // ctx.lineTo(20, 10);
+ // ctx.closePath();
+ // ctx.clip();
+ // ctx.shadowBlur = 10;
+ // ...
+ // ctx.fill();
+ // )
+ ? function () {
+ var clipPaths = this.__clipPaths;
+ var style = this.style;
+ var modified;
+
+ if (clipPaths) {
+ for (var i = 0; i < clipPaths.length; i++) {
+ var shape = clipPaths[i] && clipPaths[i].shape;
+ if (shape && shape.startAngle === shape.endAngle) {
+ for (var j = 0; j < shadowTemp.length; j++) {
+ shadowTemp[j][2] = style[shadowTemp[j][0]];
+ style[shadowTemp[j][0]] = shadowTemp[j][1];
+ }
+ modified = true;
+ break;
+ }
+ }
+ }
+
+ Path.prototype.brush.apply(this, arguments);
+
+ if (modified) {
+ for (var j = 0; j < shadowTemp.length; j++) {
+ style[shadowTemp[j][0]] = shadowTemp[j][2];
+ }
+ }
+ }
+ : Path.prototype.brush,
+
+ buildPath: function (ctx, shape) {
+
+ var x = shape.cx;
+ var y = shape.cy;
+ var r0 = Math.max(shape.r0 || 0, 0);
+ var r = Math.max(shape.r, 0);
+ var startAngle = shape.startAngle;
+ var endAngle = shape.endAngle;
+ var clockwise = shape.clockwise;
+
+ var unitX = Math.cos(startAngle);
+ var unitY = Math.sin(startAngle);
+
+ ctx.moveTo(unitX * r0 + x, unitY * r0 + y);
+
+ ctx.lineTo(unitX * r + x, unitY * r + y);
+
+ ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
+
+ ctx.lineTo(
+ Math.cos(endAngle) * r0 + x,
+ Math.sin(endAngle) * r0 + y
+ );
+
+ if (r0 !== 0) {
+ ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
+ }
+
+ ctx.closePath();
+ }
+ });
+
+
+
+/***/ },
+/* 53 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 圆环
+ * @module zrender/graphic/shape/Ring
+ */
+
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'ring',
+
+ shape: {
+ cx: 0,
+ cy: 0,
+ r: 0,
+ r0: 0
+ },
+
+ buildPath: function (ctx, shape) {
+ var x = shape.cx;
+ var y = shape.cy;
+ var PI2 = Math.PI * 2;
+ ctx.moveTo(x + shape.r, y);
+ ctx.arc(x, y, shape.r, 0, PI2, false);
+ ctx.moveTo(x + shape.r0, y);
+ ctx.arc(x, y, shape.r0, 0, PI2, true);
+ }
+ });
+
+
+
+/***/ },
+/* 54 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 多边形
+ * @module zrender/shape/Polygon
+ */
+
+
+ var polyHelper = __webpack_require__(55);
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'polygon',
+
+ shape: {
+ points: null,
+
+ smooth: false,
+
+ smoothConstraint: null
+ },
+
+ buildPath: function (ctx, shape) {
+ polyHelper.buildPath(ctx, shape, true);
+ }
+ });
+
+
+/***/ },
+/* 55 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var smoothSpline = __webpack_require__(56);
+ var smoothBezier = __webpack_require__(57);
+
+ module.exports = {
+ buildPath: function (ctx, shape, closePath) {
+ var points = shape.points;
+ var smooth = shape.smooth;
+ if (points && points.length >= 2) {
+ if (smooth && smooth !== 'spline') {
+ var controlPoints = smoothBezier(
+ points, smooth, closePath, shape.smoothConstraint
+ );
+
+ ctx.moveTo(points[0][0], points[0][1]);
+ var len = points.length;
+ for (var i = 0; i < (closePath ? len : len - 1); i++) {
+ var cp1 = controlPoints[i * 2];
+ var cp2 = controlPoints[i * 2 + 1];
+ var p = points[(i + 1) % len];
+ ctx.bezierCurveTo(
+ cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]
+ );
+ }
+ }
+ else {
+ if (smooth === 'spline') {
+ points = smoothSpline(points, closePath);
+ }
+
+ ctx.moveTo(points[0][0], points[0][1]);
+ for (var i = 1, l = points.length; i < l; i++) {
+ ctx.lineTo(points[i][0], points[i][1]);
+ }
+ }
+
+ closePath && ctx.closePath();
+ }
+ }
+ };
+
+
+/***/ },
+/* 56 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Catmull-Rom spline 插值折线
+ * @module zrender/shape/util/smoothSpline
+ * @author pissang (https://www.github.com/pissang)
+ * Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * errorrik (errorrik@gmail.com)
+ */
+
+ var vec2 = __webpack_require__(10);
+
+ /**
+ * @inner
+ */
+ function interpolate(p0, p1, p2, p3, t, t2, t3) {
+ var v0 = (p2 - p0) * 0.5;
+ var v1 = (p3 - p1) * 0.5;
+ return (2 * (p1 - p2) + v0 + v1) * t3
+ + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
+ + v0 * t + p1;
+ }
+
+ /**
+ * @alias module:zrender/shape/util/smoothSpline
+ * @param {Array} points 线段顶点数组
+ * @param {boolean} isLoop
+ * @return {Array}
+ */
+ module.exports = function (points, isLoop) {
+ var len = points.length;
+ var ret = [];
+
+ var distance = 0;
+ for (var i = 1; i < len; i++) {
+ distance += vec2.distance(points[i - 1], points[i]);
+ }
+
+ var segs = distance / 2;
+ segs = segs < len ? len : segs;
+ for (var i = 0; i < segs; i++) {
+ var pos = i / (segs - 1) * (isLoop ? len : len - 1);
+ var idx = Math.floor(pos);
+
+ var w = pos - idx;
+
+ var p0;
+ var p1 = points[idx % len];
+ var p2;
+ var p3;
+ if (!isLoop) {
+ p0 = points[idx === 0 ? idx : idx - 1];
+ p2 = points[idx > len - 2 ? len - 1 : idx + 1];
+ p3 = points[idx > len - 3 ? len - 1 : idx + 2];
+ }
+ else {
+ p0 = points[(idx - 1 + len) % len];
+ p2 = points[(idx + 1) % len];
+ p3 = points[(idx + 2) % len];
+ }
+
+ var w2 = w * w;
+ var w3 = w * w2;
+
+ ret.push([
+ interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),
+ interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)
+ ]);
+ }
+ return ret;
+ };
+
+
+
+/***/ },
+/* 57 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 贝塞尔平滑曲线
+ * @module zrender/shape/util/smoothBezier
+ * @author pissang (https://www.github.com/pissang)
+ * Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * errorrik (errorrik@gmail.com)
+ */
+
+
+ var vec2 = __webpack_require__(10);
+ var v2Min = vec2.min;
+ var v2Max = vec2.max;
+ var v2Scale = vec2.scale;
+ var v2Distance = vec2.distance;
+ var v2Add = vec2.add;
+
+ /**
+ * 贝塞尔平滑曲线
+ * @alias module:zrender/shape/util/smoothBezier
+ * @param {Array} points 线段顶点数组
+ * @param {number} smooth 平滑等级, 0-1
+ * @param {boolean} isLoop
+ * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内
+ * 比如 [[0, 0], [100, 100]], 这个包围盒会与
+ * 整个折线的包围盒做一个并集用来约束控制点。
+ * @param {Array} 计算出来的控制点数组
+ */
+ module.exports = function (points, smooth, isLoop, constraint) {
+ var cps = [];
+
+ var v = [];
+ var v1 = [];
+ var v2 = [];
+ var prevPoint;
+ var nextPoint;
+
+ var min, max;
+ if (constraint) {
+ min = [Infinity, Infinity];
+ max = [-Infinity, -Infinity];
+ for (var i = 0, len = points.length; i < len; i++) {
+ v2Min(min, min, points[i]);
+ v2Max(max, max, points[i]);
+ }
+ // 与指定的包围盒做并集
+ v2Min(min, min, constraint[0]);
+ v2Max(max, max, constraint[1]);
+ }
+
+ for (var i = 0, len = points.length; i < len; i++) {
+ var point = points[i];
+
+ if (isLoop) {
+ prevPoint = points[i ? i - 1 : len - 1];
+ nextPoint = points[(i + 1) % len];
+ }
+ else {
+ if (i === 0 || i === len - 1) {
+ cps.push(vec2.clone(points[i]));
+ continue;
+ }
+ else {
+ prevPoint = points[i - 1];
+ nextPoint = points[i + 1];
+ }
+ }
+
+ vec2.sub(v, nextPoint, prevPoint);
+
+ // use degree to scale the handle length
+ v2Scale(v, v, smooth);
+
+ var d0 = v2Distance(point, prevPoint);
+ var d1 = v2Distance(point, nextPoint);
+ var sum = d0 + d1;
+ if (sum !== 0) {
+ d0 /= sum;
+ d1 /= sum;
+ }
+
+ v2Scale(v1, v, -d0);
+ v2Scale(v2, v, d1);
+ var cp0 = v2Add([], point, v1);
+ var cp1 = v2Add([], point, v2);
+ if (constraint) {
+ v2Max(cp0, cp0, min);
+ v2Min(cp0, cp0, max);
+ v2Max(cp1, cp1, min);
+ v2Min(cp1, cp1, max);
+ }
+ cps.push(cp0);
+ cps.push(cp1);
+ }
+
+ if (isLoop) {
+ cps.push(cps.shift());
+ }
+
+ return cps;
+ };
+
+
+
+/***/ },
+/* 58 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @module zrender/graphic/shape/Polyline
+ */
+
+
+ var polyHelper = __webpack_require__(55);
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'polyline',
+
+ shape: {
+ points: null,
+
+ smooth: false,
+
+ smoothConstraint: null
+ },
+
+ style: {
+ stroke: '#000',
+
+ fill: null
+ },
+
+ buildPath: function (ctx, shape) {
+ polyHelper.buildPath(ctx, shape, false);
+ }
+ });
+
+
+/***/ },
+/* 59 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 矩形
+ * @module zrender/graphic/shape/Rect
+ */
+
+
+ var roundRectHelper = __webpack_require__(60);
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'rect',
+
+ shape: {
+ // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4
+ // r缩写为1 相当于 [1, 1, 1, 1]
+ // r缩写为[1] 相当于 [1, 1, 1, 1]
+ // r缩写为[1, 2] 相当于 [1, 2, 1, 2]
+ // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]
+ r: 0,
+
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0
+ },
+
+ buildPath: function (ctx, shape) {
+ var x = shape.x;
+ var y = shape.y;
+ var width = shape.width;
+ var height = shape.height;
+ if (!shape.r) {
+ ctx.rect(x, y, width, height);
+ }
+ else {
+ roundRectHelper.buildPath(ctx, shape);
+ }
+ ctx.closePath();
+ return;
+ }
+ });
+
+
+
+/***/ },
+/* 60 */
+/***/ function(module, exports) {
+
+
+
+ module.exports = {
+ buildPath: function (ctx, shape) {
+ var x = shape.x;
+ var y = shape.y;
+ var width = shape.width;
+ var height = shape.height;
+ var r = shape.r;
+ var r1;
+ var r2;
+ var r3;
+ var r4;
+
+ // Convert width and height to positive for better borderRadius
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+
+ if (typeof r === 'number') {
+ r1 = r2 = r3 = r4 = r;
+ }
+ else if (r instanceof Array) {
+ if (r.length === 1) {
+ r1 = r2 = r3 = r4 = r[0];
+ }
+ else if (r.length === 2) {
+ r1 = r3 = r[0];
+ r2 = r4 = r[1];
+ }
+ else if (r.length === 3) {
+ r1 = r[0];
+ r2 = r4 = r[1];
+ r3 = r[2];
+ }
+ else {
+ r1 = r[0];
+ r2 = r[1];
+ r3 = r[2];
+ r4 = r[3];
+ }
+ }
+ else {
+ r1 = r2 = r3 = r4 = 0;
+ }
+
+ var total;
+ if (r1 + r2 > width) {
+ total = r1 + r2;
+ r1 *= width / total;
+ r2 *= width / total;
+ }
+ if (r3 + r4 > width) {
+ total = r3 + r4;
+ r3 *= width / total;
+ r4 *= width / total;
+ }
+ if (r2 + r3 > height) {
+ total = r2 + r3;
+ r2 *= height / total;
+ r3 *= height / total;
+ }
+ if (r1 + r4 > height) {
+ total = r1 + r4;
+ r1 *= height / total;
+ r4 *= height / total;
+ }
+ ctx.moveTo(x + r1, y);
+ ctx.lineTo(x + width - r2, y);
+ r2 !== 0 && ctx.quadraticCurveTo(
+ x + width, y, x + width, y + r2
+ );
+ ctx.lineTo(x + width, y + height - r3);
+ r3 !== 0 && ctx.quadraticCurveTo(
+ x + width, y + height, x + width - r3, y + height
+ );
+ ctx.lineTo(x + r4, y + height);
+ r4 !== 0 && ctx.quadraticCurveTo(
+ x, y + height, x, y + height - r4
+ );
+ ctx.lineTo(x, y + r1);
+ r1 !== 0 && ctx.quadraticCurveTo(x, y, x + r1, y);
+ }
+ };
+
+
+/***/ },
+/* 61 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 直线
+ * @module zrender/graphic/shape/Line
+ */
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'line',
+
+ shape: {
+ // Start point
+ x1: 0,
+ y1: 0,
+ // End point
+ x2: 0,
+ y2: 0,
+
+ percent: 1
+ },
+
+ style: {
+ stroke: '#000',
+ fill: null
+ },
+
+ buildPath: function (ctx, shape) {
+ var x1 = shape.x1;
+ var y1 = shape.y1;
+ var x2 = shape.x2;
+ var y2 = shape.y2;
+ var percent = shape.percent;
+
+ if (percent === 0) {
+ return;
+ }
+
+ ctx.moveTo(x1, y1);
+
+ if (percent < 1) {
+ x2 = x1 * (1 - percent) + x2 * percent;
+ y2 = y1 * (1 - percent) + y2 * percent;
+ }
+ ctx.lineTo(x2, y2);
+ },
+
+ /**
+ * Get point at percent
+ * @param {number} percent
+ * @return {Array.}
+ */
+ pointAt: function (p) {
+ var shape = this.shape;
+ return [
+ shape.x1 * (1 - p) + shape.x2 * p,
+ shape.y1 * (1 - p) + shape.y2 * p
+ ];
+ }
+ });
+
+
+
+/***/ },
+/* 62 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 贝塞尔曲线
+ * @module zrender/shape/BezierCurve
+ */
+
+
+ var curveTool = __webpack_require__(37);
+ var vec2 = __webpack_require__(10);
+ var quadraticSubdivide = curveTool.quadraticSubdivide;
+ var cubicSubdivide = curveTool.cubicSubdivide;
+ var quadraticAt = curveTool.quadraticAt;
+ var cubicAt = curveTool.cubicAt;
+ var quadraticDerivativeAt = curveTool.quadraticDerivativeAt;
+ var cubicDerivativeAt = curveTool.cubicDerivativeAt;
+
+ var out = [];
+
+ function someVectorAt(shape, t, isTangent) {
+ var cpx2 = shape.cpx2;
+ var cpy2 = shape.cpy2;
+ if (cpx2 === null || cpy2 === null) {
+ return [
+ (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),
+ (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)
+ ];
+ }
+ else {
+ return [
+ (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),
+ (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)
+ ];
+ }
+ }
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'bezier-curve',
+
+ shape: {
+ x1: 0,
+ y1: 0,
+ x2: 0,
+ y2: 0,
+ cpx1: 0,
+ cpy1: 0,
+ // cpx2: 0,
+ // cpy2: 0
+
+ // Curve show percent, for animating
+ percent: 1
+ },
+
+ style: {
+ stroke: '#000',
+ fill: null
+ },
+
+ buildPath: function (ctx, shape) {
+ var x1 = shape.x1;
+ var y1 = shape.y1;
+ var x2 = shape.x2;
+ var y2 = shape.y2;
+ var cpx1 = shape.cpx1;
+ var cpy1 = shape.cpy1;
+ var cpx2 = shape.cpx2;
+ var cpy2 = shape.cpy2;
+ var percent = shape.percent;
+ if (percent === 0) {
+ return;
+ }
+
+ ctx.moveTo(x1, y1);
+
+ if (cpx2 == null || cpy2 == null) {
+ if (percent < 1) {
+ quadraticSubdivide(
+ x1, cpx1, x2, percent, out
+ );
+ cpx1 = out[1];
+ x2 = out[2];
+ quadraticSubdivide(
+ y1, cpy1, y2, percent, out
+ );
+ cpy1 = out[1];
+ y2 = out[2];
+ }
+
+ ctx.quadraticCurveTo(
+ cpx1, cpy1,
+ x2, y2
+ );
+ }
+ else {
+ if (percent < 1) {
+ cubicSubdivide(
+ x1, cpx1, cpx2, x2, percent, out
+ );
+ cpx1 = out[1];
+ cpx2 = out[2];
+ x2 = out[3];
+ cubicSubdivide(
+ y1, cpy1, cpy2, y2, percent, out
+ );
+ cpy1 = out[1];
+ cpy2 = out[2];
+ y2 = out[3];
+ }
+ ctx.bezierCurveTo(
+ cpx1, cpy1,
+ cpx2, cpy2,
+ x2, y2
+ );
+ }
+ },
+
+ /**
+ * Get point at percent
+ * @param {number} t
+ * @return {Array.}
+ */
+ pointAt: function (t) {
+ return someVectorAt(this.shape, t, false);
+ },
+
+ /**
+ * Get tangent at percent
+ * @param {number} t
+ * @return {Array.}
+ */
+ tangentAt: function (t) {
+ var p = someVectorAt(this.shape, t, true);
+ return vec2.normalize(p, p);
+ }
+ });
+
+
+
+/***/ },
+/* 63 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * 圆弧
+ * @module zrender/graphic/shape/Arc
+ */
+
+
+ module.exports = __webpack_require__(20).extend({
+
+ type: 'arc',
+
+ shape: {
+
+ cx: 0,
+
+ cy: 0,
+
+ r: 0,
+
+ startAngle: 0,
+
+ endAngle: Math.PI * 2,
+
+ clockwise: true
+ },
+
+ style: {
+
+ stroke: '#000',
+
+ fill: null
+ },
+
+ buildPath: function (ctx, shape) {
+
+ var x = shape.cx;
+ var y = shape.cy;
+ var r = Math.max(shape.r, 0);
+ var startAngle = shape.startAngle;
+ var endAngle = shape.endAngle;
+ var clockwise = shape.clockwise;
+
+ var unitX = Math.cos(startAngle);
+ var unitY = Math.sin(startAngle);
+
+ ctx.moveTo(unitX * r + x, unitY * r + y);
+ ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
+ }
+ });
+
+
+/***/ },
+/* 64 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // CompoundPath to improve performance
+
+
+ var Path = __webpack_require__(20);
+
+ module.exports = Path.extend({
+
+ type: 'compound',
+
+ shape: {
+
+ paths: null
+ },
+
+ _updatePathDirty: function () {
+ var dirtyPath = this.__dirtyPath;
+ var paths = this.shape.paths;
+ for (var i = 0; i < paths.length; i++) {
+ // Mark as dirty if any subpath is dirty
+ dirtyPath = dirtyPath || paths[i].__dirtyPath;
+ }
+ this.__dirtyPath = dirtyPath;
+ this.__dirty = this.__dirty || dirtyPath;
+ },
+
+ beforeBrush: function () {
+ this._updatePathDirty();
+ var paths = this.shape.paths || [];
+ var scale = this.getGlobalScale();
+ // Update path scale
+ for (var i = 0; i < paths.length; i++) {
+ if (!paths[i].path) {
+ paths[i].createPathProxy();
+ }
+ paths[i].path.setScale(scale[0], scale[1]);
+ }
+ },
+
+ buildPath: function (ctx, shape) {
+ var paths = shape.paths || [];
+ for (var i = 0; i < paths.length; i++) {
+ paths[i].buildPath(ctx, paths[i].shape, true);
+ }
+ },
+
+ afterBrush: function () {
+ var paths = this.shape.paths;
+ for (var i = 0; i < paths.length; i++) {
+ paths[i].__dirtyPath = false;
+ }
+ },
+
+ getBoundingRect: function () {
+ this._updatePathDirty();
+ return Path.prototype.getBoundingRect.call(this);
+ }
+ });
+
+
+/***/ },
+/* 65 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var Gradient = __webpack_require__(66);
+
+ /**
+ * x, y, x2, y2 are all percent from 0 to 1
+ * @param {number} [x=0]
+ * @param {number} [y=0]
+ * @param {number} [x2=1]
+ * @param {number} [y2=0]
+ * @param {Array.} colorStops
+ * @param {boolean} [globalCoord=false]
+ */
+ var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {
+ // Should do nothing more in this constructor. Because gradient can be
+ // declard by `color: {type: 'linear', colorStops: ...}`, where
+ // this constructor will not be called.
+
+ this.x = x == null ? 0 : x;
+
+ this.y = y == null ? 0 : y;
+
+ this.x2 = x2 == null ? 1 : x2;
+
+ this.y2 = y2 == null ? 0 : y2;
+
+ // Can be cloned
+ this.type = 'linear';
+
+ // If use global coord
+ this.global = globalCoord || false;
+
+ Gradient.call(this, colorStops);
+ };
+
+ LinearGradient.prototype = {
+
+ constructor: LinearGradient
+ };
+
+ zrUtil.inherits(LinearGradient, Gradient);
+
+ module.exports = LinearGradient;
+
+
+/***/ },
+/* 66 */
+/***/ function(module, exports) {
+
+
+
+ /**
+ * @param {Array.} colorStops
+ */
+ var Gradient = function (colorStops) {
+
+ this.colorStops = colorStops || [];
+ };
+
+ Gradient.prototype = {
+
+ constructor: Gradient,
+
+ addColorStop: function (offset, color) {
+ this.colorStops.push({
+
+ offset: offset,
+
+ color: color
+ });
+ }
+ };
+
+ module.exports = Gradient;
+
+
+/***/ },
+/* 67 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var Gradient = __webpack_require__(66);
+
+ /**
+ * x, y, r are all percent from 0 to 1
+ * @param {number} [x=0.5]
+ * @param {number} [y=0.5]
+ * @param {number} [r=0.5]
+ * @param {Array.} [colorStops]
+ * @param {boolean} [globalCoord=false]
+ */
+ var RadialGradient = function (x, y, r, colorStops, globalCoord) {
+ // Should do nothing more in this constructor. Because gradient can be
+ // declard by `color: {type: 'radial', colorStops: ...}`, where
+ // this constructor will not be called.
+
+ this.x = x == null ? 0.5 : x;
+
+ this.y = y == null ? 0.5 : y;
+
+ this.r = r == null ? 0.5 : r;
+
+ // Can be cloned
+ this.type = 'radial';
+
+ // If use global coord
+ this.global = globalCoord || false;
+
+ Gradient.call(this, colorStops);
+ };
+
+ RadialGradient.prototype = {
+
+ constructor: RadialGradient
+ };
+
+ zrUtil.inherits(RadialGradient, Gradient);
+
+ module.exports = RadialGradient;
+
+
+/***/ },
+/* 68 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ var getItemStyle = __webpack_require__(15)(
+ [
+ ['fill', 'color'],
+ ['stroke', 'borderColor'],
+ ['lineWidth', 'borderWidth'],
+ ['opacity'],
+ ['shadowBlur'],
+ ['shadowOffsetX'],
+ ['shadowOffsetY'],
+ ['shadowColor'],
+ ['textPosition'],
+ ['textAlign']
+ ]
+ );
+ module.exports = {
+ getItemStyle: function (excludes, includes) {
+ var style = getItemStyle.call(this, excludes, includes);
+ var lineDash = this.getBorderLineDash();
+ lineDash && (style.lineDash = lineDash);
+ return style;
+ },
+
+ getBorderLineDash: function () {
+ var lineType = this.get('borderType');
+ return (lineType === 'solid' || lineType == null) ? null
+ : (lineType === 'dashed' ? [5, 5] : [1, 1]);
+ }
+ };
+
+
+/***/ },
+/* 69 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Component model
+ *
+ * @module echarts/model/Component
+ */
+
+
+ var Model = __webpack_require__(12);
+ var zrUtil = __webpack_require__(4);
+ var arrayPush = Array.prototype.push;
+ var componentUtil = __webpack_require__(70);
+ var clazzUtil = __webpack_require__(13);
+ var layout = __webpack_require__(71);
+
+ /**
+ * @alias module:echarts/model/Component
+ * @constructor
+ * @param {Object} option
+ * @param {module:echarts/model/Model} parentModel
+ * @param {module:echarts/model/Model} ecModel
+ */
+ var ComponentModel = Model.extend({
+
+ type: 'component',
+
+ /**
+ * @readOnly
+ * @type {string}
+ */
+ id: '',
+
+ /**
+ * @readOnly
+ */
+ name: '',
+
+ /**
+ * @readOnly
+ * @type {string}
+ */
+ mainType: '',
+
+ /**
+ * @readOnly
+ * @type {string}
+ */
+ subType: '',
+
+ /**
+ * @readOnly
+ * @type {number}
+ */
+ componentIndex: 0,
+
+ /**
+ * @type {Object}
+ * @protected
+ */
+ defaultOption: null,
+
+ /**
+ * @type {module:echarts/model/Global}
+ * @readOnly
+ */
+ ecModel: null,
+
+ /**
+ * key: componentType
+ * value: Component model list, can not be null.
+ * @type {Object.>}
+ * @readOnly
+ */
+ dependentModels: [],
+
+ /**
+ * @type {string}
+ * @readOnly
+ */
+ uid: null,
+
+ /**
+ * Support merge layout params.
+ * Only support 'box' now (left/right/top/bottom/width/height).
+ * @type {string|Object} Object can be {ignoreSize: true}
+ * @readOnly
+ */
+ layoutMode: null,
+
+ $constructor: function (option, parentModel, ecModel, extraOpt) {
+ Model.call(this, option, parentModel, ecModel, extraOpt);
+
+ this.uid = componentUtil.getUID('componentModel');
+ },
+
+
+ init: function (option, parentModel, ecModel, extraOpt) {
+ this.mergeDefaultAndTheme(option, ecModel);
+ },
+
+ mergeDefaultAndTheme: function (option, ecModel) {
+ var layoutMode = this.layoutMode;
+ var inputPositionParams = layoutMode
+ ? layout.getLayoutParams(option) : {};
+
+ var themeModel = ecModel.getTheme();
+ zrUtil.merge(option, themeModel.get(this.mainType));
+ zrUtil.merge(option, this.getDefaultOption());
+
+ if (layoutMode) {
+ layout.mergeLayoutParam(option, inputPositionParams, layoutMode);
+ }
+ },
+
+ mergeOption: function (option, extraOpt) {
+ zrUtil.merge(this.option, option, true);
+
+ var layoutMode = this.layoutMode;
+ if (layoutMode) {
+ layout.mergeLayoutParam(this.option, option, layoutMode);
+ }
+ },
+
+ // Hooker after init or mergeOption
+ optionUpdated: function (newCptOption, isInit) {},
+
+ getDefaultOption: function () {
+ if (!clazzUtil.hasOwn(this, '__defaultOption')) {
+ var optList = [];
+ var Class = this.constructor;
+ while (Class) {
+ var opt = Class.prototype.defaultOption;
+ opt && optList.push(opt);
+ Class = Class.superClass;
+ }
+
+ var defaultOption = {};
+ for (var i = optList.length - 1; i >= 0; i--) {
+ defaultOption = zrUtil.merge(defaultOption, optList[i], true);
+ }
+ clazzUtil.set(this, '__defaultOption', defaultOption);
+ }
+ return clazzUtil.get(this, '__defaultOption');
+ },
+
+ getReferringComponents: function (mainType) {
+ return this.ecModel.queryComponents({
+ mainType: mainType,
+ index: this.get(mainType + 'Index', true),
+ id: this.get(mainType + 'Id', true)
+ });
+ }
+
+ });
+
+ // Reset ComponentModel.extend, add preConstruct.
+ // clazzUtil.enableClassExtend(
+ // ComponentModel,
+ // function (option, parentModel, ecModel, extraOpt) {
+ // // Set dependentModels, componentIndex, name, id, mainType, subType.
+ // zrUtil.extend(this, extraOpt);
+
+ // this.uid = componentUtil.getUID('componentModel');
+
+ // // this.setReadOnly([
+ // // 'type', 'id', 'uid', 'name', 'mainType', 'subType',
+ // // 'dependentModels', 'componentIndex'
+ // // ]);
+ // }
+ // );
+
+ // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
+ clazzUtil.enableClassManagement(
+ ComponentModel, {registerWhenExtend: true}
+ );
+ componentUtil.enableSubTypeDefaulter(ComponentModel);
+
+ // Add capability of ComponentModel.topologicalTravel.
+ componentUtil.enableTopologicalTravel(ComponentModel, getDependencies);
+
+ function getDependencies(componentType) {
+ var deps = [];
+ zrUtil.each(ComponentModel.getClassesByMainType(componentType), function (Clazz) {
+ arrayPush.apply(deps, Clazz.prototype.dependencies || []);
+ });
+ // Ensure main type
+ return zrUtil.map(deps, function (type) {
+ return clazzUtil.parseClassType(type).main;
+ });
+ }
+
+ zrUtil.mixin(ComponentModel, __webpack_require__(72));
+
+ module.exports = ComponentModel;
+
+
+/***/ },
+/* 70 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var zrUtil = __webpack_require__(4);
+ var clazz = __webpack_require__(13);
+
+ var parseClassType = clazz.parseClassType;
+
+ var base = 0;
+
+ var componentUtil = {};
+
+ var DELIMITER = '_';
+
+ /**
+ * @public
+ * @param {string} type
+ * @return {string}
+ */
+ componentUtil.getUID = function (type) {
+ // Considering the case of crossing js context,
+ // use Math.random to make id as unique as possible.
+ return [(type || ''), base++, Math.random()].join(DELIMITER);
+ };
+
+ /**
+ * @inner
+ */
+ componentUtil.enableSubTypeDefaulter = function (entity) {
+
+ var subTypeDefaulters = {};
+
+ entity.registerSubTypeDefaulter = function (componentType, defaulter) {
+ componentType = parseClassType(componentType);
+ subTypeDefaulters[componentType.main] = defaulter;
+ };
+
+ entity.determineSubType = function (componentType, option) {
+ var type = option.type;
+ if (!type) {
+ var componentTypeMain = parseClassType(componentType).main;
+ if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {
+ type = subTypeDefaulters[componentTypeMain](option);
+ }
+ }
+ return type;
+ };
+
+ return entity;
+ };
+
+ /**
+ * Topological travel on Activity Network (Activity On Vertices).
+ * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].
+ *
+ * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.
+ *
+ * If there is circle dependencey, Error will be thrown.
+ *
+ */
+ componentUtil.enableTopologicalTravel = function (entity, dependencyGetter) {
+
+ /**
+ * @public
+ * @param {Array.} targetNameList Target Component type list.
+ * Can be ['aa', 'bb', 'aa.xx']
+ * @param {Array.} fullNameList By which we can build dependency graph.
+ * @param {Function} callback Params: componentType, dependencies.
+ * @param {Object} context Scope of callback.
+ */
+ entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {
+ if (!targetNameList.length) {
+ return;
+ }
+
+ var result = makeDepndencyGraph(fullNameList);
+ var graph = result.graph;
+ var stack = result.noEntryList;
+
+ var targetNameSet = {};
+ zrUtil.each(targetNameList, function (name) {
+ targetNameSet[name] = true;
+ });
+
+ while (stack.length) {
+ var currComponentType = stack.pop();
+ var currVertex = graph[currComponentType];
+ var isInTargetNameSet = !!targetNameSet[currComponentType];
+ if (isInTargetNameSet) {
+ callback.call(context, currComponentType, currVertex.originalDeps.slice());
+ delete targetNameSet[currComponentType];
+ }
+ zrUtil.each(
+ currVertex.successor,
+ isInTargetNameSet ? removeEdgeAndAdd : removeEdge
+ );
+ }
+
+ zrUtil.each(targetNameSet, function () {
+ throw new Error('Circle dependency may exists');
+ });
+
+ function removeEdge(succComponentType) {
+ graph[succComponentType].entryCount--;
+ if (graph[succComponentType].entryCount === 0) {
+ stack.push(succComponentType);
+ }
+ }
+
+ // Consider this case: legend depends on series, and we call
+ // chart.setOption({series: [...]}), where only series is in option.
+ // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will
+ // not be called, but only sereis.mergeOption is called. Thus legend
+ // have no chance to update its local record about series (like which
+ // name of series is available in legend).
+ function removeEdgeAndAdd(succComponentType) {
+ targetNameSet[succComponentType] = true;
+ removeEdge(succComponentType);
+ }
+ };
+
+ /**
+ * DepndencyGraph: {Object}
+ * key: conponentType,
+ * value: {
+ * successor: [conponentTypes...],
+ * originalDeps: [conponentTypes...],
+ * entryCount: {number}
+ * }
+ */
+ function makeDepndencyGraph(fullNameList) {
+ var graph = {};
+ var noEntryList = [];
+
+ zrUtil.each(fullNameList, function (name) {
+
+ var thisItem = createDependencyGraphItem(graph, name);
+ var originalDeps = thisItem.originalDeps = dependencyGetter(name);
+
+ var availableDeps = getAvailableDependencies(originalDeps, fullNameList);
+ thisItem.entryCount = availableDeps.length;
+ if (thisItem.entryCount === 0) {
+ noEntryList.push(name);
+ }
+
+ zrUtil.each(availableDeps, function (dependentName) {
+ if (zrUtil.indexOf(thisItem.predecessor, dependentName) < 0) {
+ thisItem.predecessor.push(dependentName);
+ }
+ var thatItem = createDependencyGraphItem(graph, dependentName);
+ if (zrUtil.indexOf(thatItem.successor, dependentName) < 0) {
+ thatItem.successor.push(name);
+ }
+ });
+ });
+
+ return {graph: graph, noEntryList: noEntryList};
+ }
+
+ function createDependencyGraphItem(graph, name) {
+ if (!graph[name]) {
+ graph[name] = {predecessor: [], successor: []};
+ }
+ return graph[name];
+ }
+
+ function getAvailableDependencies(originalDeps, fullNameList) {
+ var availableDeps = [];
+ zrUtil.each(originalDeps, function (dep) {
+ zrUtil.indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);
+ });
+ return availableDeps;
+ }
+ };
+
+ module.exports = componentUtil;
+
+
+/***/ },
+/* 71 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ // Layout helpers for each component positioning
+
+
+ var zrUtil = __webpack_require__(4);
+ var BoundingRect = __webpack_require__(9);
+ var numberUtil = __webpack_require__(7);
+ var formatUtil = __webpack_require__(6);
+ var parsePercent = numberUtil.parsePercent;
+ var each = zrUtil.each;
+
+ var layout = {};
+
+ /**
+ * @public
+ */
+ var LOCATION_PARAMS = layout.LOCATION_PARAMS = [
+ 'left', 'right', 'top', 'bottom', 'width', 'height'
+ ];
+
+ /**
+ * @public
+ */
+ var HV_NAMES = layout.HV_NAMES = [
+ ['width', 'left', 'right'],
+ ['height', 'top', 'bottom']
+ ];
+
+ function boxLayout(orient, group, gap, maxWidth, maxHeight) {
+ var x = 0;
+ var y = 0;
+ if (maxWidth == null) {
+ maxWidth = Infinity;
+ }
+ if (maxHeight == null) {
+ maxHeight = Infinity;
+ }
+ var currentLineMaxSize = 0;
+ group.eachChild(function (child, idx) {
+ var position = child.position;
+ var rect = child.getBoundingRect();
+ var nextChild = group.childAt(idx + 1);
+ var nextChildRect = nextChild && nextChild.getBoundingRect();
+ var nextX;
+ var nextY;
+ if (orient === 'horizontal') {
+ var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);
+ nextX = x + moveX;
+ // Wrap when width exceeds maxWidth or meet a `newline` group
+ if (nextX > maxWidth || child.newline) {
+ x = 0;
+ nextX = moveX;
+ y += currentLineMaxSize + gap;
+ currentLineMaxSize = rect.height;
+ }
+ else {
+ currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
+ }
+ }
+ else {
+ var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);
+ nextY = y + moveY;
+ // Wrap when width exceeds maxHeight or meet a `newline` group
+ if (nextY > maxHeight || child.newline) {
+ x += currentLineMaxSize + gap;
+ y = 0;
+ nextY = moveY;
+ currentLineMaxSize = rect.width;
+ }
+ else {
+ currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
+ }
+ }
+
+ if (child.newline) {
+ return;
+ }
+
+ position[0] = x;
+ position[1] = y;
+
+ orient === 'horizontal'
+ ? (x = nextX + gap)
+ : (y = nextY + gap);
+ });
+ }
+
+ /**
+ * VBox or HBox layouting
+ * @param {string} orient
+ * @param {module:zrender/container/Group} group
+ * @param {number} gap
+ * @param {number} [width=Infinity]
+ * @param {number} [height=Infinity]
+ */
+ layout.box = boxLayout;
+
+ /**
+ * VBox layouting
+ * @param {module:zrender/container/Group} group
+ * @param {number} gap
+ * @param {number} [width=Infinity]
+ * @param {number} [height=Infinity]
+ */
+ layout.vbox = zrUtil.curry(boxLayout, 'vertical');
+
+ /**
+ * HBox layouting
+ * @param {module:zrender/container/Group} group
+ * @param {number} gap
+ * @param {number} [width=Infinity]
+ * @param {number} [height=Infinity]
+ */
+ layout.hbox = zrUtil.curry(boxLayout, 'horizontal');
+
+ /**
+ * If x or x2 is not specified or 'center' 'left' 'right',
+ * the width would be as long as possible.
+ * If y or y2 is not specified or 'middle' 'top' 'bottom',
+ * the height would be as long as possible.
+ *
+ * @param {Object} positionInfo
+ * @param {number|string} [positionInfo.x]
+ * @param {number|string} [positionInfo.y]
+ * @param {number|string} [positionInfo.x2]
+ * @param {number|string} [positionInfo.y2]
+ * @param {Object} containerRect
+ * @param {string|number} margin
+ * @return {Object} {width, height}
+ */
+ layout.getAvailableSize = function (positionInfo, containerRect, margin) {
+ var containerWidth = containerRect.width;
+ var containerHeight = containerRect.height;
+
+ var x = parsePercent(positionInfo.x, containerWidth);
+ var y = parsePercent(positionInfo.y, containerHeight);
+ var x2 = parsePercent(positionInfo.x2, containerWidth);
+ var y2 = parsePercent(positionInfo.y2, containerHeight);
+
+ (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0);
+ (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth);
+ (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0);
+ (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight);
+
+ margin = formatUtil.normalizeCssArray(margin || 0);
+
+ return {
+ width: Math.max(x2 - x - margin[1] - margin[3], 0),
+ height: Math.max(y2 - y - margin[0] - margin[2], 0)
+ };
+ };
+
+ /**
+ * Parse position info.
+ *
+ * @param {Object} positionInfo
+ * @param {number|string} [positionInfo.left]
+ * @param {number|string} [positionInfo.top]
+ * @param {number|string} [positionInfo.right]
+ * @param {number|string} [positionInfo.bottom]
+ * @param {number|string} [positionInfo.width]
+ * @param {number|string} [positionInfo.height]
+ * @param {number|string} [positionInfo.aspect] Aspect is width / height
+ * @param {Object} containerRect
+ * @param {string|number} [margin]
+ *
+ * @return {module:zrender/core/BoundingRect}
+ */
+ layout.getLayoutRect = function (
+ positionInfo, containerRect, margin
+ ) {
+ margin = formatUtil.normalizeCssArray(margin || 0);
+
+ var containerWidth = containerRect.width;
+ var containerHeight = containerRect.height;
+
+ var left = parsePercent(positionInfo.left, containerWidth);
+ var top = parsePercent(positionInfo.top, containerHeight);
+ var right = parsePercent(positionInfo.right, containerWidth);
+ var bottom = parsePercent(positionInfo.bottom, containerHeight);
+ var width = parsePercent(positionInfo.width, containerWidth);
+ var height = parsePercent(positionInfo.height, containerHeight);
+
+ var verticalMargin = margin[2] + margin[0];
+ var horizontalMargin = margin[1] + margin[3];
+ var aspect = positionInfo.aspect;
+
+ // If width is not specified, calculate width from left and right
+ if (isNaN(width)) {
+ width = containerWidth - right - horizontalMargin - left;
+ }
+ if (isNaN(height)) {
+ height = containerHeight - bottom - verticalMargin - top;
+ }
+
+ // If width and height are not given
+ // 1. Graph should not exceeds the container
+ // 2. Aspect must be keeped
+ // 3. Graph should take the space as more as possible
+ if (isNaN(width) && isNaN(height)) {
+ if (aspect > containerWidth / containerHeight) {
+ width = containerWidth * 0.8;
+ }
+ else {
+ height = containerHeight * 0.8;
+ }
+ }
+
+ if (aspect != null) {
+ // Calculate width or height with given aspect
+ if (isNaN(width)) {
+ width = aspect * height;
+ }
+ if (isNaN(height)) {
+ height = width / aspect;
+ }
+ }
+
+ // If left is not specified, calculate left from right and width
+ if (isNaN(left)) {
+ left = containerWidth - right - width - horizontalMargin;
+ }
+ if (isNaN(top)) {
+ top = containerHeight - bottom - height - verticalMargin;
+ }
+
+ // Align left and top
+ switch (positionInfo.left || positionInfo.right) {
+ case 'center':
+ left = containerWidth / 2 - width / 2 - margin[3];
+ break;
+ case 'right':
+ left = containerWidth - width - horizontalMargin;
+ break;
+ }
+ switch (positionInfo.top || positionInfo.bottom) {
+ case 'middle':
+ case 'center':
+ top = containerHeight / 2 - height / 2 - margin[0];
+ break;
+ case 'bottom':
+ top = containerHeight - height - verticalMargin;
+ break;
+ }
+ // If something is wrong and left, top, width, height are calculated as NaN
+ left = left || 0;
+ top = top || 0;
+ if (isNaN(width)) {
+ // Width may be NaN if only one value is given except width
+ width = containerWidth - left - (right || 0);
+ }
+ if (isNaN(height)) {
+ // Height may be NaN if only one value is given except height
+ height = containerHeight - top - (bottom || 0);
+ }
+
+ var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);
+ rect.margin = margin;
+ return rect;
+ };
+
+
+ /**
+ * Position a zr element in viewport
+ * Group position is specified by either
+ * {left, top}, {right, bottom}
+ * If all properties exists, right and bottom will be igonred.
+ *
+ * Logic:
+ * 1. Scale (against origin point in parent coord)
+ * 2. Rotate (against origin point in parent coord)
+ * 3. Traslate (with el.position by this method)
+ * So this method only fixes the last step 'Traslate', which does not affect
+ * scaling and rotating.
+ *
+ * If be called repeatly with the same input el, the same result will be gotten.
+ *
+ * @param {module:zrender/Element} el Should have `getBoundingRect` method.
+ * @param {Object} positionInfo
+ * @param {number|string} [positionInfo.left]
+ * @param {number|string} [positionInfo.top]
+ * @param {number|string} [positionInfo.right]
+ * @param {number|string} [positionInfo.bottom]
+ * @param {Object} containerRect
+ * @param {string|number} margin
+ * @param {Object} [opt]
+ * @param {Array.} [opt.hv=[1,1]] Only horizontal or only vertical.
+ * @param {Array.} [opt.boundingMode='all']
+ * Specify how to calculate boundingRect when locating.
+ * 'all': Position the boundingRect that is transformed and uioned
+ * both itself and its descendants.
+ * This mode simplies confine the elements in the bounding
+ * of their container (e.g., using 'right: 0').
+ * 'raw': Position the boundingRect that is not transformed and only itself.
+ * This mode is useful when you want a element can overflow its
+ * container. (Consider a rotated circle needs to be located in a corner.)
+ * In this mode positionInfo.width/height can only be number.
+ */
+ layout.positionElement = function (el, positionInfo, containerRect, margin, opt) {
+ var h = !opt || !opt.hv || opt.hv[0];
+ var v = !opt || !opt.hv || opt.hv[1];
+ var boundingMode = opt && opt.boundingMode || 'all';
+
+ if (!h && !v) {
+ return;
+ }
+
+ var rect;
+ if (boundingMode === 'raw') {
+ rect = el.type === 'group'
+ ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)
+ : el.getBoundingRect();
+ }
+ else {
+ rect = el.getBoundingRect();
+ if (el.needLocalTransform()) {
+ var transform = el.getLocalTransform();
+ // Notice: raw rect may be inner object of el,
+ // which should not be modified.
+ rect = rect.clone();
+ rect.applyTransform(transform);
+ }
+ }
+
+ positionInfo = layout.getLayoutRect(
+ zrUtil.defaults(
+ {width: rect.width, height: rect.height},
+ positionInfo
+ ),
+ containerRect,
+ margin
+ );
+
+ // Because 'tranlate' is the last step in transform
+ // (see zrender/core/Transformable#getLocalTransfrom),
+ // we can just only modify el.position to get final result.
+ var elPos = el.position;
+ var dx = h ? positionInfo.x - rect.x : 0;
+ var dy = v ? positionInfo.y - rect.y : 0;
+
+ el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);
+ };
+
+ /**
+ * @param {Object} option Contains some of the properties in HV_NAMES.
+ * @param {number} hvIdx 0: horizontal; 1: vertical.
+ */
+ layout.sizeCalculable = function (option, hvIdx) {
+ return option[HV_NAMES[hvIdx][0]] != null
+ || (option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null);
+ };
+
+ /**
+ * Consider Case:
+ * When defulat option has {left: 0, width: 100}, and we set {right: 0}
+ * through setOption or media query, using normal zrUtil.merge will cause
+ * {right: 0} does not take effect.
+ *
+ * @example
+ * ComponentModel.extend({
+ * init: function () {
+ * ...
+ * var inputPositionParams = layout.getLayoutParams(option);
+ * this.mergeOption(inputPositionParams);
+ * },
+ * mergeOption: function (newOption) {
+ * newOption && zrUtil.merge(thisOption, newOption, true);
+ * layout.mergeLayoutParam(thisOption, newOption);
+ * }
+ * });
+ *
+ * @param {Object} targetOption
+ * @param {Object} newOption
+ * @param {Object|string} [opt]
+ * @param {boolean|Array.} [opt.ignoreSize=false] Some component must has width and height.
+ */
+ layout.mergeLayoutParam = function (targetOption, newOption, opt) {
+ !zrUtil.isObject(opt) && (opt = {});
+
+ var ignoreSize = opt.ignoreSize;
+ !zrUtil.isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);
+
+ var hResult = merge(HV_NAMES[0], 0);
+ var vResult = merge(HV_NAMES[1], 1);
+
+ copy(HV_NAMES[0], targetOption, hResult);
+ copy(HV_NAMES[1], targetOption, vResult);
+
+ function merge(names, hvIdx) {
+ var newParams = {};
+ var newValueCount = 0;
+ var merged = {};
+ var mergedValueCount = 0;
+ var enoughParamNumber = 2;
+
+ each(names, function (name) {
+ merged[name] = targetOption[name];
+ });
+ each(names, function (name) {
+ // Consider case: newOption.width is null, which is
+ // set by user for removing width setting.
+ hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
+ hasValue(newParams, name) && newValueCount++;
+ hasValue(merged, name) && mergedValueCount++;
+ });
+
+ if (ignoreSize[hvIdx]) {
+ // Only one of left/right is premitted to exist.
+ if (hasValue(newOption, names[1])) {
+ merged[names[2]] = null;
+ }
+ else if (hasValue(newOption, names[2])) {
+ merged[names[1]] = null;
+ }
+ return merged;
+ }
+
+ // Case: newOption: {width: ..., right: ...},
+ // or targetOption: {right: ...} and newOption: {width: ...},
+ // There is no conflict when merged only has params count
+ // little than enoughParamNumber.
+ if (mergedValueCount === enoughParamNumber || !newValueCount) {
+ return merged;
+ }
+ // Case: newOption: {width: ..., right: ...},
+ // Than we can make sure user only want those two, and ignore
+ // all origin params in targetOption.
+ else if (newValueCount >= enoughParamNumber) {
+ return newParams;
+ }
+ else {
+ // Chose another param from targetOption by priority.
+ for (var i = 0; i < names.length; i++) {
+ var name = names[i];
+ if (!hasProp(newParams, name) && hasProp(targetOption, name)) {
+ newParams[name] = targetOption[name];
+ break;
+ }
+ }
+ return newParams;
+ }
+ }
+
+ function hasProp(obj, name) {
+ return obj.hasOwnProperty(name);
+ }
+
+ function hasValue(obj, name) {
+ return obj[name] != null && obj[name] !== 'auto';
+ }
+
+ function copy(names, target, source) {
+ each(names, function (name) {
+ target[name] = source[name];
+ });
+ }
+ };
+
+ /**
+ * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
+ * @param {Object} source
+ * @return {Object} Result contains those props.
+ */
+ layout.getLayoutParams = function (source) {
+ return layout.copyLayoutParams({}, source);
+ };
+
+ /**
+ * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
+ * @param {Object} source
+ * @return {Object} Result contains those props.
+ */
+ layout.copyLayoutParams = function (target, source) {
+ source && target && each(LOCATION_PARAMS, function (name) {
+ source.hasOwnProperty(name) && (target[name] = source[name]);
+ });
+ return target;
+ };
+
+ module.exports = layout;
+
+
+
+/***/ },
+/* 72 */
+/***/ function(module, exports) {
+
+
+
+ module.exports = {
+ getBoxLayoutParams: function () {
+ return {
+ left: this.get('left'),
+ top: this.get('top'),
+ right: this.get('right'),
+ bottom: this.get('bottom'),
+ width: this.get('width'),
+ height: this.get('height')
+ };
+ }
+ };
+
+
+/***/ },
+/* 73 */
+/***/ function(module, exports) {
+
+
+ var platform = '';
+ // Navigator not exists in node
+ if (typeof navigator !== 'undefined') {
+ platform = navigator.platform || '';
+ }
+ module.exports = {
+ // 全图默认背景
+ // backgroundColor: 'rgba(0,0,0,0)',
+
+ // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization
+ // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],
+ // 浅色
+ // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],
+ // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],
+ // 深色
+ color: ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3'],
+
+ // 默认需要 Grid 配置项
+ // grid: {},
+ // 主题,主题
+ textStyle: {
+ // color: '#000',
+ // decoration: 'none',
+ // PENDING
+ fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',
+ // fontFamily: 'Arial, Verdana, sans-serif',
+ fontSize: 12,
+ fontStyle: 'normal',
+ fontWeight: 'normal'
+ },
+
+ // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/
+ // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
+ // Default is source-over
+ blendMode: null,
+
+ animation: 'auto',
+ animationDuration: 1000,
+ animationDurationUpdate: 300,
+ animationEasing: 'exponentialOut',
+ animationEasingUpdate: 'cubicOut',
+
+ animationThreshold: 2000,
+ // Configuration for progressive/incremental rendering
+ progressiveThreshold: 3000,
+ progressive: 400,
+
+ // Threshold of if use single hover layer to optimize.
+ // It is recommended that `hoverLayerThreshold` is equivalent to or less than
+ // `progressiveThreshold`, otherwise hover will cause restart of progressive,
+ // which is unexpected.
+ // see example .
+ hoverLayerThreshold: 3000,
+
+ // See: module:echarts/scale/Time
+ useUTC: false
+ };
+
+
+/***/ },
+/* 74 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var classUtil = __webpack_require__(13);
+ var set = classUtil.set;
+ var get = classUtil.get;
+
+ module.exports = {
+ clearColorPalette: function () {
+ set(this, 'colorIdx', 0);
+ set(this, 'colorNameMap', {});
+ },
+
+ getColorFromPalette: function (name, scope) {
+ scope = scope || this;
+ var colorIdx = get(scope, 'colorIdx') || 0;
+ var colorNameMap = get(scope, 'colorNameMap') || set(scope, 'colorNameMap', {});
+ // Use `hasOwnProperty` to avoid conflict with Object.prototype.
+ if (colorNameMap.hasOwnProperty(name)) {
+ return colorNameMap[name];
+ }
+ var colorPalette = this.get('color', true) || [];
+ if (!colorPalette.length) {
+ return;
+ }
+
+ var color = colorPalette[colorIdx];
+ if (name) {
+ colorNameMap[name] = color;
+ }
+ set(scope, 'colorIdx', (colorIdx + 1) % colorPalette.length);
+
+ return color;
+ }
+ };
+
+
+/***/ },
+/* 75 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var echartsAPIList = [
+ 'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',
+ 'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',
+ 'getViewOfComponentModel', 'getViewOfSeriesModel'
+ ];
+ // And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js
+
+ function ExtensionAPI(chartInstance) {
+ zrUtil.each(echartsAPIList, function (name) {
+ this[name] = zrUtil.bind(chartInstance[name], chartInstance);
+ }, this);
+ }
+
+ module.exports = ExtensionAPI;
+
+
+/***/ },
+/* 76 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var coordinateSystemCreators = {};
+
+ function CoordinateSystemManager() {
+
+ this._coordinateSystems = [];
+ }
+
+ CoordinateSystemManager.prototype = {
+
+ constructor: CoordinateSystemManager,
+
+ create: function (ecModel, api) {
+ var coordinateSystems = [];
+ zrUtil.each(coordinateSystemCreators, function (creater, type) {
+ var list = creater.create(ecModel, api);
+ coordinateSystems = coordinateSystems.concat(list || []);
+ });
+
+ this._coordinateSystems = coordinateSystems;
+ },
+
+ update: function (ecModel, api) {
+ zrUtil.each(this._coordinateSystems, function (coordSys) {
+ // FIXME MUST have
+ coordSys.update && coordSys.update(ecModel, api);
+ });
+ },
+
+ getCoordinateSystems: function () {
+ return this._coordinateSystems.slice();
+ }
+ };
+
+ CoordinateSystemManager.register = function (type, coordinateSystemCreator) {
+ coordinateSystemCreators[type] = coordinateSystemCreator;
+ };
+
+ CoordinateSystemManager.get = function (type) {
+ return coordinateSystemCreators[type];
+ };
+
+ module.exports = CoordinateSystemManager;
+
+
+/***/ },
+/* 77 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * ECharts option manager
+ *
+ * @module {echarts/model/OptionManager}
+ */
+
+
+
+ var zrUtil = __webpack_require__(4);
+ var modelUtil = __webpack_require__(5);
+ var ComponentModel = __webpack_require__(69);
+ var each = zrUtil.each;
+ var clone = zrUtil.clone;
+ var map = zrUtil.map;
+ var merge = zrUtil.merge;
+
+ var QUERY_REG = /^(min|max)?(.+)$/;
+
+ /**
+ * TERM EXPLANATIONS:
+ *
+ * [option]:
+ *
+ * An object that contains definitions of components. For example:
+ * var option = {
+ * title: {...},
+ * legend: {...},
+ * visualMap: {...},
+ * series: [
+ * {data: [...]},
+ * {data: [...]},
+ * ...
+ * ]
+ * };
+ *
+ * [rawOption]:
+ *
+ * An object input to echarts.setOption. 'rawOption' may be an
+ * 'option', or may be an object contains multi-options. For example:
+ * var option = {
+ * baseOption: {
+ * title: {...},
+ * legend: {...},
+ * series: [
+ * {data: [...]},
+ * {data: [...]},
+ * ...
+ * ]
+ * },
+ * timeline: {...},
+ * options: [
+ * {title: {...}, series: {data: [...]}},
+ * {title: {...}, series: {data: [...]}},
+ * ...
+ * ],
+ * media: [
+ * {
+ * query: {maxWidth: 320},
+ * option: {series: {x: 20}, visualMap: {show: false}}
+ * },
+ * {
+ * query: {minWidth: 320, maxWidth: 720},
+ * option: {series: {x: 500}, visualMap: {show: true}}
+ * },
+ * {
+ * option: {series: {x: 1200}, visualMap: {show: true}}
+ * }
+ * ]
+ * };
+ *
+ * @alias module:echarts/model/OptionManager
+ * @param {module:echarts/ExtensionAPI} api
+ */
+ function OptionManager(api) {
+
+ /**
+ * @private
+ * @type {module:echarts/ExtensionAPI}
+ */
+ this._api = api;
+
+ /**
+ * @private
+ * @type {Array.}
+ */
+ this._timelineOptions = [];
+
+ /**
+ * @private
+ * @type {Array.}
+ */
+ this._mediaList = [];
+
+ /**
+ * @private
+ * @type {Object}
+ */
+ this._mediaDefault;
+
+ /**
+ * -1, means default.
+ * empty means no media.
+ * @private
+ * @type {Array.}
+ */
+ this._currentMediaIndices = [];
+
+ /**
+ * @private
+ * @type {Object}
+ */
+ this._optionBackup;
+
+ /**
+ * @private
+ * @type {Object}
+ */
+ this._newBaseOption;
+ }
+
+ // timeline.notMerge is not supported in ec3. Firstly there is rearly
+ // case that notMerge is needed. Secondly supporting 'notMerge' requires
+ // rawOption cloned and backuped when timeline changed, which does no
+ // good to performance. What's more, that both timeline and setOption
+ // method supply 'notMerge' brings complex and some problems.
+ // Consider this case:
+ // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);
+ // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);
+
+ OptionManager.prototype = {
+
+ constructor: OptionManager,
+
+ /**
+ * @public
+ * @param {Object} rawOption Raw option.
+ * @param {module:echarts/model/Global} ecModel
+ * @param {Array.} optionPreprocessorFuncs
+ * @return {Object} Init option
+ */
+ setOption: function (rawOption, optionPreprocessorFuncs) {
+ rawOption = clone(rawOption, true);
+
+ // FIXME
+ // 如果 timeline options 或者 media 中设置了某个属性,而baseOption中没有设置,则进行警告。
+
+ var oldOptionBackup = this._optionBackup;
+ var newParsedOption = parseRawOption.call(
+ this, rawOption, optionPreprocessorFuncs, !oldOptionBackup
+ );
+ this._newBaseOption = newParsedOption.baseOption;
+
+ // For setOption at second time (using merge mode);
+ if (oldOptionBackup) {
+ // Only baseOption can be merged.
+ //**yuki**changed Only series shouldn't be merged.
+ //Here is the first step, ensure that oldOptionBackup doesn't hava series.
+ oldOptionBackup.baseOption.series=[];
+ //**yuki**changed Over.
+ mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);
+
+ // For simplicity, timeline options and media options do not support merge,
+ // that is, if you `setOption` twice and both has timeline options, the latter
+ // timeline opitons will not be merged to the formers, but just substitude them.
+ if (newParsedOption.timelineOptions.length) {
+ oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;
+ }
+ if (newParsedOption.mediaList.length) {
+ oldOptionBackup.mediaList = newParsedOption.mediaList;
+ }
+ if (newParsedOption.mediaDefault) {
+ oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;
+ }
+ }
+ else {
+ this._optionBackup = newParsedOption;
+ }
+ },
+
+ /**
+ * @param {boolean} isRecreate
+ * @return {Object}
+ */
+ mountOption: function (isRecreate) {
+ var optionBackup = this._optionBackup;
+
+ // TODO
+ // 如果没有reset功能则不clone。
+
+ this._timelineOptions = map(optionBackup.timelineOptions, clone);
+ this._mediaList = map(optionBackup.mediaList, clone);
+ this._mediaDefault = clone(optionBackup.mediaDefault);
+ this._currentMediaIndices = [];
+
+ return clone(isRecreate
+ // this._optionBackup.baseOption, which is created at the first `setOption`
+ // called, and is merged into every new option by inner method `mergeOption`
+ // each time `setOption` called, can be only used in `isRecreate`, because
+ // its reliability is under suspicion. In other cases option merge is
+ // performed by `model.mergeOption`.
+ ? optionBackup.baseOption : this._newBaseOption
+ );
+ },
+
+ /**
+ * @param {module:echarts/model/Global} ecModel
+ * @return {Object}
+ */
+ getTimelineOption: function (ecModel) {
+ var option;
+ var timelineOptions = this._timelineOptions;
+
+ if (timelineOptions.length) {
+ // getTimelineOption can only be called after ecModel inited,
+ // so we can get currentIndex from timelineModel.
+ var timelineModel = ecModel.getComponent('timeline');
+ if (timelineModel) {
+ option = clone(
+ timelineOptions[timelineModel.getCurrentIndex()],
+ true
+ );
+ }
+ }
+
+ return option;
+ },
+
+ /**
+ * @param {module:echarts/model/Global} ecModel
+ * @return {Array.}
+ */
+ getMediaOption: function (ecModel) {
+ var ecWidth = this._api.getWidth();
+ var ecHeight = this._api.getHeight();
+ var mediaList = this._mediaList;
+ var mediaDefault = this._mediaDefault;
+ var indices = [];
+ var result = [];
+
+ // No media defined.
+ if (!mediaList.length && !mediaDefault) {
+ return result;
+ }
+
+ // Multi media may be applied, the latter defined media has higher priority.
+ for (var i = 0, len = mediaList.length; i < len; i++) {
+ if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {
+ indices.push(i);
+ }
+ }
+
+ // FIXME
+ // 是否mediaDefault应该强制用户设置,否则可能修改不能回归。
+ if (!indices.length && mediaDefault) {
+ indices = [-1];
+ }
+
+ if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {
+ result = map(indices, function (index) {
+ return clone(
+ index === -1 ? mediaDefault.option : mediaList[index].option
+ );
+ });
+ }
+ // Otherwise return nothing.
+
+ this._currentMediaIndices = indices;
+
+ return result;
+ }
+ };
+
+ function parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {
+ var timelineOptions = [];
+ var mediaList = [];
+ var mediaDefault;
+ var baseOption;
+
+ // Compatible with ec2.
+ var timelineOpt = rawOption.timeline;
+
+ if (rawOption.baseOption) {
+ baseOption = rawOption.baseOption;
+ }
+
+ // For timeline
+ if (timelineOpt || rawOption.options) {
+ baseOption = baseOption || {};
+ timelineOptions = (rawOption.options || []).slice();
+ }
+
+ // For media query
+ if (rawOption.media) {
+ baseOption = baseOption || {};
+ var media = rawOption.media;
+ each(media, function (singleMedia) {
+ if (singleMedia && singleMedia.option) {
+ if (singleMedia.query) {
+ mediaList.push(singleMedia);
+ }
+ else if (!mediaDefault) {
+ // Use the first media default.
+ mediaDefault = singleMedia;
+ }
+ }
+ });
+ }
+
+ // For normal option
+ if (!baseOption) {
+ baseOption = rawOption;
+ }
+
+ // Set timelineOpt to baseOption in ec3,
+ // which is convenient for merge option.
+ if (!baseOption.timeline) {
+ baseOption.timeline = timelineOpt;
+ }
+
+ // Preprocess.
+ each([baseOption].concat(timelineOptions)
+ .concat(zrUtil.map(mediaList, function (media) {
+ return media.option;
+ })),
+ function (option) {
+ each(optionPreprocessorFuncs, function (preProcess) {
+ preProcess(option, isNew);
+ });
+ }
+ );
+
+ return {
+ baseOption: baseOption,
+ timelineOptions: timelineOptions,
+ mediaDefault: mediaDefault,
+ mediaList: mediaList
+ };
+ }
+
+ /**
+ * @see
+ * Support: width, height, aspectRatio
+ * Can use max or min as prefix.
+ */
+ function applyMediaQuery(query, ecWidth, ecHeight) {
+ var realMap = {
+ width: ecWidth,
+ height: ecHeight,
+ aspectratio: ecWidth / ecHeight // lowser case for convenientce.
+ };
+
+ var applicatable = true;
+
+ zrUtil.each(query, function (value, attr) {
+ var matched = attr.match(QUERY_REG);
+
+ if (!matched || !matched[1] || !matched[2]) {
+ return;
+ }
+
+ var operator = matched[1];
+ var realAttr = matched[2].toLowerCase();
+
+ if (!compare(realMap[realAttr], value, operator)) {
+ applicatable = false;
+ }
+ });
+
+ return applicatable;
+ }
+
+ function compare(real, expect, operator) {
+ if (operator === 'min') {
+ return real >= expect;
+ }
+ else if (operator === 'max') {
+ return real <= expect;
+ }
+ else { // Equals
+ return real === expect;
+ }
+ }
+
+ function indicesEquals(indices1, indices2) {
+ // indices is always order by asc and has only finite number.
+ return indices1.join(',') === indices2.join(',');
+ }
+
+ /**
+ * Consider case:
+ * `chart.setOption(opt1);`
+ * Then user do some interaction like dataZoom, dataView changing.
+ * `chart.setOption(opt2);`
+ * Then user press 'reset button' in toolbox.
+ *
+ * After doing that all of the interaction effects should be reset, the
+ * chart should be the same as the result of invoke
+ * `chart.setOption(opt1); chart.setOption(opt2);`.
+ *
+ * Although it is not able ensure that
+ * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to
+ * `chart.setOption(merge(opt1, opt2));` exactly,
+ * this might be the only simple way to implement that feature.
+ *
+ * MEMO: We've considered some other approaches:
+ * 1. Each model handle its self restoration but not uniform treatment.
+ * (Too complex in logic and error-prone)
+ * 2. Use a shadow ecModel. (Performace expensive)
+ */
+
+ function mergeOption(oldOption, newOption) {
+ newOption = newOption || {};
+
+ each(newOption, function (newCptOpt, mainType) {
+ if (newCptOpt == null) {
+ return;
+ }
+
+ var oldCptOpt = oldOption[mainType];
+
+ if (!ComponentModel.hasClass(mainType)) {
+ oldOption[mainType] = merge(oldCptOpt, newCptOpt, true);
+ }
+ else {
+ newCptOpt = modelUtil.normalizeToArray(newCptOpt);
+ oldCptOpt = modelUtil.normalizeToArray(oldCptOpt);
+
+ var mapResult = modelUtil.mappingToExists(oldCptOpt, newCptOpt);
+
+ oldOption[mainType] = map(mapResult, function (item) {
+ return (item.option && item.exist)
+ ? merge(item.exist, item.option, true)
+ : (item.exist || item.option);
+ });
+ }
+ });
+ }
+
+ module.exports = OptionManager;
+
+
+/***/ },
+/* 78 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+
+ var zrUtil = __webpack_require__(4);
+ var formatUtil = __webpack_require__(6);
+ var classUtil = __webpack_require__(13);
+ var modelUtil = __webpack_require__(5);
+ var ComponentModel = __webpack_require__(69);
+ var colorPaletteMixin = __webpack_require__(74);
+ var env = __webpack_require__(2);
+ var layout = __webpack_require__(71);
+
+ var set = classUtil.set;
+ var get = classUtil.get;
+ var encodeHTML = formatUtil.encodeHTML;
+ var addCommas = formatUtil.addCommas;
+
+ var SeriesModel = ComponentModel.extend({
+
+ type: 'series.__base__',
+
+ /**
+ * @readOnly
+ */
+ seriesIndex: 0,
+
+ // coodinateSystem will be injected in the echarts/CoordinateSystem
+ coordinateSystem: null,
+
+ /**
+ * @type {Object}
+ * @protected
+ */
+ defaultOption: null,
+
+ /**
+ * Data provided for legend
+ * @type {Function}
+ */
+ // PENDING
+ legendDataProvider: null,
+
+ /**
+ * Access path of color for visual
+ */
+ visualColorAccessPath: 'itemStyle.normal.color',
+
+ /**
+ * Support merge layout params.
+ * Only support 'box' now (left/right/top/bottom/width/height).
+ * @type {string|Object} Object can be {ignoreSize: true}
+ * @readOnly
+ */
+ layoutMode: null,
+
+ init: function (option, parentModel, ecModel, extraOpt) {
+
+ /**
+ * @type {number}
+ * @readOnly
+ */
+ this.seriesIndex = this.componentIndex;
+
+ this.mergeDefaultAndTheme(option, ecModel);
+
+ var data = this.getInitialData(option, ecModel);
+ if (true) {
+ zrUtil.assert(data, 'getInitialData returned invalid data.');
+ }
+ /**
+ * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}
+ * @private
+ */
+ set(this, 'dataBeforeProcessed', data);
+
+ // If we reverse the order (make data firstly, and then make
+ // dataBeforeProcessed by cloneShallow), cloneShallow will
+ // cause data.graph.data !== data when using
+ // module:echarts/data/Graph or module:echarts/data/Tree.
+ // See module:echarts/data/helper/linkList
+ this.restoreData();
+ },
+
+ /**
+ * Util for merge default and theme to option
+ * @param {Object} option
+ * @param {module:echarts/model/Global} ecModel
+ */
+ mergeDefaultAndTheme: function (option, ecModel) {
+ var layoutMode = this.layoutMode;
+ var inputPositionParams = layoutMode
+ ? layout.getLayoutParams(option) : {};
+
+ zrUtil.merge(
+ option,
+ ecModel.getTheme().get(this.subType)
+ );
+ zrUtil.merge(option, this.getDefaultOption());
+
+ // Default label emphasis `position` and `show`
+ // FIXME Set label in mergeOption
+ modelUtil.defaultEmphasis(option.label, modelUtil.LABEL_OPTIONS);
+
+ this.fillDataTextStyle(option.data);
+
+ if (layoutMode) {
+ layout.mergeLayoutParam(option, inputPositionParams, layoutMode);
+ }
+ },
+
+ mergeOption: function (newSeriesOption, ecModel) {
+ newSeriesOption = zrUtil.merge(this.option, newSeriesOption, true);
+ this.fillDataTextStyle(newSeriesOption.data);
+
+ var layoutMode = this.layoutMode;
+ if (layoutMode) {
+ layout.mergeLayoutParam(this.option, newSeriesOption, layoutMode);
+ }
+
+ var data = this.getInitialData(newSeriesOption, ecModel);
+ // TODO Merge data?
+ if (data) {
+ set(this, 'data', data);
+ set(this, 'dataBeforeProcessed', data.cloneShallow());
+ }
+ },
+
+ fillDataTextStyle: function (data) {
+ // Default data label emphasis `position` and `show`
+ // FIXME Tree structure data ?
+ // FIXME Performance ?
+ if (data) {
+ for (var i = 0; i < data.length; i++) {
+ if (data[i] && data[i].label) {
+ modelUtil.defaultEmphasis(data[i].label, modelUtil.LABEL_OPTIONS);
+ }
+ }
+ }
+ },
+
+ /**
+ * Init a data structure from data related option in series
+ * Must be overwritten
+ */
+ getInitialData: function () {},
+
+ /**
+ * @param {string} [dataType]
+ * @return {module:echarts/data/List}
+ */
+ getData: function (dataType) {
+ var data = get(this, 'data');
+ return dataType == null ? data : data.getLinkedData(dataType);
+ },
+
+ /**
+ * @param {module:echarts/data/List} data
+ */
+ setData: function (data) {
+ set(this, 'data', data);
+ },
+
+ /**
+ * Get data before processed
+ * @return {module:echarts/data/List}
+ */
+ getRawData: function () {
+ return get(this, 'dataBeforeProcessed');
+ },
+
+ /**
+ * Coord dimension to data dimension.
+ *
+ * By default the result is the same as dimensions of series data.
+ * But in some series data dimensions are different from coord dimensions (i.e.
+ * candlestick and boxplot). Override this method to handle those cases.
+ *
+ * Coord dimension to data dimension can be one-to-many
+ *
+ * @param {string} coordDim
+ * @return {Array.} dimensions on the axis.
+ */
+ coordDimToDataDim: function (coordDim) {
+ return modelUtil.coordDimToDataDim(this.getData(), coordDim);
+ },
+
+ /**
+ * Convert data dimension to coord dimension.
+ *
+ * @param {string|number} dataDim
+ * @return {string}
+ */
+ dataDimToCoordDim: function (dataDim) {
+ return modelUtil.dataDimToCoordDim(this.getData(), dataDim);
+ },
+
+ /**
+ * Get base axis if has coordinate system and has axis.
+ * By default use coordSys.getBaseAxis();
+ * Can be overrided for some chart.
+ * @return {type} description
+ */
+ getBaseAxis: function () {
+ var coordSys = this.coordinateSystem;
+ return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
+ },
+
+ // FIXME
+ /**
+ * Default tooltip formatter
+ *
+ * @param {number} dataIndex
+ * @param {boolean} [multipleSeries=false]
+ * @param {number} [dataType]
+ */
+ formatTooltip: function (dataIndex, multipleSeries, dataType) {
+ function formatArrayValue(value) {
+ var vertially = zrUtil.reduce(value, function (vertially, val, idx) {
+ var dimItem = data.getDimensionInfo(idx);
+ return vertially |= dimItem && dimItem.tooltip !== false && dimItem.tooltipName != null;
+ }, 0);
+
+ var result = [];
+ var tooltipDims = modelUtil.otherDimToDataDim(data, 'tooltip');
+
+ tooltipDims.length
+ ? zrUtil.each(tooltipDims, function (dimIdx) {
+ setEachItem(data.get(dimIdx, dataIndex), dimIdx);
+ })
+ // By default, all dims is used on tooltip.
+ : zrUtil.each(value, setEachItem);
+
+ function setEachItem(val, dimIdx) {
+ var dimInfo = data.getDimensionInfo(dimIdx);
+ // If `dimInfo.tooltip` is not set, show tooltip.
+ if (!dimInfo || dimInfo.otherDims.tooltip === false) {
+ return;
+ }
+ var dimType = dimInfo.type;
+ var valStr = (vertially ? '- ' + (dimInfo.tooltipName || dimInfo.name) + ': ' : '')
+ + (dimType === 'ordinal'
+ ? val + ''
+ : dimType === 'time'
+ ? (multipleSeries ? '' : formatUtil.formatTime('yyyy/MM/dd hh:mm:ss', val))
+ : addCommas(val)
+ );
+ valStr && result.push(encodeHTML(valStr));
+ }
+
+ return (vertially ? ' ' : '') + result.join(vertially ? ' ' : ', ');
+ }
+
+ var data = get(this, 'data');
+
+ var value = this.getRawValue(dataIndex);
+ var formattedValue = zrUtil.isArray(value)
+ ? formatArrayValue(value) : encodeHTML(addCommas(value));
+ var name = data.getName(dataIndex);
+
+ var color = data.getItemVisual(dataIndex, 'color');
+ if (zrUtil.isObject(color) && color.colorStops) {
+ color = (color.colorStops[0] || {}).color;
+ }
+ color = color || 'transparent';
+
+ var colorEl = formatUtil.getTooltipMarker(color);
+
+ var seriesName = this.name;
+ // FIXME
+ if (seriesName === '\0-') {
+ // Not show '-'
+ seriesName = '';
+ }
+ seriesName = seriesName
+ ? encodeHTML(seriesName) + (!multipleSeries ? ' ' : ': ')
+ : '';
+ return !multipleSeries
+ ? seriesName + colorEl
+ + (name
+ ? encodeHTML(name) + ': ' + formattedValue
+ : formattedValue
+ )
+ : colorEl + seriesName + formattedValue;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isAnimationEnabled: function () {
+ if (env.node) {
+ return false;
+ }
+
+ var animationEnabled = this.getShallow('animation');
+ if (animationEnabled) {
+ if (this.getData().count() > this.getShallow('animationThreshold')) {
+ animationEnabled = false;
+ }
+ }
+ return animationEnabled;
+ },
+
+ restoreData: function () {
+ set(this, 'data', get(this, 'dataBeforeProcessed').cloneShallow());
+ },
+
+ getColorFromPalette: function (name, scope) {
+ var ecModel = this.ecModel;
+ // PENDING
+ var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope);
+ if (!color) {
+ color = ecModel.getColorFromPalette(name, scope);
+ }
+ return color;
+ },
+
+ /**
+ * Get data indices for show tooltip content. See tooltip.
+ * @abstract
+ * @param {Array.|string} dim
+ * @param {Array.} value
+ * @param {module:echarts/coord/single/SingleAxis} baseAxis
+ * @return {Object} {dataIndices, nestestValue}.
+ */
+ getAxisTooltipData: null,
+
+ /**
+ * See tooltip.
+ * @abstract
+ * @param {number} dataIndex
+ * @return {Array.} Point of tooltip. null/undefined can be returned.
+ */
+ getTooltipPosition: null
+ });
+
+ zrUtil.mixin(SeriesModel, modelUtil.dataFormatMixin);
+ zrUtil.mixin(SeriesModel, colorPaletteMixin);
+
+ module.exports = SeriesModel;
+
+
+/***/ },
+/* 79 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var Group = __webpack_require__(48);
+ var componentUtil = __webpack_require__(70);
+ var clazzUtil = __webpack_require__(13);
+
+ var Component = function () {
+ /**
+ * @type {module:zrender/container/Group}
+ * @readOnly
+ */
+ this.group = new Group();
+
+ /**
+ * @type {string}
+ * @readOnly
+ */
+ this.uid = componentUtil.getUID('viewComponent');
+ };
+
+ Component.prototype = {
+
+ constructor: Component,
+
+ init: function (ecModel, api) {},
+
+ render: function (componentModel, ecModel, api, payload) {},
+
+ dispose: function () {}
+
+ };
+
+ var componentProto = Component.prototype;
+ componentProto.updateView
+ = componentProto.updateLayout
+ = componentProto.updateVisual
+ = function (seriesModel, ecModel, api, payload) {
+ // Do nothing;
+ };
+ // Enable Component.extend.
+ clazzUtil.enableClassExtend(Component);
+
+ // Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
+ clazzUtil.enableClassManagement(Component, {registerWhenExtend: true});
+
+ module.exports = Component;
+
+
+/***/ },
+/* 80 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var Group = __webpack_require__(48);
+ var componentUtil = __webpack_require__(70);
+ var clazzUtil = __webpack_require__(13);
+ var modelUtil = __webpack_require__(5);
+ var zrUtil = __webpack_require__(4);
+
+ function Chart() {
+
+ /**
+ * @type {module:zrender/container/Group}
+ * @readOnly
+ */
+ this.group = new Group();
+
+ /**
+ * @type {string}
+ * @readOnly
+ */
+ this.uid = componentUtil.getUID('viewChart');
+ }
+
+ Chart.prototype = {
+
+ type: 'chart',
+
+ /**
+ * Init the chart
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ */
+ init: function (ecModel, api) {},
+
+ /**
+ * Render the chart
+ * @param {module:echarts/model/Series} seriesModel
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ * @param {Object} payload
+ */
+ render: function (seriesModel, ecModel, api, payload) {},
+
+ /**
+ * Highlight series or specified data item
+ * @param {module:echarts/model/Series} seriesModel
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ * @param {Object} payload
+ */
+ highlight: function (seriesModel, ecModel, api, payload) {
+ toggleHighlight(seriesModel.getData(), payload, 'emphasis');
+ },
+
+ /**
+ * Downplay series or specified data item
+ * @param {module:echarts/model/Series} seriesModel
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ * @param {Object} payload
+ */
+ downplay: function (seriesModel, ecModel, api, payload) {
+ toggleHighlight(seriesModel.getData(), payload, 'normal');
+ },
+
+ /**
+ * Remove self
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ */
+ remove: function (ecModel, api) {
+ this.group.removeAll();
+ },
+
+ /**
+ * Dispose self
+ * @param {module:echarts/model/Global} ecModel
+ * @param {module:echarts/ExtensionAPI} api
+ */
+ dispose: function () {}
+
+ /**
+ * The view contains the given point.
+ * @interface
+ * @param {Array.} point
+ * @return {boolean}
+ */
+ // containPoint: function () {}
+
+ };
+
+ var chartProto = Chart.prototype;
+ chartProto.updateView
+ = chartProto.updateLayout
+ = chartProto.updateVisual
+ = function (seriesModel, ecModel, api, payload) {
+ this.render(seriesModel, ecModel, api, payload);
+ };
+
+ /**
+ * Set state of single element
+ * @param {module:zrender/Element} el
+ * @param {string} state
+ */
+ function elSetState(el, state) {
+ if (el) {
+ el.trigger(state);
+ if (el.type === 'group') {
+ for (var i = 0; i < el.childCount(); i++) {
+ elSetState(el.childAt(i), state);
+ }
+ }
+ }
+ }
+ /**
+ * @param {module:echarts/data/List} data
+ * @param {Object} payload
+ * @param {string} state 'normal'|'emphasis'
+ * @inner
+ */
+ function toggleHighlight(data, payload, state) {
+ var dataIndex = modelUtil.queryDataIndex(data, payload);
+
+ if (dataIndex != null) {
+ zrUtil.each(modelUtil.normalizeToArray(dataIndex), function (dataIdx) {
+ elSetState(data.getItemGraphicEl(dataIdx), state);
+ });
+ }
+ else {
+ data.eachItemGraphicEl(function (el) {
+ elSetState(el, state);
+ });
+ }
+ }
+
+ // Enable Chart.extend.
+ clazzUtil.enableClassExtend(Chart, ['dispose']);
+
+ // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
+ clazzUtil.enableClassManagement(Chart, {registerWhenExtend: true});
+
+ module.exports = Chart;
+
+
+/***/ },
+/* 81 */
+/***/ function(module, exports) {
+
+
+
+ var lib = {};
+
+ var ORIGIN_METHOD = '\0__throttleOriginMethod';
+ var RATE = '\0__throttleRate';
+ var THROTTLE_TYPE = '\0__throttleType';
+
+ /**
+ * @public
+ * @param {(Function)} fn
+ * @param {number} [delay=0] Unit: ms.
+ * @param {boolean} [debounce=false]
+ * true: If call interval less than `delay`, only the last call works.
+ * false: If call interval less than `delay, call works on fixed rate.
+ * @return {(Function)} throttled fn.
+ */
+ lib.throttle = function (fn, delay, debounce) {
+
+ var currCall;
+ var lastCall = 0;
+ var lastExec = 0;
+ var timer = null;
+ var diff;
+ var scope;
+ var args;
+ var debounceNextCall;
+
+ delay = delay || 0;
+
+ function exec() {
+ lastExec = (new Date()).getTime();
+ timer = null;
+ fn.apply(scope, args || []);
+ }
+
+ var cb = function () {
+ currCall = (new Date()).getTime();
+ scope = this;
+ args = arguments;
+ var thisDelay = debounceNextCall || delay;
+ var thisDebounce = debounceNextCall || debounce;
+ debounceNextCall = null;
+ diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;
+
+ clearTimeout(timer);
+
+ if (thisDebounce) {
+ timer = setTimeout(exec, thisDelay);
+ }
+ else {
+ if (diff >= 0) {
+ exec();
+ }
+ else {
+ timer = setTimeout(exec, -diff);
+ }
+ }
+
+ lastCall = currCall;
+ };
+
+ /**
+ * Clear throttle.
+ * @public
+ */
+ cb.clear = function () {
+ if (timer) {
+ clearTimeout(timer);
+ timer = null;
+ }
+ };
+
+ /**
+ * Enable debounce once.
+ */
+ cb.debounceNextCall = function (debounceDelay) {
+ debounceNextCall = debounceDelay;
+ };
+
+ return cb;
+ };
+
+ /**
+ * Create throttle method or update throttle rate.
+ *
+ * @example
+ * ComponentView.prototype.render = function () {
+ * ...
+ * throttle.createOrUpdate(
+ * this,
+ * '_dispatchAction',
+ * this.model.get('throttle'),
+ * 'fixRate'
+ * );
+ * };
+ * ComponentView.prototype.remove = function () {
+ * throttle.clear(this, '_dispatchAction');
+ * };
+ * ComponentView.prototype.dispose = function () {
+ * throttle.clear(this, '_dispatchAction');
+ * };
+ *
+ * @public
+ * @param {Object} obj
+ * @param {string} fnAttr
+ * @param {number} [rate]
+ * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'
+ * @return {Function} throttled function.
+ */
+ lib.createOrUpdate = function (obj, fnAttr, rate, throttleType) {
+ var fn = obj[fnAttr];
+
+ if (!fn) {
+ return;
+ }
+
+ var originFn = fn[ORIGIN_METHOD] || fn;
+ var lastThrottleType = fn[THROTTLE_TYPE];
+ var lastRate = fn[RATE];
+
+ if (lastRate !== rate || lastThrottleType !== throttleType) {
+ if (rate == null || !throttleType) {
+ return (obj[fnAttr] = originFn);
+ }
+
+ fn = obj[fnAttr] = lib.throttle(
+ originFn, rate, throttleType === 'debounce'
+ );
+ fn[ORIGIN_METHOD] = originFn;
+ fn[THROTTLE_TYPE] = throttleType;
+ fn[RATE] = rate;
+ }
+
+ return fn;
+ };
+
+ /**
+ * Clear throttle. Example see throttle.createOrUpdate.
+ *
+ * @public
+ * @param {Object} obj
+ * @param {string} fnAttr
+ */
+ lib.clear = function (obj, fnAttr) {
+ var fn = obj[fnAttr];
+ if (fn && fn[ORIGIN_METHOD]) {
+ obj[fnAttr] = fn[ORIGIN_METHOD];
+ }
+ };
+
+ module.exports = lib;
+
+
+
+/***/ },
+/* 82 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /*!
+ * ZRender, a high performance 2d drawing library.
+ *
+ * Copyright (c) 2013, Baidu Inc.
+ * All rights reserved.
+ *
+ * LICENSE
+ * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
+ */
+ // Global defines
+
+ var guid = __webpack_require__(24);
+ var env = __webpack_require__(2);
+ var zrUtil = __webpack_require__(4);
+
+ var Handler = __webpack_require__(83);
+ var Storage = __webpack_require__(85);
+ var Animation = __webpack_require__(87);
+ var HandlerProxy = __webpack_require__(90);
+
+ var useVML = !env.canvasSupported;
+
+ var painterCtors = {
+ canvas: __webpack_require__(92)
+ };
+
+ var instances = {}; // ZRender实例map索引
+
+ var zrender = {};
+
+ /**
+ * @type {string}
+ */
+ zrender.version = '3.5.2';
+
+ /**
+ * Initializing a zrender instance
+ * @param {HTMLElement} dom
+ * @param {Object} opts
+ * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
+ * @param {number} [opts.devicePixelRatio]
+ * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)
+ * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)
+ * @return {module:zrender/ZRender}
+ */
+ zrender.init = function(dom, opts) {
+ var zr = new ZRender(guid(), dom, opts);
+ instances[zr.id] = zr;
+ return zr;
+ };
+
+ /**
+ * Dispose zrender instance
+ * @param {module:zrender/ZRender} zr
+ */
+ zrender.dispose = function (zr) {
+ if (zr) {
+ zr.dispose();
+ }
+ else {
+ for (var key in instances) {
+ if (instances.hasOwnProperty(key)) {
+ instances[key].dispose();
+ }
+ }
+ instances = {};
+ }
+
+ return zrender;
+ };
+
+ /**
+ * Get zrender instance by id
+ * @param {string} id zrender instance id
+ * @return {module:zrender/ZRender}
+ */
+ zrender.getInstance = function (id) {
+ return instances[id];
+ };
+
+ zrender.registerPainter = function (name, Ctor) {
+ painterCtors[name] = Ctor;
+ };
+
+ function delInstance(id) {
+ delete instances[id];
+ }
+
+ /**
+ * @module zrender/ZRender
+ */
+ /**
+ * @constructor
+ * @alias module:zrender/ZRender
+ * @param {string} id
+ * @param {HTMLDomElement} dom
+ * @param {Object} opts
+ * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
+ * @param {number} [opts.devicePixelRatio]
+ * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)
+ * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)
+ */
+ var ZRender = function(id, dom, opts) {
+
+ opts = opts || {};
+
+ /**
+ * @type {HTMLDomElement}
+ */
+ this.dom = dom;
+
+ /**
+ * @type {string}
+ */
+ this.id = id;
+
+ var self = this;
+ var storage = new Storage();
+
+ var rendererType = opts.renderer;
+ // TODO WebGL
+ if (useVML) {
+ if (!painterCtors.vml) {
+ throw new Error('You need to require \'zrender/vml/vml\' to support IE8');
+ }
+ rendererType = 'vml';
+ }
+ else if (!rendererType || !painterCtors[rendererType]) {
+ rendererType = 'canvas';
+ }
+ var painter = new painterCtors[rendererType](dom, storage, opts);
+
+ this.storage = storage;
+ this.painter = painter;
+
+ var handerProxy = !env.node ? new HandlerProxy(painter.getViewportRoot()) : null;
+ this.handler = new Handler(storage, painter, handerProxy, painter.root);
+
+ /**
+ * @type {module:zrender/animation/Animation}
+ */
+ this.animation = new Animation({
+ stage: {
+ update: zrUtil.bind(this.flush, this)
+ }
+ });
+ this.animation.start();
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this._needsRefresh;
+
+ // 修改 storage.delFromStorage, 每次删除元素之前删除动画
+ // FIXME 有点ugly
+ var oldDelFromStorage = storage.delFromStorage;
+ var oldAddToStorage = storage.addToStorage;
+
+ storage.delFromStorage = function (el) {
+ oldDelFromStorage.call(storage, el);
+
+ el && el.removeSelfFromZr(self);
+ };
+
+ storage.addToStorage = function (el) {
+ oldAddToStorage.call(storage, el);
+
+ el.addSelfToZr(self);
+ };
+ };
+
+ ZRender.prototype = {
+
+ constructor: ZRender,
+ /**
+ * 获取实例唯一标识
+ * @return {string}
+ */
+ getId: function () {
+ return this.id;
+ },
+
+ /**
+ * 添加元素
+ * @param {module:zrender/Element} el
+ */
+ add: function (el) {
+ this.storage.addRoot(el);
+ this._needsRefresh = true;
+ },
+
+ /**
+ * 删除元素
+ * @param {module:zrender/Element} el
+ */
+ remove: function (el) {
+ this.storage.delRoot(el);
+ this._needsRefresh = true;
+ },
+
+ /**
+ * Change configuration of layer
+ * @param {string} zLevel
+ * @param {Object} config
+ * @param {string} [config.clearColor=0] Clear color
+ * @param {string} [config.motionBlur=false] If enable motion blur
+ * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer
+ */
+ configLayer: function (zLevel, config) {
+ this.painter.configLayer(zLevel, config);
+ this._needsRefresh = true;
+ },
+
+ /**
+ * Repaint the canvas immediately
+ */
+ refreshImmediately: function () {
+ // Clear needsRefresh ahead to avoid something wrong happens in refresh
+ // Or it will cause zrender refreshes again and again.
+ this._needsRefresh = false;
+ this.painter.refresh();
+ /**
+ * Avoid trigger zr.refresh in Element#beforeUpdate hook
+ */
+ this._needsRefresh = false;
+ },
+
+ /**
+ * Mark and repaint the canvas in the next frame of browser
+ */
+ refresh: function() {
+ this._needsRefresh = true;
+ },
+
+ /**
+ * Perform all refresh
+ */
+ flush: function () {
+ if (this._needsRefresh) {
+ this.refreshImmediately();
+ }
+ if (this._needsRefreshHover) {
+ this.refreshHoverImmediately();
+ }
+ },
+
+ /**
+ * Add element to hover layer
+ * @param {module:zrender/Element} el
+ * @param {Object} style
+ */
+ addHover: function (el, style) {
+ if (this.painter.addHover) {
+ this.painter.addHover(el, style);
+ this.refreshHover();
+ }
+ },
+
+ /**
+ * Add element from hover layer
+ * @param {module:zrender/Element} el
+ */
+ removeHover: function (el) {
+ if (this.painter.removeHover) {
+ this.painter.removeHover(el);
+ this.refreshHover();
+ }
+ },
+
+ /**
+ * Clear all hover elements in hover layer
+ * @param {module:zrender/Element} el
+ */
+ clearHover: function () {
+ if (this.painter.clearHover) {
+ this.painter.clearHover();
+ this.refreshHover();
+ }
+ },
+
+ /**
+ * Refresh hover in next frame
+ */
+ refreshHover: function () {
+ this._needsRefreshHover = true;
+ },
+
+ /**
+ * Refresh hover immediately
+ */
+ refreshHoverImmediately: function () {
+ this._needsRefreshHover = false;
+ this.painter.refreshHover && this.painter.refreshHover();
+ },
+
+ /**
+ * Resize the canvas.
+ * Should be invoked when container size is changed
+ * @param {Object} [opts]
+ * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)
+ * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)
+ */
+ resize: function(opts) {
+ opts = opts || {};
+ this.painter.resize(opts.width, opts.height);
+ this.handler.resize();
+ },
+
+ /**
+ * Stop and clear all animation immediately
+ */
+ clearAnimation: function () {
+ this.animation.clear();
+ },
+
+ /**
+ * Get container width
+ */
+ getWidth: function() {
+ return this.painter.getWidth();
+ },
+
+ /**
+ * Get container height
+ */
+ getHeight: function() {
+ return this.painter.getHeight();
+ },
+
+ /**
+ * Export the canvas as Base64 URL
+ * @param {string} type
+ * @param {string} [backgroundColor='#fff']
+ * @return {string} Base64 URL
+ */
+ // toDataURL: function(type, backgroundColor) {
+ // return this.painter.getRenderedCanvas({
+ // backgroundColor: backgroundColor
+ // }).toDataURL(type);
+ // },
+
+ /**
+ * Converting a path to image.
+ * It has much better performance of drawing image rather than drawing a vector path.
+ * @param {module:zrender/graphic/Path} e
+ * @param {number} width
+ * @param {number} height
+ */
+ pathToImage: function(e, dpr) {
+ return this.painter.pathToImage(e, dpr);
+ },
+
+ /**
+ * Set default cursor
+ * @param {string} [cursorStyle='default'] 例如 crosshair
+ */
+ setCursorStyle: function (cursorStyle) {
+ this.handler.setCursorStyle(cursorStyle);
+ },
+
+ /**
+ * Find hovered element
+ * @param {number} x
+ * @param {number} y
+ * @return {Object} {target, topTarget}
+ */
+ findHover: function (x, y) {
+ return this.handler.findHover(x, y);
+ },
+
+ /**
+ * Bind event
+ *
+ * @param {string} eventName Event name
+ * @param {Function} eventHandler Handler function
+ * @param {Object} [context] Context object
+ */
+ on: function(eventName, eventHandler, context) {
+ this.handler.on(eventName, eventHandler, context);
+ },
+
+ /**
+ * Unbind event
+ * @param {string} eventName Event name
+ * @param {Function} [eventHandler] Handler function
+ */
+ off: function(eventName, eventHandler) {
+ this.handler.off(eventName, eventHandler);
+ },
+
+ /**
+ * Trigger event manually
+ *
+ * @param {string} eventName Event name
+ * @param {event=} event Event object
+ */
+ trigger: function (eventName, event) {
+ this.handler.trigger(eventName, event);
+ },
+
+
+ /**
+ * Clear all objects and the canvas.
+ */
+ clear: function () {
+ this.storage.delRoot();
+ this.painter.clear();
+ },
+
+ /**
+ * Dispose self.
+ */
+ dispose: function () {
+ this.animation.stop();
+
+ this.clear();
+ this.storage.dispose();
+ this.painter.dispose();
+ this.handler.dispose();
+
+ this.animation =
+ this.storage =
+ this.painter =
+ this.handler = null;
+
+ delInstance(this.id);
+ }
+ };
+
+ module.exports = zrender;
+
+
+
+/***/ },
+/* 83 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * Handler
+ * @module zrender/Handler
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * errorrik (errorrik@gmail.com)
+ * pissang (shenyi.914@gmail.com)
+ */
+
+
+ var util = __webpack_require__(4);
+ var Draggable = __webpack_require__(84);
+
+ var Eventful = __webpack_require__(25);
+
+ var SILENT = 'silent';
+
+ function makeEventPacket(eveType, targetInfo, event) {
+ return {
+ type: eveType,
+ event: event,
+ // target can only be an element that is not silent.
+ target: targetInfo.target,
+ // topTarget can be a silent element.
+ topTarget: targetInfo.topTarget,
+ cancelBubble: false,
+ offsetX: event.zrX,
+ offsetY: event.zrY,
+ gestureEvent: event.gestureEvent,
+ pinchX: event.pinchX,
+ pinchY: event.pinchY,
+ pinchScale: event.pinchScale,
+ wheelDelta: event.zrDelta,
+ zrByTouch: event.zrByTouch
+ };
+ }
+
+ function EmptyProxy () {}
+ EmptyProxy.prototype.dispose = function () {};
+
+ var handlerNames = [
+ 'click', 'dblclick', 'mousewheel', 'mouseout',
+ 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
+ ];
+ /**
+ * @alias module:zrender/Handler
+ * @constructor
+ * @extends module:zrender/mixin/Eventful
+ * @param {module:zrender/Storage} storage Storage instance.
+ * @param {module:zrender/Painter} painter Painter instance.
+ * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.
+ * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).
+ */
+ var Handler = function(storage, painter, proxy, painterRoot) {
+ Eventful.call(this);
+
+ this.storage = storage;
+
+ this.painter = painter;
+
+ this.painterRoot = painterRoot;
+
+ proxy = proxy || new EmptyProxy();
+
+ /**
+ * Proxy of event. can be Dom, WebGLSurface, etc.
+ */
+ this.proxy = proxy;
+
+ // Attach handler
+ proxy.handler = this;
+
+ /**
+ * {target, topTarget}
+ * @private
+ * @type {Object}
+ */
+ this._hovered = {};
+
+ /**
+ * @private
+ * @type {Date}
+ */
+ this._lastTouchMoment;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this._lastX;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this._lastY;
+
+
+ Draggable.call(this);
+
+ util.each(handlerNames, function (name) {
+ proxy.on && proxy.on(name, this[name], this);
+ }, this);
+ };
+
+ Handler.prototype = {
+
+ constructor: Handler,
+
+ mousemove: function (event) {
+ var x = event.zrX;
+ var y = event.zrY;
+
+ var lastHovered = this._hovered;
+ var hovered = this._hovered = this.findHover(x, y);
+ var hoveredTarget = hovered.target;
+ var lastHoveredTarget = lastHovered.target;
+
+ var proxy = this.proxy;
+ proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');
+
+ // Mouse out on previous hovered element
+ if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget && lastHoveredTarget.__zr) {
+ this.dispatchToElement(lastHovered, 'mouseout', event);
+ }
+
+ // Mouse moving on one element
+ this.dispatchToElement(hovered, 'mousemove', event);
+
+ // Mouse over on a new element
+ if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {
+ this.dispatchToElement(hovered, 'mouseover', event);
+ }
+ },
+
+ mouseout: function (event) {
+ this.dispatchToElement(this._hovered, 'mouseout', event);
+
+ // There might be some doms created by upper layer application
+ // at the same level of painter.getViewportRoot() (e.g., tooltip
+ // dom created by echarts), where 'globalout' event should not
+ // be triggered when mouse enters these doms. (But 'mouseout'
+ // should be triggered at the original hovered element as usual).
+ var element = event.toElement || event.relatedTarget;
+ var innerDom;
+ do {
+ element = element && element.parentNode;
+ }
+ while (element && element.nodeType != 9 && !(
+ innerDom = element === this.painterRoot
+ ));
+
+ !innerDom && this.trigger('globalout', {event: event});
+ },
+
+ /**
+ * Resize
+ */
+ resize: function (event) {
+ this._hovered = {};
+ },
+
+ /**
+ * Dispatch event
+ * @param {string} eventName
+ * @param {event=} eventArgs
+ */
+ dispatch: function (eventName, eventArgs) {
+ var handler = this[eventName];
+ handler && handler.call(this, eventArgs);
+ },
+
+ /**
+ * Dispose
+ */
+ dispose: function () {
+
+ this.proxy.dispose();
+
+ this.storage =
+ this.proxy =
+ this.painter = null;
+ },
+
+ /**
+ * 设置默认的cursor style
+ * @param {string} [cursorStyle='default'] 例如 crosshair
+ */
+ setCursorStyle: function (cursorStyle) {
+ var proxy = this.proxy;
+ proxy.setCursor && proxy.setCursor(cursorStyle);
+ },
+
+ /**
+ * 事件分发代理
+ *
+ * @private
+ * @param {Object} targetInfo {target, topTarget} 目标图形元素
+ * @param {string} eventName 事件名称
+ * @param {Object} event 事件对象
+ */
+ dispatchToElement: function (targetInfo, eventName, event) {
+ targetInfo = targetInfo || {};
+ var eventHandler = 'on' + eventName;
+ var eventPacket = makeEventPacket(eventName, targetInfo, event);
+
+ var el = targetInfo.target;
+ while (el) {
+ el[eventHandler]
+ && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));
+
+ el.trigger(eventName, eventPacket);
+
+ el = el.parent;
+
+ if (eventPacket.cancelBubble) {
+ break;
+ }
+ }
+
+ if (!eventPacket.cancelBubble) {
+ // 冒泡到顶级 zrender 对象
+ this.trigger(eventName, eventPacket);
+ // 分发事件到用户自定义层
+ // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在
+ this.painter && this.painter.eachOtherLayer(function (layer) {
+ if (typeof(layer[eventHandler]) == 'function') {
+ layer[eventHandler].call(layer, eventPacket);
+ }
+ if (layer.trigger) {
+ layer.trigger(eventName, eventPacket);
+ }
+ });
+ }
+ },
+
+ /**
+ * @private
+ * @param {number} x
+ * @param {number} y
+ * @param {module:zrender/graphic/Displayable} exclude
+ * @return {model:zrender/Element}
+ * @method
+ */
+ findHover: function(x, y, exclude) {
+ var list = this.storage.getDisplayList();
+ var out = {};
+ var selected = new Array();//here the change is for to return a selected set
+ for (var i = 0; i < list.length ; i++) {
+ var hoverCheckResult;
+ if (list[i] !== exclude
+ // getDisplayList may include ignored item in VML mode
+ && !list[i].ignore
+ && (hoverCheckResult = isHover(list[i], x, y))
+ ) {
+ !out.topTarget && (out.topTarget = list[i]);
+ if (hoverCheckResult !== SILENT) {
+ out.target = list[i];
+ //**yukichange begin
+ selected.push(list[i]) ;
+ //**yukichange end
+ }
+ }
+ }
+ //**yukichange begin
+ if(out.target){
+ out.target.selected = selected;
+ }
+ //**yukichange end
+ return out;
+ }
+ };
+
+ // Common handlers
+ util.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
+ Handler.prototype[name] = function (event) {
+ // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
+
+ var hovered = this.findHover(event.zrX, event.zrY);
+ var hoveredTarget = hovered.target;
+
+ if (name === 'mousedown') {
+ this._downel = hoveredTarget;
+ // In case click triggered before mouseup
+ this._upel = hoveredTarget;
+ }
+ else if (name === 'mosueup') {
+ this._upel = hoveredTarget;
+ }
+ else if (name === 'click') {
+ if (this._downel !== this._upel) {
+ return;
+ }
+ }
+
+ this.dispatchToElement(hovered, name, event);
+ };
+ });
+
+ function isHover(displayable, x, y) {
+ if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
+ var el = displayable;
+ var isSilent;
+ while (el) {
+ // If clipped by ancestor.
+ // FIXME: If clipPath has neither stroke nor fill,
+ // el.clipPath.contain(x, y) will always return false.
+ if (el.clipPath && !el.clipPath.contain(x, y)) {
+ return false;
+ }
+ if (el.silent) {
+ isSilent = true;
+ }
+ el = el.parent;
+ }
+ return isSilent ? SILENT : true;
+ }
+
+ return false;
+ }
+
+ util.mixin(Handler, Eventful);
+ util.mixin(Handler, Draggable);
+
+ module.exports = Handler;
+
+
+
+/***/ },
+/* 84 */
+/***/ function(module, exports) {
+
+ // TODO Draggable for group
+ // FIXME Draggable on element which has parent rotation or scale
+
+ function Draggable() {
+
+ this.on('mousedown', this._dragStart, this);
+ this.on('mousemove', this._drag, this);
+ this.on('mouseup', this._dragEnd, this);
+ this.on('globalout', this._dragEnd, this);
+ // this._dropTarget = null;
+ // this._draggingTarget = null;
+
+ // this._x = 0;
+ // this._y = 0;
+ }
+
+ Draggable.prototype = {
+
+ constructor: Draggable,
+
+ _dragStart: function (e) {
+ var draggingTarget = e.target;
+ if (draggingTarget && draggingTarget.draggable) {
+ this._draggingTarget = draggingTarget;
+ draggingTarget.dragging = true;
+ this._x = e.offsetX;
+ this._y = e.offsetY;
+
+ this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);
+ }
+ },
+
+ _drag: function (e) {
+ var draggingTarget = this._draggingTarget;
+ if (draggingTarget) {
+
+ var x = e.offsetX;
+ var y = e.offsetY;
+
+ var dx = x - this._x;
+ var dy = y - this._y;
+ this._x = x;
+ this._y = y;
+
+ draggingTarget.drift(dx, dy, e);
+ this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);
+
+ var dropTarget = this.findHover(x, y, draggingTarget).target;
+ var lastDropTarget = this._dropTarget;
+ this._dropTarget = dropTarget;
+
+ if (draggingTarget !== dropTarget) {
+ if (lastDropTarget && dropTarget !== lastDropTarget) {
+ this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);
+ }
+ if (dropTarget && dropTarget !== lastDropTarget) {
+ this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);
+ }
+ }
+ }
+ },
+
+ _dragEnd: function (e) {
+ var draggingTarget = this._draggingTarget;
+
+ if (draggingTarget) {
+ draggingTarget.dragging = false;
+ }
+
+ this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);
+
+ if (this._dropTarget) {
+ this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);
+ }
+
+ this._draggingTarget = null;
+ this._dropTarget = null;
+ }
+
+ };
+
+ function param(target, e) {
+ return {target: target, topTarget: e && e.topTarget};
+ }
+
+ module.exports = Draggable;
+
+
+/***/ },
+/* 85 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * Storage内容仓库模块
+ * @module zrender/Storage
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * @author errorrik (errorrik@gmail.com)
+ * @author pissang (https://github.com/pissang/)
+ */
+
+
+ var util = __webpack_require__(4);
+ var env = __webpack_require__(2);
+
+ var Group = __webpack_require__(48);
+
+ // Use timsort because in most case elements are partially sorted
+ // https://jsfiddle.net/pissang/jr4x7mdm/8/
+ var timsort = __webpack_require__(86);
+
+ function shapeCompareFunc(a, b) {
+ if (a.zlevel === b.zlevel) {
+ if (a.z === b.z) {
+ // if (a.z2 === b.z2) {
+ // // FIXME Slow has renderidx compare
+ // // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement
+ // // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012
+ // return a.__renderidx - b.__renderidx;
+ // }
+ return a.z2 - b.z2;
+ }
+ return a.z - b.z;
+ }
+ return a.zlevel - b.zlevel;
+ }
+ /**
+ * 内容仓库 (M)
+ * @alias module:zrender/Storage
+ * @constructor
+ */
+ var Storage = function () {
+ this._roots = [];
+
+ this._displayList = [];
+
+ this._displayListLen = 0;
+ };
+
+ Storage.prototype = {
+
+ constructor: Storage,
+
+ /**
+ * @param {Function} cb
+ *
+ */
+ traverse: function (cb, context) {
+ for (var i = 0; i < this._roots.length; i++) {
+ this._roots[i].traverse(cb, context);
+ }
+ },
+
+ /**
+ * 返回所有图形的绘制队列
+ * @param {boolean} [update=false] 是否在返回前更新该数组
+ * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效
+ *
+ * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}
+ * @return {Array.}
+ */
+ getDisplayList: function (update, includeIgnore) {
+ includeIgnore = includeIgnore || false;
+ if (update) {
+ this.updateDisplayList(includeIgnore);
+ }
+ return this._displayList;
+ },
+
+ /**
+ * 更新图形的绘制队列。
+ * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
+ * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
+ * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组
+ */
+ updateDisplayList: function (includeIgnore) {
+ this._displayListLen = 0;
+ var roots = this._roots;
+ var displayList = this._displayList;
+ for (var i = 0, len = roots.length; i < len; i++) {
+ this._updateAndAddDisplayable(roots[i], null, includeIgnore);
+ }
+ displayList.length = this._displayListLen;
+
+ // for (var i = 0, len = displayList.length; i < len; i++) {
+ // displayList[i].__renderidx = i;
+ // }
+
+ // displayList.sort(shapeCompareFunc);
+ env.canvasSupported && timsort(displayList, shapeCompareFunc);
+ },
+
+ _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {
+
+ if (el.ignore && !includeIgnore) {
+ return;
+ }
+
+ el.beforeUpdate();
+
+ if (el.__dirty) {
+
+ el.update();
+
+ }
+
+ el.afterUpdate();
+
+ var userSetClipPath = el.clipPath;
+ if (userSetClipPath) {
+
+ // FIXME 效率影响
+ if (clipPaths) {
+ clipPaths = clipPaths.slice();
+ }
+ else {
+ clipPaths = [];
+ }
+
+ var currentClipPath = userSetClipPath;
+ var parentClipPath = el;
+ // Recursively add clip path
+ while (currentClipPath) {
+ // clipPath 的变换是基于使用这个 clipPath 的元素
+ currentClipPath.parent = parentClipPath;
+ currentClipPath.updateTransform();
+
+ clipPaths.push(currentClipPath);
+
+ parentClipPath = currentClipPath;
+ currentClipPath = currentClipPath.clipPath;
+ }
+ }
+
+ if (el.isGroup) {
+ var children = el._children;
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+
+ // Force to mark as dirty if group is dirty
+ // FIXME __dirtyPath ?
+ if (el.__dirty) {
+ child.__dirty = true;
+ }
+
+ this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
+ }
+
+ // Mark group clean here
+ el.__dirty = false;
+
+ }
+ else {
+ el.__clipPaths = clipPaths;
+
+ this._displayList[this._displayListLen++] = el;
+ }
+ },
+
+ /**
+ * 添加图形(Shape)或者组(Group)到根节点
+ * @param {module:zrender/Element} el
+ */
+ addRoot: function (el) {
+ if (el.__storage === this) {
+ return;
+ }
+
+ if (el instanceof Group) {
+ el.addChildrenToStorage(this);
+ }
+
+ this.addToStorage(el);
+ this._roots.push(el);
+ },
+
+ /**
+ * 删除指定的图形(Shape)或者组(Group)
+ * @param {string|Array.} [el] 如果为空清空整个Storage
+ */
+ delRoot: function (el) {
+ if (el == null) {
+ // 不指定el清空
+ for (var i = 0; i < this._roots.length; i++) {
+ var root = this._roots[i];
+ if (root instanceof Group) {
+ root.delChildrenFromStorage(this);
+ }
+ }
+
+ this._roots = [];
+ this._displayList = [];
+ this._displayListLen = 0;
+
+ return;
+ }
+
+ if (el instanceof Array) {
+ for (var i = 0, l = el.length; i < l; i++) {
+ this.delRoot(el[i]);
+ }
+ return;
+ }
+
+
+ var idx = util.indexOf(this._roots, el);
+ if (idx >= 0) {
+ this.delFromStorage(el);
+ this._roots.splice(idx, 1);
+ if (el instanceof Group) {
+ el.delChildrenFromStorage(this);
+ }
+ }
+ },
+
+ addToStorage: function (el) {
+ el.__storage = this;
+ el.dirty(false);
+
+ return this;
+ },
+
+ delFromStorage: function (el) {
+ if (el) {
+ el.__storage = null;
+ }
+
+ return this;
+ },
+
+ /**
+ * 清空并且释放Storage
+ */
+ dispose: function () {
+ this._renderList =
+ this._roots = null;
+ },
+
+ displayableSortFunc: shapeCompareFunc
+ };
+
+ module.exports = Storage;
+
+
+
+/***/ },
+/* 86 */
+/***/ function(module, exports) {
+
+ // https://github.com/mziccard/node-timsort
+
+ var DEFAULT_MIN_MERGE = 32;
+
+ var DEFAULT_MIN_GALLOPING = 7;
+
+ var DEFAULT_TMP_STORAGE_LENGTH = 256;
+
+ function minRunLength(n) {
+ var r = 0;
+
+ while (n >= DEFAULT_MIN_MERGE) {
+ r |= n & 1;
+ n >>= 1;
+ }
+
+ return n + r;
+ }
+
+ function makeAscendingRun(array, lo, hi, compare) {
+ var runHi = lo + 1;
+
+ if (runHi === hi) {
+ return 1;
+ }
+
+ if (compare(array[runHi++], array[lo]) < 0) {
+ while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
+ runHi++;
+ }
+
+ reverseRun(array, lo, runHi);
+ }
+ else {
+ while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
+ runHi++;
+ }
+ }
+
+ return runHi - lo;
+ }
+
+ function reverseRun(array, lo, hi) {
+ hi--;
+
+ while (lo < hi) {
+ var t = array[lo];
+ array[lo++] = array[hi];
+ array[hi--] = t;
+ }
+ }
+
+ function binaryInsertionSort(array, lo, hi, start, compare) {
+ if (start === lo) {
+ start++;
+ }
+
+ for (; start < hi; start++) {
+ var pivot = array[start];
+
+ var left = lo;
+ var right = start;
+ var mid;
+
+ while (left < right) {
+ mid = left + right >>> 1;
+
+ if (compare(pivot, array[mid]) < 0) {
+ right = mid;
+ }
+ else {
+ left = mid + 1;
+ }
+ }
+
+ var n = start - left;
+
+ switch (n) {
+ case 3:
+ array[left + 3] = array[left + 2];
+
+ case 2:
+ array[left + 2] = array[left + 1];
+
+ case 1:
+ array[left + 1] = array[left];
+ break;
+ default:
+ while (n > 0) {
+ array[left + n] = array[left + n - 1];
+ n--;
+ }
+ }
+
+ array[left] = pivot;
+ }
+ }
+
+ function gallopLeft(value, array, start, length, hint, compare) {
+ var lastOffset = 0;
+ var maxOffset = 0;
+ var offset = 1;
+
+ if (compare(value, array[start + hint]) > 0) {
+ maxOffset = length - hint;
+
+ while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
+ lastOffset = offset;
+ offset = (offset << 1) + 1;
+
+ if (offset <= 0) {
+ offset = maxOffset;
+ }
+ }
+
+ if (offset > maxOffset) {
+ offset = maxOffset;
+ }
+
+ lastOffset += hint;
+ offset += hint;
+ }
+ else {
+ maxOffset = hint + 1;
+ while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
+ lastOffset = offset;
+ offset = (offset << 1) + 1;
+
+ if (offset <= 0) {
+ offset = maxOffset;
+ }
+ }
+ if (offset > maxOffset) {
+ offset = maxOffset;
+ }
+
+ var tmp = lastOffset;
+ lastOffset = hint - offset;
+ offset = hint - tmp;
+ }
+
+ lastOffset++;
+ while (lastOffset < offset) {
+ var m = lastOffset + (offset - lastOffset >>> 1);
+
+ if (compare(value, array[start + m]) > 0) {
+ lastOffset = m + 1;
+ }
+ else {
+ offset = m;
+ }
+ }
+ return offset;
+ }
+
+ function gallopRight(value, array, start, length, hint, compare) {
+ var lastOffset = 0;
+ var maxOffset = 0;
+ var offset = 1;
+
+ if (compare(value, array[start + hint]) < 0) {
+ maxOffset = hint + 1;
+
+ while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
+ lastOffset = offset;
+ offset = (offset << 1) + 1;
+
+ if (offset <= 0) {
+ offset = maxOffset;
+ }
+ }
+
+ if (offset > maxOffset) {
+ offset = maxOffset;
+ }
+
+ var tmp = lastOffset;
+ lastOffset = hint - offset;
+ offset = hint - tmp;
+ }
+ else {
+ maxOffset = length - hint;
+
+ while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
+ lastOffset = offset;
+ offset = (offset << 1) + 1;
+
+ if (offset <= 0) {
+ offset = maxOffset;
+ }
+ }
+
+ if (offset > maxOffset) {
+ offset = maxOffset;
+ }
+
+ lastOffset += hint;
+ offset += hint;
+ }
+
+ lastOffset++;
+
+ while (lastOffset < offset) {
+ var m = lastOffset + (offset - lastOffset >>> 1);
+
+ if (compare(value, array[start + m]) < 0) {
+ offset = m;
+ }
+ else {
+ lastOffset = m + 1;
+ }
+ }
+
+ return offset;
+ }
+
+ function TimSort(array, compare) {
+ var minGallop = DEFAULT_MIN_GALLOPING;
+ var length = 0;
+ var tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
+ var stackLength = 0;
+ var runStart;
+ var runLength;
+ var stackSize = 0;
+
+ length = array.length;
+
+ if (length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
+ tmpStorageLength = length >>> 1;
+ }
+
+ var tmp = [];
+
+ stackLength = length < 120 ? 5 : length < 1542 ? 10 : length < 119151 ? 19 : 40;
+
+ runStart = [];
+ runLength = [];
+
+ function pushRun(_runStart, _runLength) {
+ runStart[stackSize] = _runStart;
+ runLength[stackSize] = _runLength;
+ stackSize += 1;
+ }
+
+ function mergeRuns() {
+ while (stackSize > 1) {
+ var n = stackSize - 2;
+
+ if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {
+ if (runLength[n - 1] < runLength[n + 1]) {
+ n--;
+ }
+ }
+ else if (runLength[n] > runLength[n + 1]) {
+ break;
+ }
+ mergeAt(n);
+ }
+ }
+
+ function forceMergeRuns() {
+ while (stackSize > 1) {
+ var n = stackSize - 2;
+
+ if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
+ n--;
+ }
+
+ mergeAt(n);
+ }
+ }
+
+ function mergeAt(i) {
+ var start1 = runStart[i];
+ var length1 = runLength[i];
+ var start2 = runStart[i + 1];
+ var length2 = runLength[i + 1];
+
+ runLength[i] = length1 + length2;
+
+ if (i === stackSize - 3) {
+ runStart[i + 1] = runStart[i + 2];
+ runLength[i + 1] = runLength[i + 2];
+ }
+
+ stackSize--;
+
+ var k = gallopRight(array[start2], array, start1, length1, 0, compare);
+ start1 += k;
+ length1 -= k;
+
+ if (length1 === 0) {
+ return;
+ }
+
+ length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
+
+ if (length2 === 0) {
+ return;
+ }
+
+ if (length1 <= length2) {
+ mergeLow(start1, length1, start2, length2);
+ }
+ else {
+ mergeHigh(start1, length1, start2, length2);
+ }
+ }
+
+ function mergeLow(start1, length1, start2, length2) {
+ var i = 0;
+
+ for (i = 0; i < length1; i++) {
+ tmp[i] = array[start1 + i];
+ }
+
+ var cursor1 = 0;
+ var cursor2 = start2;
+ var dest = start1;
+
+ array[dest++] = array[cursor2++];
+
+ if (--length2 === 0) {
+ for (i = 0; i < length1; i++) {
+ array[dest + i] = tmp[cursor1 + i];
+ }
+ return;
+ }
+
+ if (length1 === 1) {
+ for (i = 0; i < length2; i++) {
+ array[dest + i] = array[cursor2 + i];
+ }
+ array[dest + length2] = tmp[cursor1];
+ return;
+ }
+
+ var _minGallop = minGallop;
+ var count1, count2, exit;
+
+ while (1) {
+ count1 = 0;
+ count2 = 0;
+ exit = false;
+
+ do {
+ if (compare(array[cursor2], tmp[cursor1]) < 0) {
+ array[dest++] = array[cursor2++];
+ count2++;
+ count1 = 0;
+
+ if (--length2 === 0) {
+ exit = true;
+ break;
+ }
+ }
+ else {
+ array[dest++] = tmp[cursor1++];
+ count1++;
+ count2 = 0;
+ if (--length1 === 1) {
+ exit = true;
+ break;
+ }
+ }
+ } while ((count1 | count2) < _minGallop);
+
+ if (exit) {
+ break;
+ }
+
+ do {
+ count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
+
+ if (count1 !== 0) {
+ for (i = 0; i < count1; i++) {
+ array[dest + i] = tmp[cursor1 + i];
+ }
+
+ dest += count1;
+ cursor1 += count1;
+ length1 -= count1;
+ if (length1 <= 1) {
+ exit = true;
+ break;
+ }
+ }
+
+ array[dest++] = array[cursor2++];
+
+ if (--length2 === 0) {
+ exit = true;
+ break;
+ }
+
+ count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
+
+ if (count2 !== 0) {
+ for (i = 0; i < count2; i++) {
+ array[dest + i] = array[cursor2 + i];
+ }
+
+ dest += count2;
+ cursor2 += count2;
+ length2 -= count2;
+
+ if (length2 === 0) {
+ exit = true;
+ break;
+ }
+ }
+ array[dest++] = tmp[cursor1++];
+
+ if (--length1 === 1) {
+ exit = true;
+ break;
+ }
+
+ _minGallop--;
+ } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+
+ if (exit) {
+ break;
+ }
+
+ if (_minGallop < 0) {
+ _minGallop = 0;
+ }
+
+ _minGallop += 2;
+ }
+
+ minGallop = _minGallop;
+
+ minGallop < 1 && (minGallop = 1);
+
+ if (length1 === 1) {
+ for (i = 0; i < length2; i++) {
+ array[dest + i] = array[cursor2 + i];
+ }
+ array[dest + length2] = tmp[cursor1];
+ }
+ else if (length1 === 0) {
+ throw new Error();
+ // throw new Error('mergeLow preconditions were not respected');
+ }
+ else {
+ for (i = 0; i < length1; i++) {
+ array[dest + i] = tmp[cursor1 + i];
+ }
+ }
+ }
+
+ function mergeHigh (start1, length1, start2, length2) {
+ var i = 0;
+
+ for (i = 0; i < length2; i++) {
+ tmp[i] = array[start2 + i];
+ }
+
+ var cursor1 = start1 + length1 - 1;
+ var cursor2 = length2 - 1;
+ var dest = start2 + length2 - 1;
+ var customCursor = 0;
+ var customDest = 0;
+
+ array[dest--] = array[cursor1--];
+
+ if (--length1 === 0) {
+ customCursor = dest - (length2 - 1);
+
+ for (i = 0; i < length2; i++) {
+ array[customCursor + i] = tmp[i];
+ }
+
+ return;
+ }
+
+ if (length2 === 1) {
+ dest -= length1;
+ cursor1 -= length1;
+ customDest = dest + 1;
+ customCursor = cursor1 + 1;
+
+ for (i = length1 - 1; i >= 0; i--) {
+ array[customDest + i] = array[customCursor + i];
+ }
+
+ array[dest] = tmp[cursor2];
+ return;
+ }
+
+ var _minGallop = minGallop;
+
+ while (true) {
+ var count1 = 0;
+ var count2 = 0;
+ var exit = false;
+
+ do {
+ if (compare(tmp[cursor2], array[cursor1]) < 0) {
+ array[dest--] = array[cursor1--];
+ count1++;
+ count2 = 0;
+ if (--length1 === 0) {
+ exit = true;
+ break;
+ }
+ }
+ else {
+ array[dest--] = tmp[cursor2--];
+ count2++;
+ count1 = 0;
+ if (--length2 === 1) {
+ exit = true;
+ break;
+ }
+ }
+ } while ((count1 | count2) < _minGallop);
+
+ if (exit) {
+ break;
+ }
+
+ do {
+ count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
+
+ if (count1 !== 0) {
+ dest -= count1;
+ cursor1 -= count1;
+ length1 -= count1;
+ customDest = dest + 1;
+ customCursor = cursor1 + 1;
+
+ for (i = count1 - 1; i >= 0; i--) {
+ array[customDest + i] = array[customCursor + i];
+ }
+
+ if (length1 === 0) {
+ exit = true;
+ break;
+ }
+ }
+
+ array[dest--] = tmp[cursor2--];
+
+ if (--length2 === 1) {
+ exit = true;
+ break;
+ }
+
+ count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
+
+ if (count2 !== 0) {
+ dest -= count2;
+ cursor2 -= count2;
+ length2 -= count2;
+ customDest = dest + 1;
+ customCursor = cursor2 + 1;
+
+ for (i = 0; i < count2; i++) {
+ array[customDest + i] = tmp[customCursor + i];
+ }
+
+ if (length2 <= 1) {
+ exit = true;
+ break;
+ }
+ }
+
+ array[dest--] = array[cursor1--];
+
+ if (--length1 === 0) {
+ exit = true;
+ break;
+ }
+
+ _minGallop--;
+ } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+
+ if (exit) {
+ break;
+ }
+
+ if (_minGallop < 0) {
+ _minGallop = 0;
+ }
+
+ _minGallop += 2;
+ }
+
+ minGallop = _minGallop;
+
+ if (minGallop < 1) {
+ minGallop = 1;
+ }
+
+ if (length2 === 1) {
+ dest -= length1;
+ cursor1 -= length1;
+ customDest = dest + 1;
+ customCursor = cursor1 + 1;
+
+ for (i = length1 - 1; i >= 0; i--) {
+ array[customDest + i] = array[customCursor + i];
+ }
+
+ array[dest] = tmp[cursor2];
+ }
+ else if (length2 === 0) {
+ throw new Error();
+ // throw new Error('mergeHigh preconditions were not respected');
+ }
+ else {
+ customCursor = dest - (length2 - 1);
+ for (i = 0; i < length2; i++) {
+ array[customCursor + i] = tmp[i];
+ }
+ }
+ }
+
+ this.mergeRuns = mergeRuns;
+ this.forceMergeRuns = forceMergeRuns;
+ this.pushRun = pushRun;
+ }
+
+ function sort(array, compare, lo, hi) {
+ if (!lo) {
+ lo = 0;
+ }
+ if (!hi) {
+ hi = array.length;
+ }
+
+ var remaining = hi - lo;
+
+ if (remaining < 2) {
+ return;
+ }
+
+ var runLength = 0;
+
+ if (remaining < DEFAULT_MIN_MERGE) {
+ runLength = makeAscendingRun(array, lo, hi, compare);
+ binaryInsertionSort(array, lo, hi, lo + runLength, compare);
+ return;
+ }
+
+ var ts = new TimSort(array, compare);
+
+ var minRun = minRunLength(remaining);
+
+ do {
+ runLength = makeAscendingRun(array, lo, hi, compare);
+ if (runLength < minRun) {
+ var force = remaining;
+ if (force > minRun) {
+ force = minRun;
+ }
+
+ binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
+ runLength = force;
+ }
+
+ ts.pushRun(lo, runLength);
+ ts.mergeRuns();
+
+ remaining -= runLength;
+ lo += runLength;
+ } while (remaining !== 0);
+
+ ts.forceMergeRuns();
+ }
+
+ module.exports = sort;
+
+
+/***/ },
+/* 87 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 动画主类, 调度和管理所有动画控制器
+ *
+ * @module zrender/animation/Animation
+ * @author pissang(https://github.com/pissang)
+ */
+ // TODO Additive animation
+ // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
+ // https://developer.apple.com/videos/wwdc2014/#236
+
+
+ var util = __webpack_require__(4);
+ var Dispatcher = __webpack_require__(88).Dispatcher;
+
+ var requestAnimationFrame = __webpack_require__(89);
+
+ var Animator = __webpack_require__(28);
+ /**
+ * @typedef {Object} IZRenderStage
+ * @property {Function} update
+ */
+
+ /**
+ * @alias module:zrender/animation/Animation
+ * @constructor
+ * @param {Object} [options]
+ * @param {Function} [options.onframe]
+ * @param {IZRenderStage} [options.stage]
+ * @example
+ * var animation = new Animation();
+ * var obj = {
+ * x: 100,
+ * y: 100
+ * };
+ * animation.animate(node.position)
+ * .when(1000, {
+ * x: 500,
+ * y: 500
+ * })
+ * .when(2000, {
+ * x: 100,
+ * y: 100
+ * })
+ * .start('spline');
+ */
+ var Animation = function (options) {
+
+ options = options || {};
+
+ this.stage = options.stage || {};
+
+ this.onframe = options.onframe || function() {};
+
+ // private properties
+ this._clips = [];
+
+ this._running = false;
+
+ this._time;
+
+ this._pausedTime;
+
+ this._pauseStart;
+
+ this._paused = false;
+
+ Dispatcher.call(this);
+ };
+
+ Animation.prototype = {
+
+ constructor: Animation,
+ /**
+ * 添加 clip
+ * @param {module:zrender/animation/Clip} clip
+ */
+ addClip: function (clip) {
+ this._clips.push(clip);
+ },
+ /**
+ * 添加 animator
+ * @param {module:zrender/animation/Animator} animator
+ */
+ addAnimator: function (animator) {
+ animator.animation = this;
+ var clips = animator.getClips();
+ for (var i = 0; i < clips.length; i++) {
+ this.addClip(clips[i]);
+ }
+ },
+ /**
+ * 删除动画片段
+ * @param {module:zrender/animation/Clip} clip
+ */
+ removeClip: function(clip) {
+ var idx = util.indexOf(this._clips, clip);
+ if (idx >= 0) {
+ this._clips.splice(idx, 1);
+ }
+ },
+
+ /**
+ * 删除动画片段
+ * @param {module:zrender/animation/Animator} animator
+ */
+ removeAnimator: function (animator) {
+ var clips = animator.getClips();
+ for (var i = 0; i < clips.length; i++) {
+ this.removeClip(clips[i]);
+ }
+ animator.animation = null;
+ },
+
+ _update: function() {
+
+ var time = new Date().getTime() - this._pausedTime;
+ var delta = time - this._time;
+ var clips = this._clips;
+ var len = clips.length;
+
+ var deferredEvents = [];
+ var deferredClips = [];
+ for (var i = 0; i < len; i++) {
+ var clip = clips[i];
+ var e = clip.step(time, delta);
+ // Throw out the events need to be called after
+ // stage.update, like destroy
+ if (e) {
+ deferredEvents.push(e);
+ deferredClips.push(clip);
+ }
+ }
+
+ // Remove the finished clip
+ for (var i = 0; i < len;) {
+ if (clips[i]._needsRemove) {
+ clips[i] = clips[len - 1];
+ clips.pop();
+ len--;
+ }
+ else {
+ i++;
+ }
+ }
+
+ len = deferredEvents.length;
+ for (var i = 0; i < len; i++) {
+ deferredClips[i].fire(deferredEvents[i]);
+ }
+
+ this._time = time;
+
+ this.onframe(delta);
+
+ this.trigger('frame', delta);
+
+ if (this.stage.update) {
+ this.stage.update();
+ }
+ },
+
+ _startLoop: function () {
+ var self = this;
+
+ this._running = true;
+
+ function step() {
+ if (self._running) {
+
+ requestAnimationFrame(step);
+
+ !self._paused && self._update();
+ }
+ }
+
+ requestAnimationFrame(step);
+ },
+
+ /**
+ * 开始运行动画
+ */
+ start: function () {
+
+ this._time = new Date().getTime();
+ this._pausedTime = 0;
+
+ this._startLoop();
+ },
+ /**
+ * 停止运行动画
+ */
+ stop: function () {
+ this._running = false;
+ },
+
+ /**
+ * Pause
+ */
+ pause: function () {
+ if (!this._paused) {
+ this._pauseStart = new Date().getTime();
+ this._paused = true;
+ }
+ },
+
+ /**
+ * Resume
+ */
+ resume: function () {
+ if (this._paused) {
+ this._pausedTime += (new Date().getTime()) - this._pauseStart;
+ this._paused = false;
+ }
+ },
+
+ /**
+ * 清除所有动画片段
+ */
+ clear: function () {
+ this._clips = [];
+ },
+ /**
+ * 对一个目标创建一个animator对象,可以指定目标中的属性使用动画
+ * @param {Object} target
+ * @param {Object} options
+ * @param {boolean} [options.loop=false] 是否循环播放动画
+ * @param {Function} [options.getter=null]
+ * 如果指定getter函数,会通过getter函数取属性值
+ * @param {Function} [options.setter=null]
+ * 如果指定setter函数,会通过setter函数设置属性值
+ * @return {module:zrender/animation/Animation~Animator}
+ */
+ // TODO Gap
+ animate: function (target, options) {
+ options = options || {};
+
+ var animator = new Animator(
+ target,
+ options.loop,
+ options.getter,
+ options.setter
+ );
+
+ this.addAnimator(animator);
+
+ return animator;
+ }
+ };
+
+ util.mixin(Animation, Dispatcher);
+
+ module.exports = Animation;
+
+
+
+/***/ },
+/* 88 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * 事件辅助类
+ * @module zrender/core/event
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ */
+
+
+ var Eventful = __webpack_require__(25);
+ var env = __webpack_require__(2);
+
+ var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;
+
+ function getBoundingClientRect(el) {
+ // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect
+ return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};
+ }
+
+ // `calculate` is optional, default false
+ function clientToLocal(el, e, out, calculate) {
+ out = out || {};
+
+ // According to the W3C Working Draft, offsetX and offsetY should be relative
+ // to the padding edge of the target element. The only browser using this convention
+ // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does
+ // not support the properties.
+ // (see http://www.jacklmoore.com/notes/mouse-position/)
+ // In zr painter.dom, padding edge equals to border edge.
+
+ // FIXME
+ // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and
+ // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y
+ // is too complex. So css-transfrom dont support in this case temporarily.
+ if (calculate || !env.canvasSupported) {
+ defaultGetZrXY(el, e, out);
+ }
+ // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned
+ // ancestor element, so we should make sure el is positioned (e.g., not position:static).
+ // BTW1, Webkit don't return the same results as FF in non-simple cases (like add
+ // zoom-factor, overflow / opacity layers, transforms ...)
+ // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.
+ //
+ // BTW3, In ff, offsetX/offsetY is always 0.
+ else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
+ out.zrX = e.layerX;
+ out.zrY = e.layerY;
+ }
+ // For IE6+, chrome, safari, opera. (When will ff support offsetX?)
+ else if (e.offsetX != null) {
+ out.zrX = e.offsetX;
+ out.zrY = e.offsetY;
+ }
+ // For some other device, e.g., IOS safari.
+ else {
+ defaultGetZrXY(el, e, out);
+ }
+
+ return out;
+ }
+
+ function defaultGetZrXY(el, e, out) {
+ // This well-known method below does not support css transform.
+ var box = getBoundingClientRect(el);
+ out.zrX = e.clientX - box.left;
+ out.zrY = e.clientY - box.top;
+ }
+
+ /**
+ * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标.
+ * `calculate` is optional, default false.
+ */
+ function normalizeEvent(el, e, calculate) {
+
+ e = e || window.event;
+
+ if (e.zrX != null) {
+ return e;
+ }
+
+ var eventType = e.type;
+ var isTouch = eventType && eventType.indexOf('touch') >= 0;
+
+ if (!isTouch) {
+ clientToLocal(el, e, e, calculate);
+ e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
+ }
+ else {
+ var touch = eventType != 'touchend'
+ ? e.targetTouches[0]
+ : e.changedTouches[0];
+ touch && clientToLocal(el, touch, e, calculate);
+ }
+
+ return e;
+ }
+
+ function addEventListener(el, name, handler) {
+ if (isDomLevel2) {
+ el.addEventListener(name, handler);
+ }
+ else {
+ el.attachEvent('on' + name, handler);
+ }
+ }
+
+ function removeEventListener(el, name, handler) {
+ if (isDomLevel2) {
+ el.removeEventListener(name, handler);
+ }
+ else {
+ el.detachEvent('on' + name, handler);
+ }
+ }
+
+ /**
+ * preventDefault and stopPropagation.
+ * Notice: do not do that in zrender. Upper application
+ * do that if necessary.
+ *
+ * @memberOf module:zrender/core/event
+ * @method
+ * @param {Event} e : event对象
+ */
+ var stop = isDomLevel2
+ ? function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ e.cancelBubble = true;
+ }
+ : function (e) {
+ e.returnValue = false;
+ e.cancelBubble = true;
+ };
+
+ module.exports = {
+ clientToLocal: clientToLocal,
+ normalizeEvent: normalizeEvent,
+ addEventListener: addEventListener,
+ removeEventListener: removeEventListener,
+
+ stop: stop,
+ // 做向上兼容
+ Dispatcher: Eventful
+ };
+
+
+
+/***/ },
+/* 89 */
+/***/ function(module, exports) {
+
+
+
+ module.exports = (typeof window !== 'undefined' &&
+ ((window.requestAnimationFrame && window.requestAnimationFrame.bind(window))
+ // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809
+ || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))
+ || window.mozRequestAnimationFrame
+ || window.webkitRequestAnimationFrame)
+ )
+ || function (func) {
+ setTimeout(func, 16);
+ };
+
+
+
+/***/ },
+/* 90 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var eventTool = __webpack_require__(88);
+ var zrUtil = __webpack_require__(4);
+ var Eventful = __webpack_require__(25);
+ var env = __webpack_require__(2);
+ var GestureMgr = __webpack_require__(91);
+
+ var addEventListener = eventTool.addEventListener;
+ var removeEventListener = eventTool.removeEventListener;
+ var normalizeEvent = eventTool.normalizeEvent;
+
+ var TOUCH_CLICK_DELAY = 300;
+
+ var mouseHandlerNames = [
+ 'click', 'dblclick', 'mousewheel', 'mouseout',
+ 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
+ ];
+
+ var touchHandlerNames = [
+ 'touchstart', 'touchend', 'touchmove'
+ ];
+
+ var pointerEventNames = {
+ pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1
+ };
+
+ var pointerHandlerNames = zrUtil.map(mouseHandlerNames, function (name) {
+ var nm = name.replace('mouse', 'pointer');
+ return pointerEventNames[nm] ? nm : name;
+ });
+
+ function eventNameFix(name) {
+ return (name === 'mousewheel' && env.browser.firefox) ? 'DOMMouseScroll' : name;
+ }
+
+ function processGesture(proxy, event, stage) {
+ var gestureMgr = proxy._gestureMgr;
+
+ stage === 'start' && gestureMgr.clear();
+
+ var gestureInfo = gestureMgr.recognize(
+ event,
+ proxy.handler.findHover(event.zrX, event.zrY, null).target,
+ proxy.dom
+ );
+
+ stage === 'end' && gestureMgr.clear();
+
+ // Do not do any preventDefault here. Upper application do that if necessary.
+ if (gestureInfo) {
+ var type = gestureInfo.type;
+ event.gestureEvent = type;
+
+ proxy.handler.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);
+ }
+ }
+
+ // function onMSGestureChange(proxy, event) {
+ // if (event.translationX || event.translationY) {
+ // // mousemove is carried by MSGesture to reduce the sensitivity.
+ // proxy.handler.dispatchToElement(event.target, 'mousemove', event);
+ // }
+ // if (event.scale !== 1) {
+ // event.pinchX = event.offsetX;
+ // event.pinchY = event.offsetY;
+ // event.pinchScale = event.scale;
+ // proxy.handler.dispatchToElement(event.target, 'pinch', event);
+ // }
+ // }
+
+ /**
+ * Prevent mouse event from being dispatched after Touch Events action
+ * @see
+ * 1. Mobile browsers dispatch mouse events 300ms after touchend.
+ * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
+ * Result: Blocking Mouse Events for 700ms.
+ */
+ function setTouchTimer(instance) {
+ instance._touching = true;
+ clearTimeout(instance._touchTimer);
+ instance._touchTimer = setTimeout(function () {
+ instance._touching = false;
+ }, 700);
+ }
+
+
+ var domHandlers = {
+ /**
+ * Mouse move handler
+ * @inner
+ * @param {Event} event
+ */
+ mousemove: function (event) {
+ event = normalizeEvent(this.dom, event);
+
+ this.trigger('mousemove', event);
+ },
+
+ /**
+ * Mouse out handler
+ * @inner
+ * @param {Event} event
+ */
+ mouseout: function (event) {
+ event = normalizeEvent(this.dom, event);
+
+ var element = event.toElement || event.relatedTarget;
+ if (element != this.dom) {
+ while (element && element.nodeType != 9) {
+ // 忽略包含在root中的dom引起的mouseOut
+ if (element === this.dom) {
+ return;
+ }
+
+ element = element.parentNode;
+ }
+ }
+
+ this.trigger('mouseout', event);
+ },
+
+ /**
+ * Touch开始响应函数
+ * @inner
+ * @param {Event} event
+ */
+ touchstart: function (event) {
+ // Default mouse behaviour should not be disabled here.
+ // For example, page may needs to be slided.
+ event = normalizeEvent(this.dom, event);
+
+ // Mark touch, which is useful in distinguish touch and
+ // mouse event in upper applicatoin.
+ event.zrByTouch = true;
+
+ this._lastTouchMoment = new Date();
+
+ processGesture(this, event, 'start');
+
+ // In touch device, trigger `mousemove`(`mouseover`) should
+ // be triggered, and must before `mousedown` triggered.
+ domHandlers.mousemove.call(this, event);
+
+ domHandlers.mousedown.call(this, event);
+
+ setTouchTimer(this);
+ },
+
+ /**
+ * Touch移动响应函数
+ * @inner
+ * @param {Event} event
+ */
+ touchmove: function (event) {
+
+ event = normalizeEvent(this.dom, event);
+
+ // Mark touch, which is useful in distinguish touch and
+ // mouse event in upper applicatoin.
+ event.zrByTouch = true;
+
+ processGesture(this, event, 'change');
+
+ // Mouse move should always be triggered no matter whether
+ // there is gestrue event, because mouse move and pinch may
+ // be used at the same time.
+ domHandlers.mousemove.call(this, event);
+
+ setTouchTimer(this);
+ },
+
+ /**
+ * Touch结束响应函数
+ * @inner
+ * @param {Event} event
+ */
+ touchend: function (event) {
+
+ event = normalizeEvent(this.dom, event);
+
+ // Mark touch, which is useful in distinguish touch and
+ // mouse event in upper applicatoin.
+ event.zrByTouch = true;
+
+ processGesture(this, event, 'end');
+
+ domHandlers.mouseup.call(this, event);
+
+ // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is
+ // triggered in `touchstart`. This seems to be illogical, but by this mechanism,
+ // we can conveniently implement "hover style" in both PC and touch device just
+ // by listening to `mouseover` to add "hover style" and listening to `mouseout`
+ // to remove "hover style" on an element, without any additional code for
+ // compatibility. (`mouseout` will not be triggered in `touchend`, so "hover
+ // style" will remain for user view)
+
+ // click event should always be triggered no matter whether
+ // there is gestrue event. System click can not be prevented.
+ if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
+ domHandlers.click.call(this, event);
+ }
+
+ setTouchTimer(this);
+ },
+
+ pointerdown: function (event) {
+ domHandlers.mousedown.call(this, event);
+
+ // if (useMSGuesture(this, event)) {
+ // this._msGesture.addPointer(event.pointerId);
+ // }
+ },
+
+ pointermove: function (event) {
+ // FIXME
+ // pointermove is so sensitive that it always triggered when
+ // tap(click) on touch screen, which affect some judgement in
+ // upper application. So, we dont support mousemove on MS touch
+ // device yet.
+ if (!isPointerFromTouch(event)) {
+ domHandlers.mousemove.call(this, event);
+ }
+ },
+
+ pointerup: function (event) {
+ domHandlers.mouseup.call(this, event);
+ },
+
+ pointerout: function (event) {
+ // pointerout will be triggered when tap on touch screen
+ // (IE11+/Edge on MS Surface) after click event triggered,
+ // which is inconsistent with the mousout behavior we defined
+ // in touchend. So we unify them.
+ // (check domHandlers.touchend for detailed explanation)
+ if (!isPointerFromTouch(event)) {
+ domHandlers.mouseout.call(this, event);
+ }
+ }
+ };
+
+ function isPointerFromTouch(event) {
+ var pointerType = event.pointerType;
+ return pointerType === 'pen' || pointerType === 'touch';
+ }
+
+ // function useMSGuesture(handlerProxy, event) {
+ // return isPointerFromTouch(event) && !!handlerProxy._msGesture;
+ // }
+
+ // Common handlers
+ zrUtil.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
+ domHandlers[name] = function (event) {
+ event = normalizeEvent(this.dom, event);
+ this.trigger(name, event);
+ };
+ });
+
+ /**
+ * 为控制类实例初始化dom 事件处理函数
+ *
+ * @inner
+ * @param {module:zrender/Handler} instance 控制类实例
+ */
+ function initDomHandler(instance) {
+ zrUtil.each(touchHandlerNames, function (name) {
+ instance._handlers[name] = zrUtil.bind(domHandlers[name], instance);
+ });
+
+ zrUtil.each(pointerHandlerNames, function (name) {
+ instance._handlers[name] = zrUtil.bind(domHandlers[name], instance);
+ });
+
+ zrUtil.each(mouseHandlerNames, function (name) {
+ instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);
+ });
+
+ function makeMouseHandler(fn, instance) {
+ return function () {
+ if (instance._touching) {
+ return;
+ }
+ return fn.apply(instance, arguments);
+ };
+ }
+ }
+
+
+ function HandlerDomProxy(dom) {
+ Eventful.call(this);
+
+ this.dom = dom;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this._touching = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this._touchTimer;
+
+ /**
+ * @private
+ * @type {module:zrender/core/GestureMgr}
+ */
+ this._gestureMgr = new GestureMgr();
+
+ this._handlers = {};
+
+ initDomHandler(this);
+
+ if (env.pointerEventsSupported) { // Only IE11+/Edge
+ // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),
+ // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event
+ // at the same time.
+ // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on
+ // screen, which do not occurs in pointer event.
+ // So we use pointer event to both detect touch gesture and mouse behavior.
+ mountHandlers(pointerHandlerNames, this);
+
+ // FIXME
+ // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,
+ // which does not prevent defuault behavior occasionally (which may cause view port
+ // zoomed in but use can not zoom it back). And event.preventDefault() does not work.
+ // So we have to not to use MSGesture and not to support touchmove and pinch on MS
+ // touch screen. And we only support click behavior on MS touch screen now.
+
+ // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.
+ // We dont support touch on IE on win7.
+ // See
+ // if (typeof MSGesture === 'function') {
+ // (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line
+ // dom.addEventListener('MSGestureChange', onMSGestureChange);
+ // }
+ }
+ else {
+ if (env.touchEventsSupported) {
+ mountHandlers(touchHandlerNames, this);
+ // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
+ // addEventListener(root, 'mouseout', this._mouseoutHandler);
+ }
+
+ // 1. Considering some devices that both enable touch and mouse event (like on MS Surface
+ // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise
+ // mouse event can not be handle in those devices.
+ // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent
+ // mouseevent after touch event triggered, see `setTouchTimer`.
+ mountHandlers(mouseHandlerNames, this);
+ }
+
+ function mountHandlers(handlerNames, instance) {
+ zrUtil.each(handlerNames, function (name) {
+ addEventListener(dom, eventNameFix(name), instance._handlers[name]);
+ }, instance);
+ }
+ }
+
+ var handlerDomProxyProto = HandlerDomProxy.prototype;
+ handlerDomProxyProto.dispose = function () {
+ var handlerNames = mouseHandlerNames.concat(touchHandlerNames);
+
+ for (var i = 0; i < handlerNames.length; i++) {
+ var name = handlerNames[i];
+ removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);
+ }
+ };
+
+ handlerDomProxyProto.setCursor = function (cursorStyle) {
+ this.dom.style.cursor = cursorStyle || 'default';
+ };
+
+ zrUtil.mixin(HandlerDomProxy, Eventful);
+
+ module.exports = HandlerDomProxy;
+
+
+/***/ },
+/* 91 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * Only implements needed gestures for mobile.
+ */
+
+
+ var eventUtil = __webpack_require__(88);
+
+ var GestureMgr = function () {
+
+ /**
+ * @private
+ * @type {Array.}
+ */
+ this._track = [];
+ };
+
+ GestureMgr.prototype = {
+
+ constructor: GestureMgr,
+
+ recognize: function (event, target, root) {
+ this._doTrack(event, target, root);
+ return this._recognize(event);
+ },
+
+ clear: function () {
+ this._track.length = 0;
+ return this;
+ },
+
+ _doTrack: function (event, target, root) {
+ var touches = event.touches;
+
+ if (!touches) {
+ return;
+ }
+
+ var trackItem = {
+ points: [],
+ touches: [],
+ target: target,
+ event: event
+ };
+
+ for (var i = 0, len = touches.length; i < len; i++) {
+ var touch = touches[i];
+ var pos = eventUtil.clientToLocal(root, touch, {});
+ trackItem.points.push([pos.zrX, pos.zrY]);
+ trackItem.touches.push(touch);
+ }
+
+ this._track.push(trackItem);
+ },
+
+ _recognize: function (event) {
+ for (var eventName in recognizers) {
+ if (recognizers.hasOwnProperty(eventName)) {
+ var gestureInfo = recognizers[eventName](this._track, event);
+ if (gestureInfo) {
+ return gestureInfo;
+ }
+ }
+ }
+ }
+ };
+
+ function dist(pointPair) {
+ var dx = pointPair[1][0] - pointPair[0][0];
+ var dy = pointPair[1][1] - pointPair[0][1];
+
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ function center(pointPair) {
+ return [
+ (pointPair[0][0] + pointPair[1][0]) / 2,
+ (pointPair[0][1] + pointPair[1][1]) / 2
+ ];
+ }
+
+ var recognizers = {
+
+ pinch: function (track, event) {
+ var trackLen = track.length;
+
+ if (!trackLen) {
+ return;
+ }
+
+ var pinchEnd = (track[trackLen - 1] || {}).points;
+ var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;
+
+ if (pinchPre
+ && pinchPre.length > 1
+ && pinchEnd
+ && pinchEnd.length > 1
+ ) {
+ var pinchScale = dist(pinchEnd) / dist(pinchPre);
+ !isFinite(pinchScale) && (pinchScale = 1);
+
+ event.pinchScale = pinchScale;
+
+ var pinchCenter = center(pinchEnd);
+ event.pinchX = pinchCenter[0];
+ event.pinchY = pinchCenter[1];
+
+ return {
+ type: 'pinch',
+ target: track[0].target,
+ event: event
+ };
+ }
+ }
+
+ // Only pinch currently.
+ };
+
+ module.exports = GestureMgr;
+
+
+
+/***/ },
+/* 92 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ /**
+ * Default canvas painter
+ * @module zrender/Painter
+ * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
+ * errorrik (errorrik@gmail.com)
+ * pissang (https://www.github.com/pissang)
+ */
+
+
+ var config = __webpack_require__(34);
+ var util = __webpack_require__(4);
+ var log = __webpack_require__(33);
+ var BoundingRect = __webpack_require__(9);
+ var timsort = __webpack_require__(86);
+
+ var Layer = __webpack_require__(93);
+
+ var requestAnimationFrame = __webpack_require__(89);
+
+ // PENDIGN
+ // Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time.
+ //
+ // Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer.
+ var MAX_PROGRESSIVE_LAYER_NUMBER = 5;
+
+ function parseInt10(val) {
+ return parseInt(val, 10);
+ }
+
+ function isLayerValid(layer) {
+ if (!layer) {
+ return false;
+ }
+
+ if (layer.__builtin__) {
+ return true;
+ }
+
+ if (typeof(layer.resize) !== 'function'
+ || typeof(layer.refresh) !== 'function'
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function preProcessLayer(layer) {
+ layer.__unusedCount++;
+ }
+
+ function postProcessLayer(layer) {
+ if (layer.__unusedCount == 1) {
+ layer.clear();
+ }
+ }
+
+ var tmpRect = new BoundingRect(0, 0, 0, 0);
+ var viewRect = new BoundingRect(0, 0, 0, 0);
+ function isDisplayableCulled(el, width, height) {
+ tmpRect.copy(el.getBoundingRect());
+ if (el.transform) {
+ tmpRect.applyTransform(el.transform);
+ }
+ viewRect.width = width;
+ viewRect.height = height;
+ return !tmpRect.intersect(viewRect);
+ }
+
+ function isClipPathChanged(clipPaths, prevClipPaths) {
+ if (clipPaths == prevClipPaths) { // Can both be null or undefined
+ return false;
+ }
+
+ if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {
+ return true;
+ }
+ for (var i = 0; i < clipPaths.length; i++) {
+ if (clipPaths[i] !== prevClipPaths[i]) {
+ return true;
+ }
+ }
+ }
+
+ function doClip(clipPaths, ctx) {
+ for (var i = 0; i < clipPaths.length; i++) {
+ var clipPath = clipPaths[i];
+
+ clipPath.setTransform(ctx);
+ ctx.beginPath();
+ clipPath.buildPath(ctx, clipPath.shape);
+ ctx.clip();
+ // Transform back
+ clipPath.restoreTransform(ctx);
+ }
+ }
+
+ function createRoot(width, height) {
+ var domRoot = document.createElement('div');
+
+ // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
+ domRoot.style.cssText = [
+ 'position:relative',
+ 'overflow:hidden',
+ 'width:' + width + 'px',
+ 'height:' + height + 'px',
+ 'padding:0',
+ 'margin:0',
+ 'border-width:0'
+ ].join(';') + ';';
+
+ return domRoot;
+ }
+
+ /**
+ * @alias module:zrender/Painter
+ * @constructor
+ * @param {HTMLElement} root 绘图容器
+ * @param {module:zrender/Storage} storage
+ * @param {Ojbect} opts
+ */
+ var Painter = function (root, storage, opts) {
+ // In node environment using node-canvas
+ var singleCanvas = !root.nodeName // In node ?
+ || root.nodeName.toUpperCase() === 'CANVAS';
+
+ this._opts = opts = util.extend({}, opts || {});
+
+ /**
+ * @type {number}
+ */
+ this.dpr = opts.devicePixelRatio || config.devicePixelRatio;
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this._singleCanvas = singleCanvas;
+ /**
+ * 绘图容器
+ * @type {HTMLElement}
+ */
+ this.root = root;
+
+ var rootStyle = root.style;
+
+ if (rootStyle) {
+ rootStyle['-webkit-tap-highlight-color'] = 'transparent';
+ rootStyle['-webkit-user-select'] =
+ rootStyle['user-select'] =
+ rootStyle['-webkit-touch-callout'] = 'none';
+
+ root.innerHTML = '';
+ }
+
+ /**
+ * @type {module:zrender/Storage}
+ */
+ this.storage = storage;
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ var zlevelList = this._zlevelList = [];
+
+ /**
+ * @type {Object.}
+ * @private
+ */
+ var layers = this._layers = {};
+
+ /**
+ * @type {Object.}
+ * @type {private}
+ */
+ this._layerConfig = {};
+
+ if (!singleCanvas) {
+ this._width = this._getSize(0);
+ this._height = this._getSize(1);
+
+ var domRoot = this._domRoot = createRoot(
+ this._width, this._height
+ );
+ root.appendChild(domRoot);
+ }
+ else {
+ if (opts.width != null) {
+ root.width = opts.width;
+ }
+ if (opts.height != null) {
+ root.height = opts.height;
+ }
+ // Use canvas width and height directly
+ var width = root.width;
+ var height = root.height;
+ this._width = width;
+ this._height = height;
+
+ // Create layer if only one given canvas
+ // Device pixel ratio is fixed to 1 because given canvas has its specified width and height
+ var mainLayer = new Layer(root, this, 1);
+ mainLayer.initContext();
+ // FIXME Use canvas width and height
+ // mainLayer.resize(width, height);
+ layers[0] = mainLayer;
+ zlevelList.push(0);
+
+ this._domRoot = root;
+ }
+
+ // Layers for progressive rendering
+ this._progressiveLayers = [];
+
+ /**
+ * @type {module:zrender/Layer}
+ * @private
+ */
+ this._hoverlayer;
+
+ this._hoverElements = [];
+ };
+
+ Painter.prototype = {
+
+ constructor: Painter,
+
+ /**
+ * If painter use a single canvas
+ * @return {boolean}
+ */
+ isSingleCanvas: function () {
+ return this._singleCanvas;
+ },
+ /**
+ * @return {HTMLDivElement}
+ */
+ getViewportRoot: function () {
+ return this._domRoot;
+ },
+
+ /**
+ * 刷新
+ * @param {boolean} [paintAll=false] 强制绘制所有displayable
+ */
+ refresh: function (paintAll) {
+
+ var list = this.storage.getDisplayList(true);
+
+ var zlevelList = this._zlevelList;
+
+ this._paintList(list, paintAll);
+
+ // Paint custum layers
+ for (var i = 0; i < zlevelList.length; i++) {
+ var z = zlevelList[i];
+ var layer = this._layers[z];
+ if (!layer.__builtin__ && layer.refresh) {
+ layer.refresh();
+ }
+ }
+
+ this.refreshHover();
+
+ if (this._progressiveLayers.length) {
+ this._startProgessive();
+ }
+
+ return this;
+ },
+
+ addHover: function (el, hoverStyle) {
+ if (el.__hoverMir) {
+ return;
+ }
+ var elMirror = new el.constructor({
+ style: el.style,
+ shape: el.shape
+ });
+ elMirror.__from = el;
+ el.__hoverMir = elMirror;
+ elMirror.setStyle(hoverStyle);
+ this._hoverElements.push(elMirror);
+ },
+
+ removeHover: function (el) {
+ var elMirror = el.__hoverMir;
+ var hoverElements = this._hoverElements;
+ var idx = util.indexOf(hoverElements, elMirror);
+ if (idx >= 0) {
+ hoverElements.splice(idx, 1);
+ }
+ el.__hoverMir = null;
+ },
+
+ clearHover: function (el) {
+ var hoverElements = this._hoverElements;
+ for (var i = 0; i < hoverElements.length; i++) {
+ var from = hoverElements[i].__from;
+ if (from) {
+ from.__hoverMir = null;
+ }
+ }
+ hoverElements.length = 0;
+ },
+
+ refreshHover: function () {
+ var hoverElements = this._hoverElements;
+ var len = hoverElements.length;
+ var hoverLayer = this._hoverlayer;
+ hoverLayer && hoverLayer.clear();
+
+ if (!len) {
+ return;
+ }
+ timsort(hoverElements, this.storage.displayableSortFunc);
+
+ // Use a extream large zlevel
+ // FIXME?
+ if (!hoverLayer) {
+ hoverLayer = this._hoverlayer = this.getLayer(1e5);
+ }
+
+ var scope = {};
+ hoverLayer.ctx.save();
+ for (var i = 0; i < len;) {
+ var el = hoverElements[i];
+ var originalEl = el.__from;
+ // Original el is removed
+ // PENDING
+ if (!(originalEl && originalEl.__zr)) {
+ hoverElements.splice(i, 1);
+ originalEl.__hoverMir = null;
+ len--;
+ continue;
+ }
+ i++;
+
+ // Use transform
+ // FIXME style and shape ?
+ if (!originalEl.invisible) {
+ el.transform = originalEl.transform;
+ el.invTransform = originalEl.invTransform;
+ el.__clipPaths = originalEl.__clipPaths;
+ // el.
+ this._doPaintEl(el, hoverLayer, true, scope);
+ }
+ }
+ hoverLayer.ctx.restore();
+ },
+
+ _startProgessive: function () {
+ var self = this;
+
+ if (!self._furtherProgressive) {
+ return;
+ }
+
+ // Use a token to stop progress steps triggered by
+ // previous zr.refresh calling.
+ var token = self._progressiveToken = +new Date();
+
+ self._progress++;
+ requestAnimationFrame(step);
+
+ function step() {
+ // In case refreshed or disposed
+ if (token === self._progressiveToken && self.storage) {
+
+ self._doPaintList(self.storage.getDisplayList());
+
+ if (self._furtherProgressive) {
+ self._progress++;
+ requestAnimationFrame(step);
+ }
+ else {
+ self._progressiveToken = -1;
+ }
+ }
+ }
+ },
+
+ _clearProgressive: function () {
+ this._progressiveToken = -1;
+ this._progress = 0;
+ util.each(this._progressiveLayers, function (layer) {
+ layer.__dirty && layer.clear();
+ });
+ },
+
+ _paintList: function (list, paintAll) {
+
+ if (paintAll == null) {
+ paintAll = false;
+ }
+
+ this._updateLayerStatus(list);
+
+ this._clearProgressive();
+
+ this.eachBuiltinLayer(preProcessLayer);
+
+ this._doPaintList(list, paintAll);
+
+ this.eachBuiltinLayer(postProcessLayer);
+ },
+
+ _doPaintList: function (list, paintAll) {
+ var currentLayer;
+ var currentZLevel;
+ var ctx;
+
+ // var invTransform = [];
+ var scope;
+
+ var progressiveLayerIdx = 0;
+ var currentProgressiveLayer;
+
+ var width = this._width;
+ var height = this._height;
+ var layerProgress;
+ var frame = this._progress;
+ function flushProgressiveLayer(layer) {
+ var dpr = ctx.dpr || 1;
+ ctx.save();
+ ctx.globalAlpha = 1;
+ ctx.shadowBlur = 0;
+ // Avoid layer don't clear in next progressive frame
+ currentLayer.__dirty = true;
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.drawImage(layer.dom, 0, 0, width * dpr, height * dpr);
+ ctx.restore();
+ }
+
+ for (var i = 0, l = list.length; i < l; i++) {
+ var el = list[i];
+ var elZLevel = this._singleCanvas ? 0 : el.zlevel;
+
+ var elFrame = el.__frame;
+
+ // Flush at current context
+ // PENDING
+ if (elFrame < 0 && currentProgressiveLayer) {
+ flushProgressiveLayer(currentProgressiveLayer);
+ currentProgressiveLayer = null;
+ }
+
+ // Change draw layer
+ if (currentZLevel !== elZLevel) {
+ if (ctx) {
+ ctx.restore();
+ }
+
+ // Reset scope
+ scope = {};
+
+ // Only 0 zlevel if only has one canvas
+ currentZLevel = elZLevel;
+ currentLayer = this.getLayer(currentZLevel);
+
+ if (!currentLayer.__builtin__) {
+ log(
+ 'ZLevel ' + currentZLevel
+ + ' has been used by unkown layer ' + currentLayer.id
+ );
+ }
+
+ ctx = currentLayer.ctx;
+ ctx.save();
+
+ // Reset the count
+ currentLayer.__unusedCount = 0;
+
+ if (currentLayer.__dirty || paintAll) {
+ currentLayer.clear();
+ }
+ }
+
+ if (!(currentLayer.__dirty || paintAll)) {
+ continue;
+ }
+
+ if (elFrame >= 0) {
+ // Progressive layer changed
+ if (!currentProgressiveLayer) {
+ currentProgressiveLayer = this._progressiveLayers[
+ Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1)
+ ];
+
+ currentProgressiveLayer.ctx.save();
+ currentProgressiveLayer.renderScope = {};
+
+ if (currentProgressiveLayer
+ && (currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress)
+ ) {
+ // flushProgressiveLayer(currentProgressiveLayer);
+ // Quick jump all progressive elements
+ // All progressive element are not dirty, jump over and flush directly
+ i = currentProgressiveLayer.__nextIdxNotProg - 1;
+ // currentProgressiveLayer = null;
+ continue;
+ }
+
+ layerProgress = currentProgressiveLayer.__progress;
+
+ if (!currentProgressiveLayer.__dirty) {
+ // Keep rendering
+ frame = layerProgress;
+ }
+
+ currentProgressiveLayer.__progress = frame + 1;
+ }
+
+ if (elFrame === frame) {
+ this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope);
+ }
+ }
+ else {
+ this._doPaintEl(el, currentLayer, paintAll, scope);
+ }
+
+ el.__dirty = false;
+ }
+
+ if (currentProgressiveLayer) {
+ flushProgressiveLayer(currentProgressiveLayer);
+ }
+
+ // Restore the lastLayer ctx
+ ctx && ctx.restore();
+ // If still has clipping state
+ // if (scope.prevElClipPaths) {
+ // ctx.restore();
+ // }
+
+ this._furtherProgressive = false;
+ util.each(this._progressiveLayers, function (layer) {
+ if (layer.__maxProgress >= layer.__progress) {
+ this._furtherProgressive = true;
+ }
+ }, this);
+ },
+
+ _doPaintEl: function (el, currentLayer, forcePaint, scope) {
+ var ctx = currentLayer.ctx;
+ var m = el.transform;
+ if (
+ (currentLayer.__dirty || forcePaint)
+ // Ignore invisible element
+ && !el.invisible
+ // Ignore transparent element
+ && el.style.opacity !== 0
+ // Ignore scale 0 element, in some environment like node-canvas
+ // Draw a scale 0 element can cause all following draw wrong
+ // And setTransform with scale 0 will cause set back transform failed.
+ && !(m && !m[0] && !m[3])
+ // Ignore culled element
+ && !(el.culling && isDisplayableCulled(el, this._width, this._height))
+ ) {
+
+ var clipPaths = el.__clipPaths;
+
+ // Optimize when clipping on group with several elements
+ if (scope.prevClipLayer !== currentLayer
+ || isClipPathChanged(clipPaths, scope.prevElClipPaths)
+ ) {
+ // If has previous clipping state, restore from it
+ if (scope.prevElClipPaths) {
+ scope.prevClipLayer.ctx.restore();
+ scope.prevClipLayer = scope.prevElClipPaths = null;
+
+ // Reset prevEl since context has been restored
+ scope.prevEl = null;
+ }
+ // New clipping state
+ if (clipPaths) {
+ ctx.save();
+ doClip(clipPaths, ctx);
+ scope.prevClipLayer = currentLayer;
+ scope.prevElClipPaths = clipPaths;
+ }
+ }
+ el.beforeBrush && el.beforeBrush(ctx);
+
+ el.brush(ctx, scope.prevEl || null);
+ scope.prevEl = el;
+
+ el.afterBrush && el.afterBrush(ctx);
+ }
+ },
+
+ /**
+ * 获取 zlevel 所在层,如果不存在则会创建一个新的层
+ * @param {number} zlevel
+ * @return {module:zrender/Layer}
+ */
+ getLayer: function (zlevel) {
+ if (this._singleCanvas) {
+ return this._layers[0];
+ }
+
+ var layer = this._layers[zlevel];
+ if (!layer) {
+ // Create a new layer
+ layer = new Layer('zr_' + zlevel, this, this.dpr);
+ layer.__builtin__ = true;
+
+ if (this._layerConfig[zlevel]) {
+ util.merge(layer, this._layerConfig[zlevel], true);
+ }
+
+ this.insertLayer(zlevel, layer);
+
+ // Context is created after dom inserted to document
+ // Or excanvas will get 0px clientWidth and clientHeight
+ layer.initContext();
+ }
+
+ return layer;
+ },
+
+ insertLayer: function (zlevel, layer) {
+
+ var layersMap = this._layers;
+ var zlevelList = this._zlevelList;
+ var len = zlevelList.length;
+ var prevLayer = null;
+ var i = -1;
+ var domRoot = this._domRoot;
+
+ if (layersMap[zlevel]) {
+ log('ZLevel ' + zlevel + ' has been used already');
+ return;
+ }
+ // Check if is a valid layer
+ if (!isLayerValid(layer)) {
+ log('Layer of zlevel ' + zlevel + ' is not valid');
+ return;
+ }
+
+ if (len > 0 && zlevel > zlevelList[0]) {
+ for (i = 0; i < len - 1; i++) {
+ if (
+ zlevelList[i] < zlevel
+ && zlevelList[i + 1] > zlevel
+ ) {
+ break;
+ }
+ }
+ prevLayer = layersMap[zlevelList[i]];
+ }
+ zlevelList.splice(i + 1, 0, zlevel);
+
+ layersMap[zlevel] = layer;
+
+ // Vitual layer will not directly show on the screen.
+ // (It can be a WebGL layer and assigned to a ZImage element)
+ // But it still under management of zrender.
+ if (!layer.virtual) {
+ if (prevLayer) {
+ var prevDom = prevLayer.dom;
+ if (prevDom.nextSibling) {
+ domRoot.insertBefore(
+ layer.dom,
+ prevDom.nextSibling
+ );
+ }
+ else {
+ domRoot.appendChild(layer.dom);
+ }
+ }
+ else {
+ if (domRoot.firstChild) {
+ domRoot.insertBefore(layer.dom, domRoot.firstChild);
+ }
+ else {
+ domRoot.appendChild(layer.dom);
+ }
+ }
+ }
+ },
+
+ // Iterate each layer
+ eachLayer: function (cb, context) {
+ var zlevelList = this._zlevelList;
+ var z;
+ var i;
+ for (i = 0; i < zlevelList.length; i++) {
+ z = zlevelList[i];
+ cb.call(context, this._layers[z], z);
+ }
+ },
+
+ // Iterate each buildin layer
+ eachBuiltinLayer: function (cb, context) {
+ var zlevelList = this._zlevelList;
+ var layer;
+ var z;
+ var i;
+ for (i = 0; i < zlevelList.length; i++) {
+ z = zlevelList[i];
+ layer = this._layers[z];
+ if (layer.__builtin__) {
+ cb.call(context, layer, z);
+ }
+ }
+ },
+
+ // Iterate each other layer except buildin layer
+ eachOtherLayer: function (cb, context) {
+ var zlevelList = this._zlevelList;
+ var layer;
+ var z;
+ var i;
+ for (i = 0; i < zlevelList.length; i++) {
+ z = zlevelList[i];
+ layer = this._layers[z];
+ if (!layer.__builtin__) {
+ cb.call(context, layer, z);
+ }
+ }
+ },
+
+ /**
+ * 获取所有已创建的层
+ * @param {Array.} [prevLayer]
+ */
+ getLayers: function () {
+ return this._layers;
+ },
+
+ _updateLayerStatus: function (list) {
+
+ var layers = this._layers;
+ var progressiveLayers = this._progressiveLayers;
+
+ var elCountsLastFrame = {};
+ var progressiveElCountsLastFrame = {};
+
+ this.eachBuiltinLayer(function (layer, z) {
+ elCountsLastFrame[z] = layer.elCount;
+ layer.elCount = 0;
+ layer.__dirty = false;
+ });
+
+ util.each(progressiveLayers, function (layer, idx) {
+ progressiveElCountsLastFrame[idx] = layer.elCount;
+ layer.elCount = 0;
+ layer.__dirty = false;
+ });
+
+ var progressiveLayerCount = 0;
+ var currentProgressiveLayer;
+ var lastProgressiveKey;
+ var frameCount = 0;
+ for (var i = 0, l = list.length; i < l; i++) {
+ var el = list[i];
+ var zlevel = this._singleCanvas ? 0 : el.zlevel;
+ var layer = layers[zlevel];
+ var elProgress = el.progressive;
+ if (layer) {
+ layer.elCount++;
+ layer.__dirty = layer.__dirty || el.__dirty;
+ }
+
+ /////// Update progressive
+ if (elProgress >= 0) {
+ // Fix wrong progressive sequence problem.
+ if (lastProgressiveKey !== elProgress) {
+ lastProgressiveKey = elProgress;
+ frameCount++;
+ }
+ var elFrame = el.__frame = frameCount - 1;
+ if (!currentProgressiveLayer) {
+ var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1);
+ currentProgressiveLayer = progressiveLayers[idx];
+ if (!currentProgressiveLayer) {
+ currentProgressiveLayer = progressiveLayers[idx] = new Layer(
+ 'progressive', this, this.dpr
+ );
+ currentProgressiveLayer.initContext();
+ }
+ currentProgressiveLayer.__maxProgress = 0;
+ }
+ currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty;
+ currentProgressiveLayer.elCount++;
+
+ currentProgressiveLayer.__maxProgress = Math.max(
+ currentProgressiveLayer.__maxProgress, elFrame
+ );
+
+ if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) {
+ // Should keep rendering this layer because progressive rendering is not finished yet
+ layer.__dirty = true;
+ }
+ }
+ else {
+ el.__frame = -1;
+
+ if (currentProgressiveLayer) {
+ currentProgressiveLayer.__nextIdxNotProg = i;
+ progressiveLayerCount++;
+ currentProgressiveLayer = null;
+ }
+ }
+ }
+
+ if (currentProgressiveLayer) {
+ progressiveLayerCount++;
+ currentProgressiveLayer.__nextIdxNotProg = i;
+ }
+
+ // 层中的元素数量有发生变化
+ this.eachBuiltinLayer(function (layer, z) {
+ if (elCountsLastFrame[z] !== layer.elCount) {
+ layer.__dirty = true;
+ }
+ });
+
+ progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER);
+ util.each(progressiveLayers, function (layer, idx) {
+ if (progressiveElCountsLastFrame[idx] !== layer.elCount) {
+ el.__dirty = true;
+ }
+ if (layer.__dirty) {
+ layer.__progress = 0;
+ }
+ });
+ },
+
+ /**
+ * 清除hover层外所有内容
+ */
+ clear: function () {
+ this.eachBuiltinLayer(this._clearLayer);
+ return this;
+ },
+
+ _clearLayer: function (layer) {
+ layer.clear();
+ },
+
+ /**
+ * 修改指定zlevel的绘制参数
+ *
+ * @param {string} zlevel
+ * @param {Object} config 配置对象
+ * @param {string} [config.clearColor=0] 每次清空画布的颜色
+ * @param {string} [config.motionBlur=false] 是否开启动态模糊
+ * @param {number} [config.lastFrameAlpha=0.7]
+ * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
+ */
+ configLayer: function (zlevel, config) {
+ if (config) {
+ var layerConfig = this._layerConfig;
+ if (!layerConfig[zlevel]) {
+ layerConfig[zlevel] = config;
+ }
+ else {
+ util.merge(layerConfig[zlevel], config, true);
+ }
+
+ var layer = this._layers[zlevel];
+
+ if (layer) {
+ util.merge(layer, layerConfig[zlevel], true);
+ }
+ }
+ },
+
+ /**
+ * 删除指定层
+ * @param {number} zlevel 层所在的zlevel
+ */
+ delLayer: function (zlevel) {
+ var layers = this._layers;
+ var zlevelList = this._zlevelList;
+ var layer = layers[zlevel];
+ if (!layer) {
+ return;
+ }
+ layer.dom.parentNode.removeChild(layer.dom);
+ delete layers[zlevel];
+
+ zlevelList.splice(util.indexOf(zlevelList, zlevel), 1);
+ },
+
+ /**
+ * 区域大小变化后重绘
+ */
+ resize: function (width, height) {
+ var domRoot = this._domRoot;
+ // FIXME Why ?
+ domRoot.style.display = 'none';
+
+ // Save input w/h
+ var opts = this._opts;
+ width != null && (opts.width = width);
+ height != null && (opts.height = height);
+
+ width = this._getSize(0);
+ height = this._getSize(1);
+
+ domRoot.style.display = '';
+
+ // 优化没有实际改变的resize
+ if (this._width != width || height != this._height) {
+ domRoot.style.width = width + 'px';
+ domRoot.style.height = height + 'px';
+
+ for (var id in this._layers) {
+ if (this._layers.hasOwnProperty(id)) {
+ this._layers[id].resize(width, height);
+ }
+ }
+ util.each(this._progressiveLayers, function (layer) {
+ layer.resize(width, height);
+ });
+
+ this.refresh(true);
+ }
+
+ this._width = width;
+ this._height = height;
+
+ return this;
+ },
+
+ /**
+ * 清除单独的一个层
+ * @param {number} zlevel
+ */
+ clearLayer: function (zlevel) {
+ var layer = this._layers[zlevel];
+ if (layer) {
+ layer.clear();
+ }
+ },
+
+ /**
+ * 释放
+ */
+ dispose: function () {
+ this.root.innerHTML = '';
+
+ this.root =
+ this.storage =
+
+ this._domRoot =
+ this._layers = null;
+ },
+
+ /**
+ * Get canvas which has all thing rendered
+ * @param {Object} opts
+ * @param {string} [opts.backgroundColor]
+ */
+ getRenderedCanvas: function (opts) {
+ opts = opts || {};
+ if (this._singleCanvas) {
+ return this._layers[0].dom;
+ }
+
+ var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
+ imageLayer.initContext();
+
+ imageLayer.clearColor = opts.backgroundColor;
+ imageLayer.clear();
+
+ var displayList = this.storage.getDisplayList(true);
+
+ var scope = {};
+ var zlevel;
+
+ var self = this;
+ function findAndDrawOtherLayer(smaller, larger) {
+ var zlevelList = self._zlevelList;
+ if (smaller == null) {
+ smaller = -Infinity;
+ }
+ var intermediateLayer;
+ for (var i = 0; i < zlevelList.length; i++) {
+ var z = zlevelList[i];
+ var layer = self._layers[z];
+ if (!layer.__builtin__ && z > smaller && z < larger) {
+ intermediateLayer = layer;
+ break;
+ }
+ }
+ if (intermediateLayer && intermediateLayer.renderToCanvas) {
+ imageLayer.ctx.save();
+ intermediateLayer.renderToCanvas(imageLayer.ctx);
+ imageLayer.ctx.restore();
+ }
+ }
+ for (var i = 0; i < displayList.length; i++) {
+ var el = displayList[i];
+
+ if (el.zlevel !== zlevel) {
+ findAndDrawOtherLayer(zlevel, el.zlevel);
+ zlevel = el.zlevel;
+ }
+ this._doPaintEl(el, imageLayer, true, scope);
+ }
+
+ findAndDrawOtherLayer(zlevel, Infinity);
+
+ return imageLayer.dom;
+ },
+ /**
+ * 获取绘图区域宽度
+ */
+ getWidth: function () {
+ return this._width;
+ },
+
+ /**
+ * 获取绘图区域高度
+ */
+ getHeight: function () {
+ return this._height;
+ },
+
+ _getSize: function (whIdx) {
+ var opts = this._opts;
+ var wh = ['width', 'height'][whIdx];
+ var cwh = ['clientWidth', 'clientHeight'][whIdx];
+ var plt = ['paddingLeft', 'paddingTop'][whIdx];
+ var prb = ['paddingRight', 'paddingBottom'][whIdx];
+
+ if (opts[wh] != null && opts[wh] !== 'auto') {
+ return parseFloat(opts[wh]);
+ }
+
+ var root = this.root;
+ var stl = document.defaultView.getComputedStyle(root);
+
+ return (
+ (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))
+ - (parseInt10(stl[plt]) || 0)
+ - (parseInt10(stl[prb]) || 0)
+ ) | 0;
+ },
+
+ pathToImage: function (path, dpr) {
+ dpr = dpr || this.dpr;
+
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('2d');
+ var rect = path.getBoundingRect();
+ var style = path.style;
+ var shadowBlurSize = style.shadowBlur;
+ var shadowOffsetX = style.shadowOffsetX;
+ var shadowOffsetY = style.shadowOffsetY;
+ var lineWidth = style.hasStroke() ? style.lineWidth : 0;
+
+ var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);
+ var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);
+ var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);
+ var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);
+ var width = rect.width + leftMargin + rightMargin;
+ var height = rect.height + topMargin + bottomMargin;
+
+ canvas.width = width * dpr;
+ canvas.height = height * dpr;
+
+ ctx.scale(dpr, dpr);
+ ctx.clearRect(0, 0, width, height);
+ ctx.dpr = dpr;
+
+ var pathTransform = {
+ position: path.position,
+ rotation: path.rotation,
+ scale: path.scale
+ };
+ path.position = [leftMargin - rect.x, topMargin - rect.y];
+ path.rotation = 0;
+ path.scale = [1, 1];
+ path.updateTransform();
+ if (path) {
+ path.brush(ctx);
+ }
+
+ var ImageShape = __webpack_require__(49);
+ var imgShape = new ImageShape({
+ style: {
+ x: 0,
+ y: 0,
+ image: canvas
+ }
+ });
+
+ if (pathTransform.position != null) {
+ imgShape.position = path.position = pathTransform.position;
+ }
+
+ if (pathTransform.rotation != null) {
+ imgShape.rotation = path.rotation = pathTransform.rotation;
+ }
+
+ if (pathTransform.scale != null) {
+ imgShape.scale = path.scale = pathTransform.scale;
+ }
+
+ return imgShape;
+ }
+ };
+
+ module.exports = Painter;
+
+
+
+/***/ },
+/* 93 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * @module zrender/Layer
+ * @author pissang(https://www.github.com/pissang)
+ */
+
+
+ var util = __webpack_require__(4);
+ var config = __webpack_require__(34);
+ var Style = __webpack_require__(22);
+ var Pattern = __webpack_require__(46);
+
+ function returnFalse() {
+ return false;
+ }
+
+ /**
+ * 创建dom
+ *
+ * @inner
+ * @param {string} id dom id 待用
+ * @param {string} type dom type,such as canvas, div etc.
+ * @param {Painter} painter painter instance
+ * @param {number} number
+ */
+ function createDom(id, type, painter, dpr) {
+ var newDom = document.createElement(type);
+ var width = painter.getWidth();
+ var height = painter.getHeight();
+
+ var newDomStyle = newDom.style;
+ // 没append呢,请原谅我这样写,清晰~
+ newDomStyle.position = 'absolute';
+ newDomStyle.left = 0;
+ newDomStyle.top = 0;
+ newDomStyle.width = width + 'px';
+ newDomStyle.height = height + 'px';
+ newDom.width = width * dpr;
+ newDom.height = height * dpr;
+
+ // id不作为索引用,避免可能造成的重名,定义为私有属性
+ newDom.setAttribute('data-zr-dom-id', id);
+ return newDom;
+ }
+
+ /**
+ * @alias module:zrender/Layer
+ * @constructor
+ * @extends module:zrender/mixin/Transformable
+ * @param {string} id
+ * @param {module:zrender/Painter} painter
+ * @param {number} [dpr]
+ */
+ var Layer = function(id, painter, dpr) {
+ var dom;
+ dpr = dpr || config.devicePixelRatio;
+ if (typeof id === 'string') {
+ dom = createDom(id, 'canvas', painter, dpr);
+ }
+ // Not using isDom because in node it will return false
+ else if (util.isObject(id)) {
+ dom = id;
+ id = dom.id;
+ }
+ this.id = id;
+ this.dom = dom;
+
+ var domStyle = dom.style;
+ if (domStyle) { // Not in node
+ dom.onselectstart = returnFalse; // 避免页面选中的尴尬
+ domStyle['-webkit-user-select'] = 'none';
+ domStyle['user-select'] = 'none';
+ domStyle['-webkit-touch-callout'] = 'none';
+ domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';
+ domStyle['padding'] = 0;
+ domStyle['margin'] = 0;
+ domStyle['border-width'] = 0;
+ }
+
+ this.domBack = null;
+ this.ctxBack = null;
+
+ this.painter = painter;
+
+ this.config = null;
+
+ // Configs
+ /**
+ * 每次清空画布的颜色
+ * @type {string}
+ * @default 0
+ */
+ this.clearColor = 0;
+ /**
+ * 是否开启动态模糊
+ * @type {boolean}
+ * @default false
+ */
+ this.motionBlur = false;
+ /**
+ * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
+ * @type {number}
+ * @default 0.7
+ */
+ this.lastFrameAlpha = 0.7;
+
+ /**
+ * Layer dpr
+ * @type {number}
+ */
+ this.dpr = dpr;
+ };
+
+ Layer.prototype = {
+
+ constructor: Layer,
+
+ elCount: 0,
+
+ __dirty: true,
+
+ initContext: function () {
+ this.ctx = this.dom.getContext('2d');
+
+ this.ctx.dpr = this.dpr;
+ },
+
+ createBackBuffer: function () {
+ var dpr = this.dpr;
+
+ this.domBack = createDom('back-' + this.id, 'canvas', this.painter, dpr);
+ this.ctxBack = this.domBack.getContext('2d');
+
+ if (dpr != 1) {
+ this.ctxBack.scale(dpr, dpr);
+ }
+ },
+
+ /**
+ * @param {number} width
+ * @param {number} height
+ */
+ resize: function (width, height) {
+ var dpr = this.dpr;
+
+ var dom = this.dom;
+ var domStyle = dom.style;
+ var domBack = this.domBack;
+
+ domStyle.width = width + 'px';
+ domStyle.height = height + 'px';
+
+ dom.width = width * dpr;
+ dom.height = height * dpr;
+
+ if (domBack) {
+ domBack.width = width * dpr;
+ domBack.height = height * dpr;
+
+ if (dpr != 1) {
+ this.ctxBack.scale(dpr, dpr);
+ }
+ }
+ },
+
+ /**
+ * 清空该层画布
+ * @param {boolean} clearAll Clear all with out motion blur
+ */
+ clear: function (clearAll) {
+ var dom = this.dom;
+ var ctx = this.ctx;
+ var width = dom.width;
+ var height = dom.height;
+
+ var clearColor = this.clearColor;
+ var haveMotionBLur = this.motionBlur && !clearAll;
+ var lastFrameAlpha = this.lastFrameAlpha;
+
+ var dpr = this.dpr;
+
+ if (haveMotionBLur) {
+ if (!this.domBack) {
+ this.createBackBuffer();
+ }
+
+ this.ctxBack.globalCompositeOperation = 'copy';
+ this.ctxBack.drawImage(
+ dom, 0, 0,
+ width / dpr,
+ height / dpr
+ );
+ }
+
+ ctx.clearRect(0, 0, width, height);
+ if (clearColor) {
+ var clearColorGradientOrPattern;
+ // Gradient
+ if (clearColor.colorStops) {
+ // Cache canvas gradient
+ clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {
+ x: 0,
+ y: 0,
+ width: width,
+ height: height
+ });
+
+ clearColor.__canvasGradient = clearColorGradientOrPattern;
+ }
+ // Pattern
+ else if (clearColor.image) {
+ clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);
+ }
+ ctx.save();
+ ctx.fillStyle = clearColorGradientOrPattern || clearColor;
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+ }
+
+ if (haveMotionBLur) {
+ var domBack = this.domBack;
+ ctx.save();
+ ctx.globalAlpha = lastFrameAlpha;
+ ctx.drawImage(domBack, 0, 0, width, height);
+ ctx.restore();
+ }
+ }
+ };
+
+ module.exports = Layer;
+
+
+/***/ },
+/* 94 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ var Gradient = __webpack_require__(66);
+ module.exports = function (ecModel) {
+ function encodeColor(seriesModel) {
+ var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.normal.color').split('.');
+ var data = seriesModel.getData();
+ var color = seriesModel.get(colorAccessPath) // Set in itemStyle
+ || seriesModel.getColorFromPalette(seriesModel.get('name')); // Default color
+
+ // FIXME Set color function or use the platte color
+ data.setVisual('color', color);
+
+ // Only visible series has each data be visual encoded
+ if (!ecModel.isSeriesFiltered(seriesModel)) {
+ if (typeof color === 'function' && !(color instanceof Gradient)) {
+ data.each(function (idx) {
+ data.setItemVisual(
+ idx, 'color', color(seriesModel.getDataParams(idx))
+ );
+ });
+ }
+
+ // itemStyle in each data item
+ data.each(function (idx) {
+ var itemModel = data.getItemModel(idx);
+ var color = itemModel.get(colorAccessPath, true);
+ if (color != null) {
+ data.setItemVisual(idx, 'color', color);
+ }
+ });
+ }
+ }
+ ecModel.eachRawSeries(encodeColor);
+ };
+
+
+/***/ },
+/* 95 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // Compatitable with 2.0
+
+
+ var zrUtil = __webpack_require__(4);
+ var compatStyle = __webpack_require__(96);
+
+ function get(opt, path) {
+ path = path.split(',');
+ var obj = opt;
+ for (var i = 0; i < path.length; i++) {
+ obj = obj && obj[path[i]];
+ if (obj == null) {
+ break;
+ }
+ }
+ return obj;
+ }
+
+ function set(opt, path, val, overwrite) {
+ path = path.split(',');
+ var obj = opt;
+ var key;
+ for (var i = 0; i < path.length - 1; i++) {
+ key = path[i];
+ if (obj[key] == null) {
+ obj[key] = {};
+ }
+ obj = obj[key];
+ }
+ if (overwrite || obj[path[i]] == null) {
+ obj[path[i]] = val;
+ }
+ }
+
+ function compatLayoutProperties(option) {
+ each(LAYOUT_PROPERTIES, function (prop) {
+ if (prop[0] in option && !(prop[1] in option)) {
+ option[prop[1]] = option[prop[0]];
+ }
+ });
+ }
+
+ var LAYOUT_PROPERTIES = [
+ ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']
+ ];
+
+ var COMPATITABLE_COMPONENTS = [
+ 'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'
+ ];
+
+ var COMPATITABLE_SERIES = [
+ 'bar', 'boxplot', 'candlestick', 'chord', 'effectScatter',
+ 'funnel', 'gauge', 'lines', 'graph', 'heatmap', 'line', 'map', 'parallel',
+ 'pie', 'radar', 'sankey', 'scatter', 'treemap'
+ ];
+
+ var each = zrUtil.each;
+
+ module.exports = function (option) {
+ each(option.series, function (seriesOpt) {
+ if (!zrUtil.isObject(seriesOpt)) {
+ return;
+ }
+
+ var seriesType = seriesOpt.type;
+
+ compatStyle(seriesOpt);
+
+ if (seriesType === 'pie' || seriesType === 'gauge') {
+ if (seriesOpt.clockWise != null) {
+ seriesOpt.clockwise = seriesOpt.clockWise;
+ }
+ }
+ if (seriesType === 'gauge') {
+ var pointerColor = get(seriesOpt, 'pointer.color');
+ pointerColor != null
+ && set(seriesOpt, 'itemStyle.normal.color', pointerColor);
+ }
+
+ for (var i = 0; i < COMPATITABLE_SERIES.length; i++) {
+ if (COMPATITABLE_SERIES[i] === seriesOpt.type) {
+ compatLayoutProperties(seriesOpt);
+ break;
+ }
+ }
+ });
+
+ // dataRange has changed to visualMap
+ if (option.dataRange) {
+ option.visualMap = option.dataRange;
+ }
+
+ each(COMPATITABLE_COMPONENTS, function (componentName) {
+ var options = option[componentName];
+ if (options) {
+ if (!zrUtil.isArray(options)) {
+ options = [options];
+ }
+ each(options, function (option) {
+ compatLayoutProperties(option);
+ });
+ }
+ });
+ };
+
+
+/***/ },
+/* 96 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var zrUtil = __webpack_require__(4);
+
+ var POSSIBLE_STYLES = [
+ 'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',
+ 'chordStyle', 'label', 'labelLine'
+ ];
+
+ function compatItemStyle(opt) {
+ var itemStyleOpt = opt && opt.itemStyle;
+ if (itemStyleOpt) {
+ zrUtil.each(POSSIBLE_STYLES, function (styleName) {
+ var normalItemStyleOpt = itemStyleOpt.normal;
+ var emphasisItemStyleOpt = itemStyleOpt.emphasis;
+ if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {
+ opt[styleName] = opt[styleName] || {};
+ if (!opt[styleName].normal) {
+ opt[styleName].normal = normalItemStyleOpt[styleName];
+ }
+ else {
+ zrUtil.merge(opt[styleName].normal, normalItemStyleOpt[styleName]);
+ }
+ normalItemStyleOpt[styleName] = null;
+ }
+ if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {
+ opt[styleName] = opt[styleName] || {};
+ if (!opt[styleName].emphasis) {
+ opt[styleName].emphasis = emphasisItemStyleOpt[styleName];
+ }
+ else {
+ zrUtil.merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);
+ }
+ emphasisItemStyleOpt[styleName] = null;
+ }
+ });
+ }
+ }
+
+ module.exports = function (seriesOpt) {
+ if (!seriesOpt) {
+ return;
+ }
+ compatItemStyle(seriesOpt);
+ compatItemStyle(seriesOpt.markPoint);
+ compatItemStyle(seriesOpt.markLine);
+ var data = seriesOpt.data;
+ if (data) {
+ for (var i = 0; i < data.length; i++) {
+ compatItemStyle(data[i]);
+ }
+ // mark point data
+ var markPoint = seriesOpt.markPoint;
+ if (markPoint && markPoint.data) {
+ var mpData = markPoint.data;
+ for (var i = 0; i < mpData.length; i++) {
+ compatItemStyle(mpData[i]);
+ }
+ }
+ // mark line data
+ var markLine = seriesOpt.markLine;
+ if (markLine && markLine.data) {
+ var mlData = markLine.data;
+ for (var i = 0; i < mlData.length; i++) {
+ if (zrUtil.isArray(mlData[i])) {
+ compatItemStyle(mlData[i][0]);
+ compatItemStyle(mlData[i][1]);
+ }
+ else {
+ compatItemStyle(mlData[i]);
+ }
+ }
+ }
+ }
+ };
+
+
+/***/ },
+/* 97 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var graphic = __webpack_require__(18);
+ var zrUtil = __webpack_require__(4);
+ var PI = Math.PI;
+ /**
+ * @param {module:echarts/ExtensionAPI} api
+ * @param {Object} [opts]
+ * @param {string} [opts.text]
+ * @param {string} [opts.color]
+ * @param {string} [opts.textColor]
+ * @return {module:zrender/Element}
+ */
+ module.exports = function (api, opts) {
+ opts = opts || {};
+ zrUtil.defaults(opts, {
+ text: 'loading',
+ color: '#c23531',
+ textColor: '#000',
+ maskColor: 'rgba(255, 255, 255, 0.8)',
+ zlevel: 0
+ });
+ var mask = new graphic.Rect({
+ style: {
+ fill: opts.maskColor
+ },
+ zlevel: opts.zlevel,
+ z: 10000
+ });
+ var arc = new graphic.Arc({
+ shape: {
+ startAngle: -PI / 2,
+ endAngle: -PI / 2 + 0.1,
+ r: 10
+ },
+ style: {
+ stroke: opts.color,
+ lineCap: 'round',
+ lineWidth: 5
+ },
+ zlevel: opts.zlevel,
+ z: 10001
+ });
+ var labelRect = new graphic.Rect({
+ style: {
+ fill: 'none',
+ text: opts.text,
+ textPosition: 'right',
+ textDistance: 10,
+ textFill: opts.textColor
+ },
+ zlevel: opts.zlevel,
+ z: 10001
+ });
+
+ arc.animateShape(true)
+ .when(1000, {
+ endAngle: PI * 3 / 2
+ })
+ .start('circularInOut');
+ arc.animateShape(true)
+ .when(1000, {
+ startAngle: PI * 3 / 2
+ })
+ .delay(300)
+ .start('circularInOut');
+
+ var group = new graphic.Group();
+ group.add(arc);
+ group.add(labelRect);
+ group.add(mask);
+ // Inject resize
+ group.resize = function () {
+ var cx = api.getWidth() / 2;
+ var cy = api.getHeight() / 2;
+ arc.setShape({
+ cx: cx,
+ cy: cy
+ });
+ var r = arc.shape.r;
+ labelRect.setShape({
+ x: cx - r,
+ y: cy - r,
+ width: r * 2,
+ height: r * 2
+ });
+
+ mask.setShape({
+ x: 0,
+ y: 0,
+ width: api.getWidth(),
+ height: api.getHeight()
+ });
+ };
+ group.resize();
+ return group;
+ };
+
+
+/***/ },
+/* 98 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(global) {/**
+ * List for data storage
+ * @module echarts/data/List
+ */
+
+
+ var UNDEFINED = 'undefined';
+ var globalObj = typeof window === 'undefined' ? global : window;
+ var Float64Array = typeof globalObj.Float64Array === UNDEFINED
+ ? Array : globalObj.Float64Array;
+ var Int32Array = typeof globalObj.Int32Array === UNDEFINED
+ ? Array : globalObj.Int32Array;
+
+ var dataCtors = {
+ 'float': Float64Array,
+ 'int': Int32Array,
+ // Ordinal data type can be string or int
+ 'ordinal': Array,
+ 'number': Array,
+ 'time': Array
+ };
+
+ var Model = __webpack_require__(12);
+ var DataDiffer = __webpack_require__(99);
+
+ var zrUtil = __webpack_require__(4);
+ var modelUtil = __webpack_require__(5);
+ var isObject = zrUtil.isObject;
+
+ var TRANSFERABLE_PROPERTIES = [
+ 'stackedOn', 'hasItemOption', '_nameList', '_idList', '_rawData'
+ ];
+
+ function transferProperties(a, b) {
+ zrUtil.each(TRANSFERABLE_PROPERTIES.concat(b.__wrappedMethods || []), function (propName) {
+ if (b.hasOwnProperty(propName)) {
+ a[propName] = b[propName];
+ }
+ });
+
+ a.__wrappedMethods = b.__wrappedMethods;
+ }
+
+ function DefaultDataProvider(dataArray) {
+ this._array = dataArray || [];
+ }
+
+ DefaultDataProvider.prototype.pure = false;
+
+ DefaultDataProvider.prototype.count = function () {
+ return this._array.length;
+ };
+ DefaultDataProvider.prototype.getItem = function (idx) {
+ return this._array[idx];
+ };
+
+ /**
+ * @constructor
+ * @alias module:echarts/data/List
+ *
+ * @param {Array.} dimensions
+ * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
+ * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
+ * @param {module:echarts/model/Model} hostModel
+ */
+ var List = function (dimensions, hostModel) {
+
+ dimensions = dimensions || ['x', 'y'];
+
+ var dimensionInfos = {};
+ var dimensionNames = [];
+ for (var i = 0; i < dimensions.length; i++) {
+ var dimensionName;
+ var dimensionInfo = {};
+ if (typeof dimensions[i] === 'string') {
+ dimensionName = dimensions[i];
+ dimensionInfo = {
+ name: dimensionName,
+ coordDim: dimensionName,
+ coordDimIndex: 0,
+ stackable: false,
+ // Type can be 'float', 'int', 'number'
+ // Default is number, Precision of float may not enough
+ type: 'number'
+ };
+ }
+ else {
+ dimensionInfo = dimensions[i];
+ dimensionName = dimensionInfo.name;
+ dimensionInfo.type = dimensionInfo.type || 'number';
+ if (!dimensionInfo.coordDim) {
+ dimensionInfo.coordDim = dimensionName;
+ dimensionInfo.coordDimIndex = 0;
+ }
+ }
+ dimensionInfo.otherDims = dimensionInfo.otherDims || {};
+ dimensionNames.push(dimensionName);
+ dimensionInfos[dimensionName] = dimensionInfo;
+ }
+
+ /**
+ * @readOnly
+ * @type {Array.}
+ */
+ this.dimensions = dimensionNames;
+
+ /**
+ * Infomation of each data dimension, like data type.
+ * @type {Object}
+ */
+ this._dimensionInfos = dimensionInfos;
+
+ /**
+ * @type {module:echarts/model/Model}
+ */
+ this.hostModel = hostModel;
+
+ /**
+ * @type {module:echarts/model/Model}
+ */
+ this.dataType;
+
+ /**
+ * Indices stores the indices of data subset after filtered.
+ * This data subset will be used in chart.
+ * @type {Array.}
+ * @readOnly
+ */
+ this.indices = [];
+
+ /**
+ * Data storage
+ * @type {Object.}
+ * @private
+ */
+ this._storage = {};
+
+ /**
+ * @type {Array.}
+ */
+ this._nameList = [];
+ /**
+ * @type {Array.}
+ */
+ this._idList = [];
+
+ /**
+ * Models of data option is stored sparse for optimizing memory cost
+ * @type {Array.}
+ * @private
+ */
+ this._optionModels = [];
+
+ /**
+ * @param {module:echarts/data/List}
+ */
+ this.stackedOn = null;
+
+ /**
+ * Global visual properties after visual coding
+ * @type {Object}
+ * @private
+ */
+ this._visual = {};
+
+ /**
+ * Globel layout properties.
+ * @type {Object}
+ * @private
+ */
+ this._layout = {};
+
+ /**
+ * Item visual properties after visual coding
+ * @type {Array.}
+ * @private
+ */
+ this._itemVisuals = [];
+
+ /**
+ * Item layout properties after layout
+ * @type {Array.}
+ * @private
+ */
+ this._itemLayouts = [];
+
+ /**
+ * Graphic elemnents
+ * @type {Array.}
+ * @private
+ */
+ this._graphicEls = [];
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this._rawData;
+
+ /**
+ * @type {Object}
+ * @private
+ */
+ this._extent;
+ };
+
+ var listProto = List.prototype;
+
+ listProto.type = 'list';
+
+ /**
+ * If each data item has it's own option
+ * @type {boolean}
+ */
+ listProto.hasItemOption = true;
+
+ /**
+ * Get dimension name
+ * @param {string|number} dim
+ * Dimension can be concrete names like x, y, z, lng, lat, angle, radius
+ * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
+ * @return {string} Concrete dim name.
+ */
+ listProto.getDimension = function (dim) {
+ if (!isNaN(dim)) {
+ dim = this.dimensions[dim] || dim;
+ }
+ return dim;
+ };
+
+ /**
+ * Get type and stackable info of particular dimension
+ * @param {string|number} dim
+ * Dimension can be concrete names like x, y, z, lng, lat, angle, radius
+ * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
+ */
+ listProto.getDimensionInfo = function (dim) {
+ return zrUtil.clone(this._dimensionInfos[this.getDimension(dim)]);
+ };
+
+ /**
+ * Initialize from data
+ * @param {Array.} data
+ * @param {Array.} [nameList]
+ * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number
+ */
+ listProto.initData = function (data, nameList, dimValueGetter) {
+ data = data || [];
+
+ var isDataArray = zrUtil.isArray(data);
+ if (isDataArray) {
+ data = new DefaultDataProvider(data);
+ }
+ if (true) {
+ if (!isDataArray && (typeof data.getItem != 'function' || typeof data.count != 'function')) {
+ throw new Error('Inavlid data provider.');
+ }
+ }
+
+ this._rawData = data;
+
+ // Clear
+ var storage = this._storage = {};
+ var indices = this.indices = [];
+
+ var dimensions = this.dimensions;
+ var dimensionInfoMap = this._dimensionInfos;
+
+ var size = data.count();
+
+ var idList = [];
+ var nameRepeatCount = {};
+ var nameDimIdx;
+
+ nameList = nameList || [];
+
+ // Init storage
+ for (var i = 0; i < dimensions.length; i++) {
+ var dimInfo = dimensionInfoMap[dimensions[i]];
+ dimInfo.otherDims.itemName === 0 && (nameDimIdx = i);
+ var DataCtor = dataCtors[dimInfo.type];
+ storage[dimensions[i]] = new DataCtor(size);
+ }
+
+ var self = this;
+ if (!dimValueGetter) {
+ self.hasItemOption = false;
+ }
+ // Default dim value getter
+ dimValueGetter = dimValueGetter || function (dataItem, dimName, dataIndex, dimIndex) {
+ var value = modelUtil.getDataItemValue(dataItem);
+ // If any dataItem is like { value: 10 }
+ if (modelUtil.isDataItemOption(dataItem)) {
+ self.hasItemOption = true;
+ }
+ return modelUtil.converDataValue(
+ (value instanceof Array)
+ ? value[dimIndex]
+ // If value is a single number or something else not array.
+ : value,
+ dimensionInfoMap[dimName]
+ );
+ };
+
+ for (var i = 0; i < size; i++) {
+ // NOTICE: Try not to write things into dataItem
+ var dataItem = data.getItem(i);
+ // Each data item is value
+ // [1, 2]
+ // 2
+ // Bar chart, line chart which uses category axis
+ // only gives the 'y' value. 'x' value is the indices of cateogry
+ // Use a tempValue to normalize the value to be a (x, y) value
+
+ // Store the data by dimensions
+ for (var k = 0; k < dimensions.length; k++) {
+ var dim = dimensions[k];
+ var dimStorage = storage[dim];
+ // PENDING NULL is empty or zero
+ dimStorage[i] = dimValueGetter(dataItem, dim, i, k);
+ }
+
+ indices.push(i);
+ }
+
+ // Use the name in option and create id
+ for (var i = 0; i < size; i++) {
+ var dataItem = data.getItem(i);
+ if (!nameList[i] && dataItem) {
+ if (dataItem.name != null) {
+ nameList[i] = dataItem.name;
+ }
+ else if (nameDimIdx != null) {
+ nameList[i] = storage[dimensions[nameDimIdx]][i];
+ }
+ }
+ var name = nameList[i] || '';
+ // Try using the id in option
+ var id = dataItem && dataItem.id;
+
+ if (!id && name) {
+ // Use name as id and add counter to avoid same name
+ nameRepeatCount[name] = nameRepeatCount[name] || 0;
+ id = name;
+ if (nameRepeatCount[name] > 0) {
+ id += '__ec__' + nameRepeatCount[name];
+ }
+ nameRepeatCount[name]++;
+ }
+ id && (idList[i] = id);
+ }
+
+ this._nameList = nameList;
+ this._idList = idList;
+ };
+
+ /**
+ * @return {number}
+ */
+ listProto.count = function () {
+ return this.indices.length;
+ };
+
+ /**
+ * Get value. Return NaN if idx is out of range.
+ * @param {string} dim Dim must be concrete name.
+ * @param {number} idx
+ * @param {boolean} stack
+ * @return {number}
+ */
+ listProto.get = function (dim, idx, stack) {
+ var storage = this._storage;
+ var dataIndex = this.indices[idx];
+
+ // If value not exists
+ if (dataIndex == null || !storage[dim]) {
+ return NaN;
+ }
+
+ var value = storage[dim][dataIndex];
+ // FIXME ordinal data type is not stackable
+ if (stack) {
+ var dimensionInfo = this._dimensionInfos[dim];
+ if (dimensionInfo && dimensionInfo.stackable) {
+ var stackedOn = this.stackedOn;
+ while (stackedOn) {
+ // Get no stacked data of stacked on
+ var stackedValue = stackedOn.get(dim, idx);
+ // Considering positive stack, negative stack and empty data
+ if ((value >= 0 && stackedValue > 0) // Positive stack
+ || (value <= 0 && stackedValue < 0) // Negative stack
+ ) {
+ value += stackedValue;
+ }
+ stackedOn = stackedOn.stackedOn;
+ }
+ }
+ }
+ return value;
+ };
+
+ /**
+ * Get value for multi dimensions.
+ * @param {Array.} [dimensions] If ignored, using all dimensions.
+ * @param {number} idx
+ * @param {boolean} stack
+ * @return {number}
+ */
+ listProto.getValues = function (dimensions, idx, stack) {
+ var values = [];
+
+ if (!zrUtil.isArray(dimensions)) {
+ stack = idx;
+ idx = dimensions;
+ dimensions = this.dimensions;
+ }
+
+ for (var i = 0, len = dimensions.length; i < len; i++) {
+ values.push(this.get(dimensions[i], idx, stack));
+ }
+
+ return values;
+ };
+
+ /**
+ * If value is NaN. Inlcuding '-'
+ * @param {string} dim
+ * @param {number} idx
+ * @return {number}
+ */
+ listProto.hasValue = function (idx) {
+ var dimensions = this.dimensions;
+ var dimensionInfos = this._dimensionInfos;
+ for (var i = 0, len = dimensions.length; i < len; i++) {
+ if (
+ // Ordinal type can be string or number
+ dimensionInfos[dimensions[i]].type !== 'ordinal'
+ && isNaN(this.get(dimensions[i], idx))
+ ) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /**
+ * Get extent of data in one dimension
+ * @param {string} dim
+ * @param {boolean} stack
+ * @param {Function} filter
+ */
+ listProto.getDataExtent = function (dim, stack, filter) {
+ dim = this.getDimension(dim);
+ var dimData = this._storage[dim];
+ var dimInfo = this.getDimensionInfo(dim);
+ stack = (dimInfo && dimInfo.stackable) && stack;
+ var dimExtent = (this._extent || (this._extent = {}))[dim + (!!stack)];
+ var value;
+ if (dimExtent) {
+ return dimExtent;
+ }
+ // var dimInfo = this._dimensionInfos[dim];
+ if (dimData) {
+ var min = Infinity;
+ var max = -Infinity;
+ // var isOrdinal = dimInfo.type === 'ordinal';
+ for (var i = 0, len = this.count(); i < len; i++) {
+ value = this.get(dim, i, stack);
+ // FIXME
+ // if (isOrdinal && typeof value === 'string') {
+ // value = zrUtil.indexOf(dimData, value);
+ // }
+ if (!filter || filter(value, dim, i)) {
+ value < min && (min = value);
+ value > max && (max = value);
+ }
+ }
+ return (this._extent[dim + !!stack] = [min, max]);
+ }
+ else {
+ return [Infinity, -Infinity];
+ }
+ };
+
+ /**
+ * Get sum of data in one dimension
+ * @param {string} dim
+ * @param {boolean} stack
+ */
+ listProto.getSum = function (dim, stack) {
+ var dimData = this._storage[dim];
+ var sum = 0;
+ if (dimData) {
+ for (var i = 0, len = this.count(); i < len; i++) {
+ var value = this.get(dim, i, stack);
+ if (!isNaN(value)) {
+ sum += value;
+ }
+ }
+ }
+ return sum;
+ };
+
+ /**
+ * Retreive the index with given value
+ * @param {number} idx
+ * @param {number} value
+ * @return {number}
+ */
+ // FIXME Precision of float value
+ listProto.indexOf = function (dim, value) {
+ var storage = this._storage;
+ var dimData = storage[dim];
+ var indices = this.indices;
+
+ if (dimData) {
+ for (var i = 0, len = indices.length; i < len; i++) {
+ var rawIndex = indices[i];
+ if (dimData[rawIndex] === value) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Retreive the index with given name
+ * @param {number} idx
+ * @param {number} name
+ * @return {number}
+ */
+ listProto.indexOfName = function (name) {
+ var indices = this.indices;
+ var nameList = this._nameList;
+
+ for (var i = 0, len = indices.length; i < len; i++) {
+ var rawIndex = indices[i];
+ if (nameList[rawIndex] === name) {
+ return i;
+ }
+ }
+
+ return -1;
+ };
+
+ /**
+ * Retreive the index with given raw data index
+ * @param {number} idx
+ * @param {number} name
+ * @return {number}
+ */
+ listProto.indexOfRawIndex = function (rawIndex) {
+ // Indices are ascending
+ var indices = this.indices;
+
+ // If rawIndex === dataIndex
+ var rawDataIndex = indices[rawIndex];
+ if (rawDataIndex != null && rawDataIndex === rawIndex) {
+ return rawIndex;
+ }
+
+ var left = 0;
+ var right = indices.length - 1;
+ while (left <= right) {
+ var mid = (left + right) / 2 | 0;
+ if (indices[mid] < rawIndex) {
+ left = mid + 1;
+ }
+ else if (indices[mid] > rawIndex) {
+ right = mid - 1;
+ }
+ else {
+ return mid;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Retreive the index of nearest value
+ * @param {string} dim
+ * @param {number} value
+ * @param {boolean} stack If given value is after stacked
+ * @param {number} [maxDistance=Infinity]
+ * @return {Array.} Considere multiple points has the same value.
+ */
+ listProto.indicesOfNearest = function (dim, value, stack, maxDistance) {
+ var storage = this._storage;
+ var dimData = storage[dim];
+ var nearestIndices = [];
+
+ if (!dimData) {
+ return nearestIndices;
+ }
+
+ if (maxDistance == null) {
+ maxDistance = Infinity;
+ }
+
+ var minDist = Number.MAX_VALUE;
+ var minDiff = -1;
+ for (var i = 0, len = this.count(); i < len; i++) {
+ var diff = value - this.get(dim, i, stack);
+ var dist = Math.abs(diff);
+ if (diff <= maxDistance && dist <= minDist) {
+ // For the case of two data are same on xAxis, which has sequence data.
+ // Show the nearest index
+ // https://github.com/ecomfe/echarts/issues/2869
+ if (dist < minDist || (diff >= 0 && minDiff < 0)) {
+ minDist = dist;
+ minDiff = diff;
+ nearestIndices.length = 0;
+ }
+ nearestIndices.push(i);
+ }
+ }
+ return nearestIndices;
+ };
+
+ /**
+ * Get raw data index
+ * @param {number} idx
+ * @return {number}
+ */
+ listProto.getRawIndex = function (idx) {
+ var rawIdx = this.indices[idx];
+ return rawIdx == null ? -1 : rawIdx;
+ };
+
+ /**
+ * Get raw data item
+ * @param {number} idx
+ * @return {number}
+ */
+ listProto.getRawDataItem = function (idx) {
+ return this._rawData.getItem(this.getRawIndex(idx));
+ };
+
+ /**
+ * @param {number} idx
+ * @param {boolean} [notDefaultIdx=false]
+ * @return {string}
+ */
+ listProto.getName = function (idx) {
+ return this._nameList[this.indices[idx]] || '';
+ };
+
+ /**
+ * @param {number} idx
+ * @param {boolean} [notDefaultIdx=false]
+ * @return {string}
+ */
+ listProto.getId = function (idx) {
+ return this._idList[this.indices[idx]] || (this.getRawIndex(idx) + '');
+ };
+
+
+ function normalizeDimensions(dimensions) {
+ if (!zrUtil.isArray(dimensions)) {
+ dimensions = [dimensions];
+ }
+ return dimensions;
+ }
+
+ /**
+ * Data iteration
+ * @param {string|Array.}
+ * @param {Function} cb
+ * @param {boolean} [stack=false]
+ * @param {*} [context=this]
+ *
+ * @example
+ * list.each('x', function (x, idx) {});
+ * list.each(['x', 'y'], function (x, y, idx) {});
+ * list.each(function (idx) {})
+ */
+ listProto.each = function (dims, cb, stack, context) {
+ if (typeof dims === 'function') {
+ context = stack;
+ stack = cb;
+ cb = dims;
+ dims = [];
+ }
+
+ dims = zrUtil.map(normalizeDimensions(dims), this.getDimension, this);
+
+ var value = [];
+ var dimSize = dims.length;
+ var indices = this.indices;
+
+ context = context || this;
+
+ for (var i = 0; i < indices.length; i++) {
+ // Simple optimization
+ switch (dimSize) {
+ case 0:
+ cb.call(context, i);
+ break;
+ case 1:
+ cb.call(context, this.get(dims[0], i, stack), i);
+ break;
+ case 2:
+ cb.call(context, this.get(dims[0], i, stack), this.get(dims[1], i, stack), i);
+ break;
+ default:
+ for (var k = 0; k < dimSize; k++) {
+ value[k] = this.get(dims[k], i, stack);
+ }
+ // Index
+ value[k] = i;
+ cb.apply(context, value);
+ }
+ }
+ };
+
+ /**
+ * Data filter
+ * @param {string|Array.}
+ * @param {Function} cb
+ * @param {boolean} [stack=false]
+ * @param {*} [context=this]
+ */
+ listProto.filterSelf = function (dimensions, cb, stack, context) {
+ if (typeof dimensions === 'function') {
+ context = stack;
+ stack = cb;
+ cb = dimensions;
+ dimensions = [];
+ }
+
+ dimensions = zrUtil.map(
+ normalizeDimensions(dimensions), this.getDimension, this
+ );
+
+ var newIndices = [];
+ var value = [];
+ var dimSize = dimensions.length;
+ var indices = this.indices;
+
+ context = context || this;
+
+ for (var i = 0; i < indices.length; i++) {
+ var keep;
+ // Simple optimization
+ if (!dimSize) {
+ keep = cb.call(context, i);
+ }
+ else if (dimSize === 1) {
+ keep = cb.call(
+ context, this.get(dimensions[0], i, stack), i
+ );
+ }
+ else {
+ for (var k = 0; k < dimSize; k++) {
+ value[k] = this.get(dimensions[k], i, stack);
+ }
+ value[k] = i;
+ keep = cb.apply(context, value);
+ }
+ if (keep) {
+ newIndices.push(indices[i]);
+ }
+ }
+
+ this.indices = newIndices;
+
+ // Reset data extent
+ this._extent = {};
+
+ return this;
+ };
+
+ /**
+ * Data mapping to a plain array
+ * @param {string|Array.} [dimensions]
+ * @param {Function} cb
+ * @param {boolean} [stack=false]
+ * @param {*} [context=this]
+ * @return {Array}
+ */
+ listProto.mapArray = function (dimensions, cb, stack, context) {
+ if (typeof dimensions === 'function') {
+ context = stack;
+ stack = cb;
+ cb = dimensions;
+ dimensions = [];
+ }
+
+ var result = [];
+ this.each(dimensions, function () {
+ result.push(cb && cb.apply(this, arguments));
+ }, stack, context);
+ return result;
+ };
+
+ function cloneListForMapAndSample(original, excludeDimensions) {
+ var allDimensions = original.dimensions;
+ var list = new List(
+ zrUtil.map(allDimensions, original.getDimensionInfo, original),
+ original.hostModel
+ );
+ // FIXME If needs stackedOn, value may already been stacked
+ transferProperties(list, original);
+
+ var storage = list._storage = {};
+ var originalStorage = original._storage;
+ // Init storage
+ for (var i = 0; i < allDimensions.length; i++) {
+ var dim = allDimensions[i];
+ var dimStore = originalStorage[dim];
+ if (zrUtil.indexOf(excludeDimensions, dim) >= 0) {
+ storage[dim] = new dimStore.constructor(
+ originalStorage[dim].length
+ );
+ }
+ else {
+ // Direct reference for other dimensions
+ storage[dim] = originalStorage[dim];
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Data mapping to a new List with given dimensions
+ * @param {string|Array.} dimensions
+ * @param {Function} cb
+ * @param {boolean} [stack=false]
+ * @param {*} [context=this]
+ * @return {Array}
+ */
+ listProto.map = function (dimensions, cb, stack, context) {
+ dimensions = zrUtil.map(
+ normalizeDimensions(dimensions), this.getDimension, this
+ );
+
+ var list = cloneListForMapAndSample(this, dimensions);
+ // Following properties are all immutable.
+ // So we can reference to the same value
+ var indices = list.indices = this.indices;
+
+ var storage = list._storage;
+
+ var tmpRetValue = [];
+ this.each(dimensions, function () {
+ var idx = arguments[arguments.length - 1];
+ var retValue = cb && cb.apply(this, arguments);
+ if (retValue != null) {
+ // a number
+ if (typeof retValue === 'number') {
+ tmpRetValue[0] = retValue;
+ retValue = tmpRetValue;
+ }
+ for (var i = 0; i < retValue.length; i++) {
+ var dim = dimensions[i];
+ var dimStore = storage[dim];
+ var rawIdx = indices[idx];
+ if (dimStore) {
+ dimStore[rawIdx] = retValue[i];
+ }
+ }
+ }
+ }, stack, context);
+
+ return list;
+ };
+
+ /**
+ * Large data down sampling on given dimension
+ * @param {string} dimension
+ * @param {number} rate
+ * @param {Function} sampleValue
+ * @param {Function} sampleIndex Sample index for name and id
+ */
+ listProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {
+ var list = cloneListForMapAndSample(this, [dimension]);
+ var storage = this._storage;
+ var targetStorage = list._storage;
+
+ var originalIndices = this.indices;
+ var indices = list.indices = [];
+
+ var frameValues = [];
+ var frameIndices = [];
+ var frameSize = Math.floor(1 / rate);
+
+ var dimStore = targetStorage[dimension];
+ var len = this.count();
+ // Copy data from original data
+ for (var i = 0; i < storage[dimension].length; i++) {
+ targetStorage[dimension][i] = storage[dimension][i];
+ }
+ for (var i = 0; i < len; i += frameSize) {
+ // Last frame
+ if (frameSize > len - i) {
+ frameSize = len - i;
+ frameValues.length = frameSize;
+ }
+ for (var k = 0; k < frameSize; k++) {
+ var idx = originalIndices[i + k];
+ frameValues[k] = dimStore[idx];
+ frameIndices[k] = idx;
+ }
+ var value = sampleValue(frameValues);
+ var idx = frameIndices[sampleIndex(frameValues, value) || 0];
+ // Only write value on the filtered data
+ dimStore[idx] = value;
+ indices.push(idx);
+ }
+
+ return list;
+ };
+
+ /**
+ * Get model of one data item.
+ *
+ * @param {number} idx
+ */
+ // FIXME Model proxy ?
+ listProto.getItemModel = function (idx) {
+ var hostModel = this.hostModel;
+ idx = this.indices[idx];
+ return new Model(this._rawData.getItem(idx), hostModel, hostModel && hostModel.ecModel);
+ };
+
+ /**
+ * Create a data differ
+ * @param {module:echarts/data/List} otherList
+ * @return {module:echarts/data/DataDiffer}
+ */
+ listProto.diff = function (otherList) {
+ var idList = this._idList;
+ var otherIdList = otherList && otherList._idList;
+ var val;
+ // Use prefix to avoid index to be the same as otherIdList[idx],
+ // which will cause weird udpate animation.
+ var prefix = 'e\0\0';
+
+ return new DataDiffer(
+ otherList ? otherList.indices : [],
+ this.indices,
+ function (idx) {
+ return (val = otherIdList[idx]) != null ? val : prefix + idx;
+ },
+ function (idx) {
+ return (val = idList[idx]) != null ? val : prefix + idx;
+ }
+ );
+ };
+ /**
+ * Get visual property.
+ * @param {string} key
+ */
+ listProto.getVisual = function (key) {
+ var visual = this._visual;
+ return visual && visual[key];
+ };
+
+ /**
+ * Set visual property
+ * @param {string|Object} key
+ * @param {*} [value]
+ *
+ * @example
+ * setVisual('color', color);
+ * setVisual({
+ * 'color': color
+ * });
+ */
+ listProto.setVisual = function (key, val) {
+ if (isObject(key)) {
+ for (var name in key) {
+ if (key.hasOwnProperty(name)) {
+ this.setVisual(name, key[name]);
+ }
+ }
+ return;
+ }
+ this._visual = this._visual || {};
+ this._visual[key] = val;
+ };
+
+ /**
+ * Set layout property.
+ * @param {string} key
+ * @param {*} [val]
+ */
+ listProto.setLayout = function (key, val) {
+ if (isObject(key)) {
+ for (var name in key) {
+ if (key.hasOwnProperty(name)) {
+ this.setLayout(name, key[name]);
+ }
+ }
+ return;
+ }
+ this._layout[key] = val;
+ };
+
+ /**
+ * Get layout property.
+ * @param {string} key.
+ * @return {*}
+ */
+ listProto.getLayout = function (key) {
+ return this._layout[key];
+ };
+
+ /**
+ * Get layout of single data item
+ * @param {number} idx
+ */
+ listProto.getItemLayout = function (idx) {
+ return this._itemLayouts[idx];
+ };
+
+ /**
+ * Set layout of single data item
+ * @param {number} idx
+ * @param {Object} layout
+ * @param {boolean=} [merge=false]
+ */
+ listProto.setItemLayout = function (idx, layout, merge) {
+ this._itemLayouts[idx] = merge
+ ? zrUtil.extend(this._itemLayouts[idx] || {}, layout)
+ : layout;
+ };
+
+ /**
+ * Clear all layout of single data item
+ */
+ listProto.clearItemLayouts = function () {
+ this._itemLayouts.length = 0;
+ };
+
+ /**
+ * Get visual property of single data item
+ * @param {number} idx
+ * @param {string} key
+ * @param {boolean} [ignoreParent=false]
+ */
+ listProto.getItemVisual = function (idx, key, ignoreParent) {
+ var itemVisual = this._itemVisuals[idx];
+ var val = itemVisual && itemVisual[key];
+ if (val == null && !ignoreParent) {
+ // Use global visual property
+ return this.getVisual(key);
+ }
+ return val;
+ };
+
+ /**
+ * Set visual property of single data item
+ *
+ * @param {number} idx
+ * @param {string|Object} key
+ * @param {*} [value]
+ *
+ * @example
+ * setItemVisual(0, 'color', color);
+ * setItemVisual(0, {
+ * 'color': color
+ * });
+ */
+ listProto.setItemVisual = function (idx, key, value) {
+ var itemVisual = this._itemVisuals[idx] || {};
+ this._itemVisuals[idx] = itemVisual;
+
+ if (isObject(key)) {
+ for (var name in key) {
+ if (key.hasOwnProperty(name)) {
+ itemVisual[name] = key[name];
+ }
+ }
+ return;
+ }
+ itemVisual[key] = value;
+ };
+
+ /**
+ * Clear itemVisuals and list visual.
+ */
+ listProto.clearAllVisual = function () {
+ this._visual = {};
+ this._itemVisuals = [];
+ };
+
+ var setItemDataAndSeriesIndex = function (child) {
+ child.seriesIndex = this.seriesIndex;
+ child.dataIndex = this.dataIndex;
+ child.dataType = this.dataType;
+ };
+ /**
+ * Set graphic element relative to data. It can be set as null
+ * @param {number} idx
+ * @param {module:zrender/Element} [el]
+ */
+ listProto.setItemGraphicEl = function (idx, el) {
+ var hostModel = this.hostModel;
+
+ if (el) {
+ // Add data index and series index for indexing the data by element
+ // Useful in tooltip
+ el.dataIndex = idx;
+ el.dataType = this.dataType;
+ el.seriesIndex = hostModel && hostModel.seriesIndex;
+ if (el.type === 'group') {
+ el.traverse(setItemDataAndSeriesIndex, el);
+ }
+ }
+
+ this._graphicEls[idx] = el;
+ };
+
+ /**
+ * @param {number} idx
+ * @return {module:zrender/Element}
+ */
+ listProto.getItemGraphicEl = function (idx) {
+ return this._graphicEls[idx];
+ };
+
+ /**
+ * @param {Function} cb
+ * @param {*} context
+ */
+ listProto.eachItemGraphicEl = function (cb, context) {
+ zrUtil.each(this._graphicEls, function (el, idx) {
+ if (el) {
+ cb && cb.call(context, el, idx);
+ }
+ });
+ };
+
+ /**
+ * Shallow clone a new list except visual and layout properties, and graph elements.
+ * New list only change the indices.
+ */
+ listProto.cloneShallow = function () {
+ var dimensionInfoList = zrUtil.map(this.dimensions, this.getDimensionInfo, this);
+ var list = new List(dimensionInfoList, this.hostModel);
+
+ // FIXME
+ list._storage = this._storage;
+
+ transferProperties(list, this);
+
+
+ // Clone will not change the data extent and indices
+ list.indices = this.indices.slice();
+
+ if (this._extent) {
+ list._extent = zrUtil.extend({}, this._extent);
+ }
+
+ return list;
+ };
+
+ /**
+ * Wrap some method to add more feature
+ * @param {string} methodName
+ * @param {Function} injectFunction
+ */
+ listProto.wrapMethod = function (methodName, injectFunction) {
+ var originalMethod = this[methodName];
+ if (typeof originalMethod !== 'function') {
+ return;
+ }
+ this.__wrappedMethods = this.__wrappedMethods || [];
+ this.__wrappedMethods.push(methodName);
+ this[methodName] = function () {
+ var res = originalMethod.apply(this, arguments);
+ return injectFunction.apply(this, [res].concat(zrUtil.slice(arguments)));
+ };
+ };
+
+ // Methods that create a new list based on this list should be listed here.
+ // Notice that those method should `RETURN` the new list.
+ listProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];
+ // Methods that change indices of this list should be listed here.
+ listProto.CHANGABLE_METHODS = ['filterSelf'];
+
+ module.exports = List;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 99 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+
+ function defaultKeyGetter(item) {
+ return item;
+ }
+
+ function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter) {
+ this._old = oldArr;
+ this._new = newArr;
+
+ this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;
+ this._newKeyGetter = newKeyGetter || defaultKeyGetter;
+ }
+
+ DataDiffer.prototype = {
+
+ constructor: DataDiffer,
+
+ /**
+ * Callback function when add a data
+ */
+ add: function (func) {
+ this._add = func;
+ return this;
+ },
+
+ /**
+ * Callback function when update a data
+ */
+ update: function (func) {
+ this._update = func;
+ return this;
+ },
+
+ /**
+ * Callback function when remove a data
+ */
+ remove: function (func) {
+ this._remove = func;
+ return this;
+ },
+
+ execute: function () {
+ var oldArr = this._old;
+ var newArr = this._new;
+ var oldKeyGetter = this._oldKeyGetter;
+ var newKeyGetter = this._newKeyGetter;
+
+ var oldDataIndexMap = {};
+ var newDataIndexMap = {};
+ var oldDataKeyArr = [];
+ var newDataKeyArr = [];
+ var i;
+
+ initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, oldKeyGetter);
+ initIndexMap(newArr, newDataIndexMap, newDataKeyArr, newKeyGetter);
+
+ // Travel by inverted order to make sure order consistency
+ // when duplicate keys exists (consider newDataIndex.pop() below).
+ // For performance consideration, these code below do not look neat.
+ for (i = 0; i < oldArr.length; i++) {
+ var key = oldDataKeyArr[i];
+ var idx = newDataIndexMap[key];
+
+ // idx can never be empty array here. see 'set null' logic below.
+ if (idx != null) {
+ // Consider there is duplicate key (for example, use dataItem.name as key).
+ // We should make sure every item in newArr and oldArr can be visited.
+ var len = idx.length;
+ if (len) {
+ len === 1 && (newDataIndexMap[key] = null);
+ idx = idx.unshift();
+ }
+ else {
+ newDataIndexMap[key] = null;
+ }
+ this._update && this._update(idx, i);
+ }
+ else {
+ this._remove && this._remove(i);
+ }
+ }
+
+ for (var i = 0; i < newDataKeyArr.length; i++) {
+ var key = newDataKeyArr[i];
+ if (newDataIndexMap.hasOwnProperty(key)) {
+ var idx = newDataIndexMap[key];
+ if (idx == null) {
+ continue;
+ }
+ // idx can never be empty array here. see 'set null' logic above.
+ if (!idx.length) {
+ this._add && this._add(idx);
+ }
+ else {
+ for (var j = 0, len = idx.length; j < len; j++) {
+ this._add && this._add(idx[j]);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ function initIndexMap(arr, map, keyArr, keyGetter) {
+ for (var i = 0; i < arr.length; i++) {
+ // Add prefix to avoid conflict with Object.prototype.
+ var key = '_ec_' + keyGetter(arr[i], i);
+ var existence = map[key];
+ if (existence == null) {
+ keyArr.push(key);
+ map[key] = i;
+ }
+ else {
+ if (!existence.length) {
+ map[key] = existence = [existence];
+ }
+ existence.push(i);
+ }
+ }
+ }
+
+ module.exports = DataDiffer;
+
+
+/***/ },
+/* 100 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var numberUtil = __webpack_require__(7);
+ var linearMap = numberUtil.linearMap;
+ var zrUtil = __webpack_require__(4);
+ var axisHelper = __webpack_require__(101);
+
+ function fixExtentWithBands(extent, nTick) {
+ var size = extent[1] - extent[0];
+ var len = nTick;
+ var margin = size / len / 2;
+ extent[0] += margin;
+ extent[1] -= margin;
+ }
+
+ var normalizedExtent = [0, 1];
+ /**
+ * @name module:echarts/coord/CartesianAxis
+ * @constructor
+ */
+ var Axis = function (dim, scale, extent) {
+
+ /**
+ * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'
+ * @type {string}
+ */
+ this.dim = dim;
+
+ /**
+ * Axis scale
+ * @type {module:echarts/coord/scale/*}
+ */
+ this.scale = scale;
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this._extent = extent || [0, 0];
+
+ /**
+ * @type {boolean}
+ */
+ this.inverse = false;
+
+ /**
+ * Usually true when axis has a ordinal scale
+ * @type {boolean}
+ */
+ this.onBand = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this._labelInterval;
+ };
+
+ Axis.prototype = {
+
+ constructor: Axis,
+
+ /**
+ * If axis extent contain given coord
+ * @param {number} coord
+ * @return {boolean}
+ */
+ contain: function (coord) {
+ var extent = this._extent;
+ var min = Math.min(extent[0], extent[1]);
+ var max = Math.max(extent[0], extent[1]);
+ return coord >= min && coord <= max;
+ },
+
+ /**
+ * If axis extent contain given data
+ * @param {number} data
+ * @return {boolean}
+ */
+ containData: function (data) {
+ return this.contain(this.dataToCoord(data));
+ },
+
+ /**
+ * Get coord extent.
+ * @return {Array.}
+ */
+ getExtent: function () {
+ return this._extent.slice();
+ },
+
+ /**
+ * Get precision used for formatting
+ * @param {Array.} [dataExtent]
+ * @return {number}
+ */
+ getPixelPrecision: function (dataExtent) {
+ return numberUtil.getPixelPrecision(
+ dataExtent || this.scale.getExtent(),
+ this._extent
+ );
+ },
+
+ /**
+ * Set coord extent
+ * @param {number} start
+ * @param {number} end
+ */
+ setExtent: function (start, end) {
+ var extent = this._extent;
+ extent[0] = start;
+ extent[1] = end;
+ },
+
+ /**
+ * Convert data to coord. Data is the rank if it has a ordinal scale
+ * @param {number} data
+ * @param {boolean} clamp
+ * @return {number}
+ */
+ dataToCoord: function (data, clamp) {
+ var extent = this._extent;
+ var scale = this.scale;
+ data = scale.normalize(data);
+
+ if (this.onBand && scale.type === 'ordinal') {
+ extent = extent.slice();
+ fixExtentWithBands(extent, scale.count());
+ }
+
+ return linearMap(data, normalizedExtent, extent, clamp);
+ },
+
+ /**
+ * Convert coord to data. Data is the rank if it has a ordinal scale
+ * @param {number} coord
+ * @param {boolean} clamp
+ * @return {number}
+ */
+ coordToData: function (coord, clamp) {
+ var extent = this._extent;
+ var scale = this.scale;
+
+ if (this.onBand && scale.type === 'ordinal') {
+ extent = extent.slice();
+ fixExtentWithBands(extent, scale.count());
+ }
+
+ var t = linearMap(coord, extent, normalizedExtent, clamp);
+
+ return this.scale.scale(t);
+ },
+
+ /**
+ * Convert pixel point to data in axis
+ * @param {Array.} point
+ * @param {boolean} clamp
+ * @return {number} data
+ */
+ pointToData: function (point, clamp) {
+ // Should be implemented in derived class if necessary.
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getTicksCoords: function (alignWithLabel) {
+ if (this.onBand && !alignWithLabel) {
+ var bands = this.getBands();
+ var coords = [];
+ for (var i = 0; i < bands.length; i++) {
+ coords.push(bands[i][0]);
+ }
+ if (bands[i - 1]) {
+ coords.push(bands[i - 1][1]);
+ }
+ return coords;
+ }
+ else {
+ return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
+ }
+ },
+
+ /**
+ * Coords of labels are on the ticks or on the middle of bands
+ * @return {Array.}
+ */
+ getLabelsCoords: function () {
+ return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
+ },
+
+ /**
+ * Get bands.
+ *
+ * If axis has labels [1, 2, 3, 4]. Bands on the axis are
+ * |---1---|---2---|---3---|---4---|.
+ *
+ * @return {Array}
+ */
+ // FIXME Situation when labels is on ticks
+ getBands: function () {
+ var extent = this.getExtent();
+ var bands = [];
+ var len = this.scale.count();
+ var start = extent[0];
+ var end = extent[1];
+ var span = end - start;
+
+ for (var i = 0; i < len; i++) {
+ bands.push([
+ span * i / len + start,
+ span * (i + 1) / len + start
+ ]);
+ }
+ return bands;
+ },
+
+ /**
+ * Get width of band
+ * @return {number}
+ */
+ getBandWidth: function () {
+ var axisExtent = this._extent;
+ var dataExtent = this.scale.getExtent();
+
+ var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);
+ // Fix #2728, avoid NaN when only one data.
+ len === 0 && (len = 1);
+
+ var size = Math.abs(axisExtent[1] - axisExtent[0]);
+
+ return Math.abs(size) / len;
+ },
+
+ /**
+ * Get interval of the axis label.
+ * @return {number}
+ */
+ getLabelInterval: function () {
+ var labelInterval = this._labelInterval;
+ if (!labelInterval) {
+ var axisModel = this.model;
+ var labelModel = axisModel.getModel('axisLabel');
+ var interval = labelModel.get('interval');
+ if (!(this.type === 'category' && interval === 'auto')) {
+ labelInterval = interval === 'auto' ? 0 : interval;
+ }
+ else if (this.isHorizontal){
+ labelInterval = axisHelper.getAxisLabelInterval(
+ zrUtil.map(this.scale.getTicks(), this.dataToCoord, this),
+ axisModel.getFormattedLabels(),
+ labelModel.getModel('textStyle').getFont(),
+ this.isHorizontal()
+ );
+ }
+ this._labelInterval = labelInterval;
+ }
+ return labelInterval;
+ }
+
+ };
+
+ module.exports = Axis;
+
+
+/***/ },
+/* 101 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+
+ var OrdinalScale = __webpack_require__(102);
+ var IntervalScale = __webpack_require__(104);
+ __webpack_require__(106);
+ __webpack_require__(107);
+ var Scale = __webpack_require__(103);
+
+ var numberUtil = __webpack_require__(7);
+ var zrUtil = __webpack_require__(4);
+ var textContain = __webpack_require__(8);
+ var axisHelper = {};
+
+ /**
+ * Get axis scale extent before niced.
+ * Item of returned array can only be number (including Infinity and NaN).
+ */
+ axisHelper.getScaleExtent = function (scale, model) {
+ var scaleType = scale.type;
+
+ var min = model.getMin();
+ var max = model.getMax();
+ var fixMin = min != null;
+ var fixMax = max != null;
+ var originalExtent = scale.getExtent();
+
+ var axisDataLen;
+ var boundaryGap;
+ var span;
+ if (scaleType === 'ordinal') {
+ axisDataLen = (model.get('data') || []).length;
+ }
+ else {
+ boundaryGap = model.get('boundaryGap');
+ if (!zrUtil.isArray(boundaryGap)) {
+ boundaryGap = [boundaryGap || 0, boundaryGap || 0];
+ }
+ if (typeof boundaryGap[0] === 'boolean') {
+ if (true) {
+ console.warn('Boolean type for boundaryGap is only '
+ + 'allowed for ordinal axis. Please use string in '
+ + 'percentage instead, e.g., "20%". Currently, '
+ + 'boundaryGap is set to be 0.');
+ }
+ boundaryGap = [0, 0];
+ }
+ boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1);
+ boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1);
+ span = (originalExtent[1] - originalExtent[0])
+ || Math.abs(originalExtent[0]);
+ }
+
+ // Notice: When min/max is not set (that is, when there are null/undefined,
+ // which is the most common case), these cases should be ensured:
+ // (1) For 'ordinal', show all axis.data.
+ // (2) For others:
+ // + `boundaryGap` is applied (if min/max set, boundaryGap is
+ // disabled).
+ // + If `needCrossZero`, min/max should be zero, otherwise, min/max should
+ // be the result that originalExtent enlarged by boundaryGap.
+ // (3) If no data, it should be ensured that `scale.setBlank` is set.
+
+ // FIXME
+ // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?
+ // (2) When `needCrossZero` and all data is positive/negative, should it be ensured
+ // that the results processed by boundaryGap are positive/negative?
+
+ if (min == null) {
+ min = scaleType === 'ordinal'
+ ? (axisDataLen ? 0 : NaN)
+ : originalExtent[0] - boundaryGap[0] * span;
+ }
+ if (max == null) {
+ max = scaleType === 'ordinal'
+ ? (axisDataLen ? axisDataLen - 1 : NaN)
+ : originalExtent[1] + boundaryGap[1] * span;
+ }
+
+ if (min === 'dataMin') {
+ min = originalExtent[0];
+ }
+ if (max === 'dataMax') {
+ max = originalExtent[1];
+ }
+
+ (min == null || !isFinite(min)) && (min = NaN);
+ (max == null || !isFinite(max)) && (max = NaN);
+
+ scale.setBlank(zrUtil.eqNaN(min) || zrUtil.eqNaN(max));
+
+ // Evaluate if axis needs cross zero
+ if (model.getNeedCrossZero()) {
+ // Axis is over zero and min is not set
+ if (min > 0 && max > 0 && !fixMin) {
+ min = 0;
+ }
+ // Axis is under zero and max is not set
+ if (min < 0 && max < 0 && !fixMax) {
+ max = 0;
+ }
+ }
+
+ return [min, max];
+ };
+
+ axisHelper.niceScaleExtent = function (scale, model) {
+ var extent = axisHelper.getScaleExtent(scale, model);
+ var fixMin = model.getMin() != null;
+ var fixMax = model.getMax() != null;
+ var splitNumber = model.get('splitNumber');
+
+ if (scale.type === 'log') {
+ scale.base = model.get('logBase');
+ }
+
+ scale.setExtent(extent[0], extent[1]);
+ scale.niceExtent({
+ splitNumber: splitNumber,
+ fixMin: fixMin,
+ fixMax: fixMax,
+ minInterval: scale.type === 'interval' ? model.get('minInterval') : null
+ });
+
+ // If some one specified the min, max. And the default calculated interval
+ // is not good enough. He can specify the interval. It is often appeared
+ // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
+ // to be 60.
+ // FIXME
+ var interval = model.get('interval');
+ if (interval != null) {
+ scale.setInterval && scale.setInterval(interval);
+ }
+ };
+
+ /**
+ * @param {module:echarts/model/Model} model
+ * @param {string} [axisType] Default retrieve from model.type
+ * @return {module:echarts/scale/*}
+ */
+ axisHelper.createScaleByModel = function(model, axisType) {
+ axisType = axisType || model.get('type');
+ if (axisType) {
+ switch (axisType) {
+ // Buildin scale
+ case 'category':
+ return new OrdinalScale(
+ model.getCategories(), [Infinity, -Infinity]
+ );
+ case 'value':
+ return new IntervalScale();
+ // Extended scale, like time and log
+ default:
+ return (Scale.getClass(axisType) || IntervalScale).create(model);
+ }
+ }
+ };
+
+ /**
+ * Check if the axis corss 0
+ */
+ axisHelper.ifAxisCrossZero = function (axis) {
+ var dataExtent = axis.scale.getExtent();
+ var min = dataExtent[0];
+ var max = dataExtent[1];
+ return !((min > 0 && max > 0) || (min < 0 && max < 0));
+ };
+
+ /**
+ * @param {Array.} tickCoords In axis self coordinate.
+ * @param {Array.} labels
+ * @param {string} font
+ * @param {boolean} isAxisHorizontal
+ * @return {number}
+ */
+ axisHelper.getAxisLabelInterval = function (tickCoords, labels, font, isAxisHorizontal) {
+ // FIXME
+ // 不同角的axis和label,不只是horizontal和vertical.
+
+ var textSpaceTakenRect;
+ var autoLabelInterval = 0;
+ var accumulatedLabelInterval = 0;
+
+ var step = 1;
+ if (labels.length > 40) {
+ // Simple optimization for large amount of labels
+ step = Math.floor(labels.length / 40);
+ }
+
+ for (var i = 0; i < tickCoords.length; i += step) {
+ var tickCoord = tickCoords[i];
+ var rect = textContain.getBoundingRect(
+ labels[i], font, 'center', 'top'
+ );
+ rect[isAxisHorizontal ? 'x' : 'y'] += tickCoord;
+ // FIXME Magic number 1.5
+ rect[isAxisHorizontal ? 'width' : 'height'] *= 1.3;
+ if (!textSpaceTakenRect) {
+ textSpaceTakenRect = rect.clone();
+ }
+ // There is no space for current label;
+ else if (textSpaceTakenRect.intersect(rect)) {
+ accumulatedLabelInterval++;
+ autoLabelInterval = Math.max(autoLabelInterval, accumulatedLabelInterval);
+ }
+ else {
+ textSpaceTakenRect.union(rect);
+ // Reset
+ accumulatedLabelInterval = 0;
+ }
+ }
+ if (autoLabelInterval === 0 && step > 1) {
+ return step;
+ }
+ return (autoLabelInterval + 1) * step - 1;
+ };
+
+ /**
+ * @param {Object} axis
+ * @param {Function} labelFormatter
+ * @return {Array.}
+ */
+ axisHelper.getFormattedLabels = function (axis, labelFormatter) {
+ var scale = axis.scale;
+ var labels = scale.getTicksLabels();
+ var ticks = scale.getTicks();
+ if (typeof labelFormatter === 'string') {
+ labelFormatter = (function (tpl) {
+ return function (val) {
+ return tpl.replace('{value}', val != null ? val : '');
+ };
+ })(labelFormatter);
+ // Consider empty array
+ return zrUtil.map(labels, labelFormatter);
+ }
+ else if (typeof labelFormatter === 'function') {
+ return zrUtil.map(ticks, function (tick, idx) {
+ return labelFormatter(
+ axisHelper.getAxisRawValue(axis, tick),
+ idx
+ );
+ }, this);
+ }
+ else {
+ return labels;
+ }
+ };
+
+ axisHelper.getAxisRawValue = function (axis, value) {
+ // In category axis with data zoom, tick is not the original
+ // index of axis.data. So tick should not be exposed to user
+ // in category axis.
+ return axis.type === 'category' ? axis.scale.getLabel(value) : value;
+ };
+
+ module.exports = axisHelper;
+
+
+/***/ },
+/* 102 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Linear continuous scale
+ * @module echarts/coord/scale/Ordinal
+ *
+ * http://en.wikipedia.org/wiki/Level_of_measurement
+ */
+
+ // FIXME only one data
+
+
+ var zrUtil = __webpack_require__(4);
+ var Scale = __webpack_require__(103);
+
+ var scaleProto = Scale.prototype;
+
+ var OrdinalScale = Scale.extend({
+
+ type: 'ordinal',
+
+ init: function (data, extent) {
+ this._data = data;
+ this._extent = extent || [0, data.length - 1];
+ },
+
+ parse: function (val) {
+ return typeof val === 'string'
+ ? zrUtil.indexOf(this._data, val)
+ // val might be float.
+ : Math.round(val);
+ },
+
+ contain: function (rank) {
+ rank = this.parse(rank);
+ return scaleProto.contain.call(this, rank)
+ && this._data[rank] != null;
+ },
+
+ /**
+ * Normalize given rank or name to linear [0, 1]
+ * @param {number|string} [val]
+ * @return {number}
+ */
+ normalize: function (val) {
+ return scaleProto.normalize.call(this, this.parse(val));
+ },
+
+ scale: function (val) {
+ return Math.round(scaleProto.scale.call(this, val));
+ },
+
+ /**
+ * @return {Array}
+ */
+ getTicks: function () {
+ var ticks = [];
+ var extent = this._extent;
+ var rank = extent[0];
+
+ while (rank <= extent[1]) {
+ ticks.push(rank);
+ rank++;
+ }
+
+ return ticks;
+ },
+
+ /**
+ * Get item on rank n
+ * @param {number} n
+ * @return {string}
+ */
+ getLabel: function (n) {
+ return this._data[n];
+ },
+
+ /**
+ * @return {number}
+ */
+ count: function () {
+ return this._extent[1] - this._extent[0] + 1;
+ },
+
+ /**
+ * @override
+ */
+ unionExtentFromData: function (data, dim) {
+ this.unionExtent(data.getDataExtent(dim, false));
+ },
+
+ niceTicks: zrUtil.noop,
+ niceExtent: zrUtil.noop
+ });
+
+ /**
+ * @return {module:echarts/scale/Time}
+ */
+ OrdinalScale.create = function () {
+ return new OrdinalScale();
+ };
+
+ module.exports = OrdinalScale;
+
+
+/***/ },
+/* 103 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * // Scale class management
+ * @module echarts/scale/Scale
+ */
+
+
+ var clazzUtil = __webpack_require__(13);
+
+ /**
+ * @param {Object} [setting]
+ */
+ function Scale(setting) {
+ this._setting = setting || {};
+
+ /**
+ * Extent
+ * @type {Array.}
+ * @protected
+ */
+ this._extent = [Infinity, -Infinity];
+
+ /**
+ * Step is calculated in adjustExtent
+ * @type {Array.}
+ * @protected
+ */
+ this._interval = 0;
+
+ this.init && this.init.apply(this, arguments);
+ }
+
+ var scaleProto = Scale.prototype;
+
+ /**
+ * Parse input val to valid inner number.
+ * @param {*} val
+ * @return {number}
+ */
+ scaleProto.parse = function (val) {
+ // Notice: This would be a trap here, If the implementation
+ // of this method depends on extent, and this method is used
+ // before extent set (like in dataZoom), it would be wrong.
+ // Nevertheless, parse does not depend on extent generally.
+ return val;
+ };
+
+ scaleProto.getSetting = function (name) {
+ return this._setting[name];
+ };
+
+ scaleProto.contain = function (val) {
+ var extent = this._extent;
+ return val >= extent[0] && val <= extent[1];
+ };
+
+ /**
+ * Normalize value to linear [0, 1], return 0.5 if extent span is 0
+ * @param {number} val
+ * @return {number}
+ */
+ scaleProto.normalize = function (val) {
+ var extent = this._extent;
+ if (extent[1] === extent[0]) {
+ return 0.5;
+ }
+ return (val - extent[0]) / (extent[1] - extent[0]);
+ };
+
+ /**
+ * Scale normalized value
+ * @param {number} val
+ * @return {number}
+ */
+ scaleProto.scale = function (val) {
+ var extent = this._extent;
+ return val * (extent[1] - extent[0]) + extent[0];
+ };
+
+ /**
+ * Set extent from data
+ * @param {Array.} other
+ */
+ scaleProto.unionExtent = function (other) {
+ var extent = this._extent;
+ other[0] < extent[0] && (extent[0] = other[0]);
+ other[1] > extent[1] && (extent[1] = other[1]);
+ // not setExtent because in log axis it may transformed to power
+ // this.setExtent(extent[0], extent[1]);
+ };
+
+ /**
+ * Set extent from data
+ * @param {module:echarts/data/List} data
+ * @param {string} dim
+ */
+ scaleProto.unionExtentFromData = function (data, dim) {
+ this.unionExtent(data.getDataExtent(dim, true));
+ };
+
+ /**
+ * Get extent
+ * @return {Array.}
+ */
+ scaleProto.getExtent = function () {
+ return this._extent.slice();
+ };
+
+ /**
+ * Set extent
+ * @param {number} start
+ * @param {number} end
+ */
+ scaleProto.setExtent = function (start, end) {
+ var thisExtent = this._extent;
+ if (!isNaN(start)) {
+ thisExtent[0] = start;
+ }
+ if (!isNaN(end)) {
+ thisExtent[1] = end;
+ }
+ };
+
+ /**
+ * @return {Array.}
+ */
+ scaleProto.getTicksLabels = function () {
+ var labels = [];
+ var ticks = this.getTicks();
+ for (var i = 0; i < ticks.length; i++) {
+ labels.push(this.getLabel(ticks[i]));
+ }
+ return labels;
+ };
+
+ /**
+ * When axis extent depends on data and no data exists,
+ * axis ticks should not be drawn, which is named 'blank'.
+ */
+ scaleProto.isBlank = function () {
+ return this._isBlank;
+ },
+
+ /**
+ * When axis extent depends on data and no data exists,
+ * axis ticks should not be drawn, which is named 'blank'.
+ */
+ scaleProto.setBlank = function (isBlank) {
+ this._isBlank = isBlank;
+ };
+
+
+ clazzUtil.enableClassExtend(Scale);
+ clazzUtil.enableClassManagement(Scale, {
+ registerWhenExtend: true
+ });
+
+ module.exports = Scale;
+
+
+/***/ },
+/* 104 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Interval scale
+ * @module echarts/scale/Interval
+ */
+
+
+
+ var numberUtil = __webpack_require__(7);
+ var formatUtil = __webpack_require__(6);
+ var Scale = __webpack_require__(103);
+ var helper = __webpack_require__(105);
+
+ var roundNumber = numberUtil.round;
+
+ /**
+ * @alias module:echarts/coord/scale/Interval
+ * @constructor
+ */
+ var IntervalScale = Scale.extend({
+
+ type: 'interval',
+
+ _interval: 0,
+
+ _intervalPrecision: 2,
+
+ setExtent: function (start, end) {
+ var thisExtent = this._extent;
+ //start,end may be a Number like '25',so...
+ if (!isNaN(start)) {
+ thisExtent[0] = parseFloat(start);
+ }
+ if (!isNaN(end)) {
+ thisExtent[1] = parseFloat(end);
+ }
+ },
+
+ unionExtent: function (other) {
+ var extent = this._extent;
+ other[0] < extent[0] && (extent[0] = other[0]);
+ other[1] > extent[1] && (extent[1] = other[1]);
+
+ // unionExtent may called by it's sub classes
+ IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);
+ },
+ /**
+ * Get interval
+ */
+ getInterval: function () {
+ return this._interval;
+ },
+
+ /**
+ * Set interval
+ */
+ setInterval: function (interval) {
+ this._interval = interval;
+ // Dropped auto calculated niceExtent and use user setted extent
+ // We assume user wan't to set both interval, min, max to get a better result
+ this._niceExtent = this._extent.slice();
+
+ this._intervalPrecision = helper.getIntervalPrecision(interval);
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getTicks: function () {
+ return helper.intervalScaleGetTicks(
+ this._interval, this._extent, this._niceExtent, this._intervalPrecision
+ );
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getTicksLabels: function () {
+ var labels = [];
+ var ticks = this.getTicks();
+ for (var i = 0; i < ticks.length; i++) {
+ labels.push(this.getLabel(ticks[i]));
+ }
+ return labels;
+ },
+
+ /**
+ * @param {number} data
+ * @param {Object} [opt]
+ * @param {number|string} [opt.precision] If 'auto', use nice presision.
+ * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.
+ * @return {string}
+ */
+ getLabel: function (data, opt) {
+ if (data == null) {
+ return '';
+ }
+
+ var precision = opt && opt.precision;
+
+ if (precision == null) {
+ precision = numberUtil.getPrecisionSafe(data) || 0;
+ }
+ else if (precision === 'auto') {
+ // Should be more precise then tick.
+ precision = this._intervalPrecision;
+ }
+
+ // (1) If `precision` is set, 12.005 should be display as '12.00500'.
+ // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.
+ data = roundNumber(data, precision, true);
+
+ return formatUtil.addCommas(data);
+ },
+
+ /**
+ * Update interval and extent of intervals for nice ticks
+ *
+ * @param {number} [splitNumber = 5] Desired number of ticks
+ * @param {number} [minInterval]
+ */
+ niceTicks: function (splitNumber, minInterval) {
+ splitNumber = splitNumber || 5;
+ var extent = this._extent;
+ var span = extent[1] - extent[0];
+ if (!isFinite(span)) {
+ return;
+ }
+ // User may set axis min 0 and data are all negative
+ // FIXME If it needs to reverse ?
+ if (span < 0) {
+ span = -span;
+ extent.reverse();
+ }
+
+ var result = helper.intervalScaleNiceTicks(extent, splitNumber, minInterval);
+
+ this._intervalPrecision = result.intervalPrecision;
+ this._interval = result.interval;
+ this._niceExtent = result.niceTickExtent;
+ },
+
+ /**
+ * Nice extent.
+ * @param {Object} opt
+ * @param {number} [opt.splitNumber = 5] Given approx tick number
+ * @param {boolean} [opt.fixMin=false]
+ * @param {boolean} [opt.fixMax=false]
+ * @param {boolean} [opt.minInterval=false]
+ */
+ niceExtent: function (opt) {
+ var extent = this._extent;
+ // If extent start and end are same, expand them
+ if (extent[0] === extent[1]) {
+ if (extent[0] !== 0) {
+ // Expand extent
+ var expandSize = extent[0];
+ // In the fowllowing case
+ // Axis has been fixed max 100
+ // Plus data are all 100 and axis extent are [100, 100].
+ // Extend to the both side will cause expanded max is larger than fixed max.
+ // So only expand to the smaller side.
+ if (!opt.fixMax) {
+ extent[1] += expandSize / 2;
+ extent[0] -= expandSize / 2;
+ }
+ else {
+ extent[0] -= expandSize / 2;
+ }
+ }
+ else {
+ extent[1] = 1;
+ }
+ }
+ var span = extent[1] - extent[0];
+ // If there are no data and extent are [Infinity, -Infinity]
+ if (!isFinite(span)) {
+ extent[0] = 0;
+ extent[1] = 1;
+ }
+
+ this.niceTicks(opt.splitNumber, opt.minInterval);
+
+ // var extent = this._extent;
+ var interval = this._interval;
+
+ if (!opt.fixMin) {
+ extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);
+ }
+ if (!opt.fixMax) {
+ extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);
+ }
+ }
+ });
+
+ /**
+ * @return {module:echarts/scale/Time}
+ */
+ IntervalScale.create = function () {
+ return new IntervalScale();
+ };
+
+ module.exports = IntervalScale;
+
+
+
+/***/ },
+/* 105 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * For testable.
+ */
+
+
+ var numberUtil = __webpack_require__(7);
+
+ var roundNumber = numberUtil.round;
+
+ var helper = {};
+
+ /**
+ * @param {Array.} extent Both extent[0] and extent[1] should be valid number.
+ * Should be extent[0] < extent[1].
+ * @param {number} splitNumber splitNumber should be >= 1.
+ * @param {number} [minInterval]
+ * @return {Object} {interval, intervalPrecision, niceTickExtent}
+ */
+ helper.intervalScaleNiceTicks = function (extent, splitNumber, minInterval) {
+ var result = {};
+ var span = extent[1] - extent[0];
+
+ var interval = result.interval = numberUtil.nice(span / splitNumber, true);
+ if (minInterval != null && interval < minInterval) {
+ interval = result.interval = minInterval;
+ }
+ // Tow more digital for tick.
+ var precision = result.intervalPrecision = helper.getIntervalPrecision(interval);
+ // Niced extent inside original extent
+ var niceTickExtent = result.niceTickExtent = [
+ roundNumber(Math.ceil(extent[0] / interval) * interval, precision),
+ roundNumber(Math.floor(extent[1] / interval) * interval, precision)
+ ];
+
+ helper.fixExtent(niceTickExtent, extent);
+
+ return result;
+ };
+
+ /**
+ * @param {number} interval
+ * @return {number} interval precision
+ */
+ helper.getIntervalPrecision = function (interval) {
+ // Tow more digital for tick.
+ return numberUtil.getPrecisionSafe(interval) + 2;
+ };
+
+ function clamp(niceTickExtent, idx, extent) {
+ niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);
+ }
+
+ // In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.
+ helper.fixExtent = function (niceTickExtent, extent) {
+ !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);
+ !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);
+ clamp(niceTickExtent, 0, extent);
+ clamp(niceTickExtent, 1, extent);
+ if (niceTickExtent[0] > niceTickExtent[1]) {
+ niceTickExtent[0] = niceTickExtent[1];
+ }
+ };
+
+ helper.intervalScaleGetTicks = function (interval, extent, niceTickExtent, intervalPrecision) {
+ var ticks = [];
+
+ // If interval is 0, return [];
+ if (!interval) {
+ return ticks;
+ }
+
+ // Consider this case: using dataZoom toolbox, zoom and zoom.
+ var safeLimit = 10000;
+
+ if (extent[0] < niceTickExtent[0]) {
+ ticks.push(extent[0]);
+ }
+ var tick = niceTickExtent[0];
+
+ while (tick <= niceTickExtent[1]) {
+ ticks.push(tick);
+ // Avoid rounding error
+ tick = roundNumber(tick + interval, intervalPrecision);
+ if (tick === ticks[ticks.length - 1]) {
+ // Consider out of safe float point, e.g.,
+ // -3711126.9907707 + 2e-10 === -3711126.9907707
+ break;
+ }
+ if (ticks.length > safeLimit) {
+ return [];
+ }
+ }
+ // Consider this case: the last item of ticks is smaller
+ // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
+ if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {
+ ticks.push(extent[1]);
+ }
+
+ return ticks;
+ };
+
+ module.exports = helper;
+
+
+/***/ },
+/* 106 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Interval scale
+ * @module echarts/coord/scale/Time
+ */
+
+
+
+ // [About UTC and local time zone]:
+ // In most cases, `number.parseDate` will treat input data string as local time
+ // (except time zone is specified in time string). And `format.formateTime` returns
+ // local time by default. option.useUTC is false by default. This design have
+ // concidered these common case:
+ // (1) Time that is persistent in server is in UTC, but it is needed to be diplayed
+ // in local time by default.
+ // (2) By default, the input data string (e.g., '2011-01-02') should be displayed
+ // as its original time, without any time difference.
+
+ var zrUtil = __webpack_require__(4);
+ var numberUtil = __webpack_require__(7);
+ var formatUtil = __webpack_require__(6);
+ var scaleHelper = __webpack_require__(105);
+
+ var IntervalScale = __webpack_require__(104);
+
+ var intervalScaleProto = IntervalScale.prototype;
+
+ var mathCeil = Math.ceil;
+ var mathFloor = Math.floor;
+ var ONE_SECOND = 1000;
+ var ONE_MINUTE = ONE_SECOND * 60;
+ var ONE_HOUR = ONE_MINUTE * 60;
+ var ONE_DAY = ONE_HOUR * 24;
+
+ // FIXME 公用?
+ var bisect = function (a, x, lo, hi) {
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (a[mid][2] < x) {
+ lo = mid + 1;
+ }
+ else {
+ hi = mid;
+ }
+ }
+ return lo;
+ };
+
+ /**
+ * @alias module:echarts/coord/scale/Time
+ * @constructor
+ */
+ var TimeScale = IntervalScale.extend({
+ type: 'time',
+
+ /**
+ * @override
+ */
+ getLabel: function (val) {
+ var stepLvl = this._stepLvl;
+
+ var date = new Date(val);
+
+ return formatUtil.formatTime(stepLvl[0], date, this.getSetting('useUTC'));
+ },
+
+ /**
+ * @override
+ */
+ niceExtent: function (opt) {
+ var extent = this._extent;
+ // If extent start and end are same, expand them
+ if (extent[0] === extent[1]) {
+ // Expand extent
+ extent[0] -= ONE_DAY;
+ extent[1] += ONE_DAY;
+ }
+ // If there are no data and extent are [Infinity, -Infinity]
+ if (extent[1] === -Infinity && extent[0] === Infinity) {
+ var d = new Date();
+ extent[1] = new Date(d.getFullYear(), d.getMonth(), d.getDate());
+ extent[0] = extent[1] - ONE_DAY;
+ }
+
+ this.niceTicks(opt.splitNumber);
+
+ // var extent = this._extent;
+ var interval = this._interval;
+
+ if (!opt.fixMin) {
+ extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
+ }
+ if (!opt.fixMax) {
+ extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
+ }
+ },
+
+ /**
+ * @override
+ */
+ niceTicks: function (approxTickNum) {
+ var timezoneOffset = this.getSetting('useUTC')
+ ? 0 : numberUtil.getTimezoneOffset() * 60 * 1000;
+ approxTickNum = approxTickNum || 10;
+
+ var extent = this._extent;
+ var span = extent[1] - extent[0];
+ var approxInterval = span / approxTickNum;
+ var scaleLevelsLen = scaleLevels.length;
+ var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);
+
+ var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];
+ var interval = level[2];
+ // Same with interval scale if span is much larger than 1 year
+ if (level[0] === 'year') {
+ var yearSpan = span / interval;
+
+ // From "Nice Numbers for Graph Labels" of Graphic Gems
+ // var niceYearSpan = numberUtil.nice(yearSpan, false);
+ var yearStep = numberUtil.nice(yearSpan / approxTickNum, true);
+
+ interval *= yearStep;
+ }
+
+ var niceExtent = [
+ Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),
+ Math.round(mathFloor((extent[1] - timezoneOffset)/ interval) * interval + timezoneOffset)
+ ];
+
+ scaleHelper.fixExtent(niceExtent, extent);
+
+ this._stepLvl = level;
+ // Interval will be used in getTicks
+ this._interval = interval;
+ this._niceExtent = niceExtent;
+ },
+
+ parse: function (val) {
+ // val might be float.
+ return +numberUtil.parseDate(val);
+ }
+ });
+
+ zrUtil.each(['contain', 'normalize'], function (methodName) {
+ TimeScale.prototype[methodName] = function (val) {
+ return intervalScaleProto[methodName].call(this, this.parse(val));
+ };
+ });
+
+ // Steps from d3
+ var scaleLevels = [
+ // Format step interval
+ ['hh:mm:ss', 1, ONE_SECOND], // 1s
+ ['hh:mm:ss', 5, ONE_SECOND * 5], // 5s
+ ['hh:mm:ss', 10, ONE_SECOND * 10], // 10s
+ ['hh:mm:ss', 15, ONE_SECOND * 15], // 15s
+ ['hh:mm:ss', 30, ONE_SECOND * 30], // 30s
+ ['hh:mm\nMM-dd',1, ONE_MINUTE], // 1m
+ ['hh:mm\nMM-dd',5, ONE_MINUTE * 5], // 5m
+ ['hh:mm\nMM-dd',10, ONE_MINUTE * 10], // 10m
+ ['hh:mm\nMM-dd',15, ONE_MINUTE * 15], // 15m
+ ['hh:mm\nMM-dd',30, ONE_MINUTE * 30], // 30m
+ ['hh:mm\nMM-dd',1, ONE_HOUR], // 1h
+ ['hh:mm\nMM-dd',2, ONE_HOUR * 2], // 2h
+ ['hh:mm\nMM-dd',6, ONE_HOUR * 6], // 6h
+ ['hh:mm\nMM-dd',12, ONE_HOUR * 12], // 12h
+ ['MM-dd\nyyyy', 1, ONE_DAY], // 1d
+ ['week', 7, ONE_DAY * 7], // 7d
+ ['month', 1, ONE_DAY * 31], // 1M
+ ['quarter', 3, ONE_DAY * 380 / 4], // 3M
+ ['half-year', 6, ONE_DAY * 380 / 2], // 6M
+ ['year', 1, ONE_DAY * 380] // 1Y
+ ];
+
+ /**
+ * @param {module:echarts/model/Model}
+ * @return {module:echarts/scale/Time}
+ */
+ TimeScale.create = function (model) {
+ return new TimeScale({useUTC: model.ecModel.get('useUTC')});
+ };
+
+ module.exports = TimeScale;
+
+
+/***/ },
+/* 107 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Log scale
+ * @module echarts/scale/Log
+ */
+
+
+ var zrUtil = __webpack_require__(4);
+ var Scale = __webpack_require__(103);
+ var numberUtil = __webpack_require__(7);
+
+ // Use some method of IntervalScale
+ var IntervalScale = __webpack_require__(104);
+
+ var scaleProto = Scale.prototype;
+ var intervalScaleProto = IntervalScale.prototype;
+
+ var getPrecisionSafe = numberUtil.getPrecisionSafe;
+ var roundingErrorFix = numberUtil.round;
+
+ var mathFloor = Math.floor;
+ var mathCeil = Math.ceil;
+ var mathPow = Math.pow;
+
+ var mathLog = Math.log;
+
+ var LogScale = Scale.extend({
+
+ type: 'log',
+
+ base: 10,
+
+ $constructor: function () {
+ Scale.apply(this, arguments);
+ this._originalScale = new IntervalScale();
+ },
+
+ /**
+ * @return {Array.}
+ */
+ getTicks: function () {
+ var originalScale = this._originalScale;
+ var extent = this._extent;
+ var originalExtent = originalScale.getExtent();
+
+ return zrUtil.map(intervalScaleProto.getTicks.call(this), function (val) {
+ var powVal = numberUtil.round(mathPow(this.base, val));
+
+ // Fix #4158
+ powVal = (val === extent[0] && originalScale.__fixMin)
+ ? fixRoundingError(powVal, originalExtent[0])
+ : powVal;
+ powVal = (val === extent[1] && originalScale.__fixMax)
+ ? fixRoundingError(powVal, originalExtent[1])
+ : powVal;
+
+ return powVal;
+ }, this);
+ },
+
+ /**
+ * @param {number} val
+ * @return {string}
+ */
+ getLabel: intervalScaleProto.getLabel,
+
+ /**
+ * @param {number} val
+ * @return {number}
+ */
+ scale: function (val) {
+ val = scaleProto.scale.call(this, val);
+ return mathPow(this.base, val);
+ },
+
+ /**
+ * @param {number} start
+ * @param {number} end
+ */
+ setExtent: function (start, end) {
+ var base = this.base;
+ start = mathLog(start) / mathLog(base);
+ end = mathLog(end) / mathLog(base);
+ intervalScaleProto.setExtent.call(this, start, end);
+ },
+
+ /**
+ * @return {number} end
+ */
+ getExtent: function () {
+ var base = this.base;
+ var extent = scaleProto.getExtent.call(this);
+ extent[0] = mathPow(base, extent[0]);
+ extent[1] = mathPow(base, extent[1]);
+
+ // Fix #4158
+ var originalScale = this._originalScale;
+ var originalExtent = originalScale.getExtent();
+ originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
+ originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
+
+ return extent;
+ },
+
+ /**
+ * @param {Array.