提交 0dc78665 编写于 作者: L lang

Interactive legend

上级 20bc4281
...@@ -22,7 +22,7 @@ define(function(require) { ...@@ -22,7 +22,7 @@ define(function(require) {
Polyline: require('zrender/graphic/shape/Polyline'), Polyline: require('zrender/graphic/shape/Polyline'),
Rectangle: require('zrender/graphic/shape/Rectangle'), Rect: require('zrender/graphic/shape/Rectangle'),
/** /**
* Create a path element from path data string * Create a path element from path data string
......
...@@ -5,6 +5,8 @@ define(function (require) { ...@@ -5,6 +5,8 @@ define(function (require) {
type: 'bar', type: 'bar',
render: function (seriesModel, ecModel, api) { render: function (seriesModel, ecModel, api) {
this.group.clear();
var coordinateSystemType = seriesModel.get('coordinateSystem'); var coordinateSystemType = seriesModel.get('coordinateSystem');
if (coordinateSystemType === 'cartesian2d') { if (coordinateSystemType === 'cartesian2d') {
...@@ -18,7 +20,7 @@ define(function (require) { ...@@ -18,7 +20,7 @@ define(function (require) {
seriesModel.getData().each(function (dataItem) { seriesModel.getData().each(function (dataItem) {
var layout = dataItem.layout; var layout = dataItem.layout;
var rect = new api.Rectangle({ var rect = new api.Rect({
shape: { shape: {
x: layout.x, x: layout.x,
y: layout.y, y: layout.y,
......
...@@ -4,8 +4,10 @@ define(function(require) { ...@@ -4,8 +4,10 @@ define(function(require) {
// Grid view // Grid view
require('../echarts').extendComponentView({ require('../echarts').extendComponentView({
render: function (gridModel, ecModel) { render: function (gridModel, ecModel, api) {
this.group.add(new api.Rectangle({
}));
} }
}); });
}); });
\ No newline at end of file
...@@ -3,6 +3,7 @@ define(function(require) { ...@@ -3,6 +3,7 @@ define(function(require) {
'use strict'; 'use strict';
var List = require('../../data/List'); var List = require('../../data/List');
var zrUtil = require('zrender/core/util');
return require('../../echarts').extendComponentModel({ return require('../../echarts').extendComponentModel({
...@@ -13,7 +14,27 @@ define(function(require) { ...@@ -13,7 +14,27 @@ define(function(require) {
option.selected = option.selected || {}; option.selected = option.selected || {};
this._data = List.fromArray(option.data); var list = new List();
zrUtil.each(option.data, function (dataItem) {
if (typeof dataItem === 'string') {
list.append(dataItem, {});
}
else {
list.append(dataItem.name, dataItem);
}
});
/**
* @type {Array.<string>}
* @private
*/
this._seriesNames = zrUtil.map(ecModel.getSeriesAll(), function (series) {
return series.name;
});
this._data = list;
this._stack = [];
}, },
/** /**
...@@ -37,12 +58,24 @@ define(function(require) { ...@@ -37,12 +58,24 @@ define(function(require) {
this.option.selected[name] = false; this.option.selected[name] = false;
}, },
/**
* @param {string} name
*/
toggleSelected: function (name) {
var selected = this.option.selected;
if (! (name in selected)) {
selected[name] = true;
}
selected[name] = !selected[name];
},
/** /**
* @param {string} name * @param {string} name
*/ */
isSelected: function (name) { isSelected: function (name) {
var selected = this.option.selected; var selected = this.option.selected;
return !((name in selected) && selected[name]); return !((name in selected) && !selected[name])
&& this._seriesNames.indexOf(name) >= 0
}, },
defaultOption: { defaultOption: {
......
define(function (require) { define(function (require) {
var numberUtil = require('../../util/number');
return require('../../echarts').extendComponentView({ return require('../../echarts').extendComponentView({
type: 'legend', type: 'legend',
render: function (legendModel, ecModel, api) { render: function (legendModel, ecModel, api) {
var itemGap = legendModel.get('itemGap');
var padding = numberUtil.normalizeCssArray(
legendModel.get('padding')
);
var orient = legendModel.get('orient');
var group = this.group;
group.clear();
group.position = [
numberUtil.parsePercent(
legendModel.get('x'), api.getWidth()
),
numberUtil.parsePercent(
legendModel.get('y'), api.getHeight()
)
];
var x = 0;
var y = 0;
legendModel.getData().each(function (dataItem) { legendModel.getData().each(function (dataItem) {
var series = ecModel.getSeriesByName(dataItem.name); var seriesName = dataItem.name;
var color = ecModel.getVisual('color'); var seriesModel = ecModel.getSeriesByName(seriesName);
var symbol = ecModel.getVisual('symbol'); var color = legendModel.isSelected(seriesName)
? seriesModel.getVisual('color')
: '#ccc';
var symbol = seriesModel.getVisual('symbol');
var width = 20;
var height = 10;
var rect = new api.Rect({
shape: {
x: x,
y: y,
width: width,
height: height
},
style: {
fill: color
}
});
var text = new api.Text({
style: {
text: dataItem.name,
x: x + width + 5,
y: y,
fill: '#000',
textAlign: 'left',
textBaseline: 'top'
}
});
var textRect = text.getBoundingRect();
if (orient === 'horizontal') {
x += width + 5 + textRect.width + itemGap;
}
else {
y += Math.max(height, textRect.height) + itemGap;
}
group.add(rect);
group.add(text);
rect.on('click', function () {
legendModel.toggleSelected(seriesName);
api.update();
});
}); });
var groupRect = group.getBoundingRect();
group.position[0] -= groupRect.width / 2;
} }
}); });
}); });
\ No newline at end of file
...@@ -63,14 +63,14 @@ define(function(require) { ...@@ -63,14 +63,14 @@ define(function(require) {
* 添加一个新的节点 * 添加一个新的节点
* @param {*} [option] 存储的数据 * @param {*} [option] 存储的数据
*/ */
Graph.prototype.addNode = function (option) { Graph.prototype.addNode = function (name, option) {
var name = option.name;
if (this._nodesMap[name]) { if (this._nodesMap[name]) {
return this._nodesMap[name]; return this._nodesMap[name];
} }
var node = new Graph.Node(option); var node = new Graph.Node(option);
node.name = name;
this.nodes.push(node); this.nodes.push(node);
...@@ -328,11 +328,13 @@ define(function(require) { ...@@ -328,11 +328,13 @@ define(function(require) {
*/ */
Graph.prototype.clone = function () { Graph.prototype.clone = function () {
var graph = new Graph(this._directed); var graph = new Graph(this._directed);
for (var i = 0; i < this.nodes.length; i++) { var nodes = this.nodes;
graph.addNode(this.nodes[i].name, this.nodes[i].data); var edges = this.edges;
for (var i = 0; i < nodes.length; i++) {
graph.addNode(nodes[i].name, nodes[i].data);
} }
for (var i = 0; i < this.edges.length; i++) { for (var i = 0; i < edges.length; i++) {
var e = this.edges[i]; var e = edges[i];
graph.addEdge(e.node1.name, e.node2.name, e.data); graph.addEdge(e.node1.name, e.node2.name, e.data);
} }
return graph; return graph;
......
...@@ -35,7 +35,7 @@ define(function(require) { ...@@ -35,7 +35,7 @@ define(function(require) {
dimension: 1, dimension: 1,
init: function (option, parentModel, ecModel, dataIndex) { init: function (option, parentModel, dataIndex) {
/** /**
* @type {string} * @type {string}
...@@ -57,7 +57,7 @@ define(function(require) { ...@@ -57,7 +57,7 @@ define(function(require) {
* @private * @private
* @readOnly * @readOnly
*/ */
this.rawIndex = dataIndex || 0; this.dataIndex = dataIndex || 0;
}, },
/** /**
...@@ -66,7 +66,7 @@ define(function(require) { ...@@ -66,7 +66,7 @@ define(function(require) {
getX: function () { getX: function () {
// Use idx as x if data is 1d // Use idx as x if data is 1d
// Usually when xAxis is category axis // Usually when xAxis is category axis
return this.dimension === 1 ? this.rawIndex : this._value[0]; return this.dimension === 1 ? this.dataIndex : this._value[0];
}, },
/** /**
...@@ -132,13 +132,21 @@ define(function(require) { ...@@ -132,13 +132,21 @@ define(function(require) {
* @param {number} value * @param {number} value
*/ */
setValue: function (value) { setValue: function (value) {
this._value[this.dimensino] = value this._value[this.dimension] = value
},
clone: function () {
var entry = new Entry(
this.option, this.parentModel, this.dataIndex
);
entry.dimension = this.dimension;
return entry;
} }
}); });
function List() { function List() {
this.elements = this.elements || []; this.elements = [];
// Depth and properties is useful in nested Array. // Depth and properties is useful in nested Array.
// For example in eventRiver, data structure is a nested 2d array as following // For example in eventRiver, data structure is a nested 2d array as following
...@@ -210,8 +218,27 @@ define(function(require) { ...@@ -210,8 +218,27 @@ define(function(require) {
} }
}, },
/**
* @param {string} name
* @param {*} option
*/
append: function (name, option) {
var elements = this.elements;
var el = new Entry(option, null, elements.length);
el.name = name;
elements.push(el);
return el;
},
clone: function () { clone: function () {
// Clone var list = new List();
var elements = this.elements;
for (var i = 0; i < elements.length; i++) {
list.elements.push(elements[i].clone());
}
list.depth = this.depth;
list.properties = this.properties;
return list;
} }
}; };
...@@ -230,7 +257,7 @@ define(function(require) { ...@@ -230,7 +257,7 @@ define(function(require) {
var list = new List(); var list = new List();
// Normalize data // Normalize data
list.elements = zrUtil.map(data, function (dataItem, index) { list.elements = zrUtil.map(data, function (dataItem, index) {
var entry = new Entry(dataItem, parentModel, null, index); var entry = new Entry(dataItem, parentModel, index);
entry.dimension = dimension || 1; entry.dimension = dimension || 1;
return entry; return entry;
}); });
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
* *
* @module echarts/data/Tree * @module echarts/data/Tree
* @author Yi Shen(https://www.github.com/pissang) * @author Yi Shen(https://www.github.com/pissang)
*
* TODO clone
*/ */
define(function(require) { define(function(require) {
......
/** /**
* TODO processor的优先级 * TODO processor的优先级
* TODO restore * restore
* TODO setTheme * setTheme
* stack
*/ */
define(function (require) { define(function (require) {
...@@ -30,25 +31,76 @@ define(function (require) { ...@@ -30,25 +31,76 @@ define(function (require) {
var ECharts = function (dom, theme, opts) { var ECharts = function (dom, theme, opts) {
opts = opts || {}; opts = opts || {};
/**
* @type {module:zrender/ZRender}
* @private
*/
this._zr = zrender.init(dom, { this._zr = zrender.init(dom, {
renderer: opts.renderer || 'canvas' renderer: opts.renderer || 'canvas'
}); });
/**
* @type {Object}
* @private
*/
this._theme = zrUtil.clone(theme); this._theme = zrUtil.clone(theme);
/**
* @type {Array.<module:echarts/view/Chart>}
* @private
*/
this._chartsList = []; this._chartsList = [];
/**
* @type {Object.<string, module:echarts/view/Chart>}
* @private
*/
this._chartsMap = {}; this._chartsMap = {};
/**
* @type {Array.<module:echarts/view/Component>}
* @private
*/
this._componentsList = []; this._componentsList = [];
/**
* @type {Object.<string, module:echarts/view/Component>}
* @private
*/
this._componentsMap = {}; this._componentsMap = {};
/**
* @type {module:echarts/api/ExtensionAPI}
* @private
*/
this._extensionAPI = new ExtensionAPI(this); this._extensionAPI = new ExtensionAPI(this);
/**
* @type {module:echarts/CoordinateSystem}
* @private
*/
this._coordinateSystem = new CoordinateSystemManager(); this._coordinateSystem = new CoordinateSystemManager();
/**
* Layout instances
* @type {Array}
* @private
*/
this._layouts = zrUtil.map(layoutClasses, function (Layout) { this._layouts = zrUtil.map(layoutClasses, function (Layout) {
return new Layout(); return new Layout();
}); });
/**
* @type {boolean}
* @private
*/
this._needsUpdate = false;
this._zr.animation.on('frame', function () {
if (this._needsUpdate) {
this.updateImmediately();
}
}, this);
}; };
ECharts.prototype = { ECharts.prototype = {
...@@ -99,6 +151,7 @@ define(function (require) { ...@@ -99,6 +151,7 @@ define(function (require) {
}, },
update: function () { update: function () {
this._needsUpdate = true;
}, },
updateImmediately: function () { updateImmediately: function () {
...@@ -106,6 +159,8 @@ define(function (require) { ...@@ -106,6 +159,8 @@ define(function (require) {
ecModel.restore(); ecModel.restore();
ecModel.save();
this._processData(ecModel); this._processData(ecModel);
this._coordinateSystem.update(ecModel, this._extensionAPI); this._coordinateSystem.update(ecModel, this._extensionAPI);
...@@ -115,6 +170,8 @@ define(function (require) { ...@@ -115,6 +170,8 @@ define(function (require) {
this._doLayout(ecModel); this._doLayout(ecModel);
this._doRender(ecModel); this._doRender(ecModel);
this._needsUpdate = false;
}, },
resize: function () { resize: function () {
...@@ -256,7 +313,6 @@ define(function (require) { ...@@ -256,7 +313,6 @@ define(function (require) {
/** /**
* Render each chart and component * Render each chart and component
*
*/ */
_doRender: function (ecModel) { _doRender: function (ecModel) {
var api = this._extensionAPI; var api = this._extensionAPI;
......
...@@ -31,11 +31,23 @@ define(function (require) { ...@@ -31,11 +31,23 @@ define(function (require) {
this.option = {}; this.option = {};
/**
* @type {Array}
* @private
*/
this._stack = [];
/**
* @type {Array.<module:echarts/model/Model}
* @private
*/
this._components = [];
/** /**
* @type {Object.<string, module:echarts/model/Model>} * @type {Object.<string, module:echarts/model/Model>}
* @private * @private
*/ */
this._components = {}; this._componentsMap = {};
/** /**
* @type {Array.<module:echarts/model/Model} * @type {Array.<module:echarts/model/Model}
...@@ -109,6 +121,7 @@ define(function (require) { ...@@ -109,6 +121,7 @@ define(function (require) {
return seriesModel.option; return seriesModel.option;
}); });
var componentsMap = this._componentsMap;
var components = this._components; var components = this._components;
for (var name in newOption) { for (var name in newOption) {
var componentOption = newOption[name]; var componentOption = newOption[name];
...@@ -128,11 +141,11 @@ define(function (require) { ...@@ -128,11 +141,11 @@ define(function (require) {
if (! (componentOption instanceof Array)) { if (! (componentOption instanceof Array)) {
componentOption = [componentOption]; componentOption = [componentOption];
} }
if (! components[name]) { if (! componentsMap[name]) {
components[name] = []; componentsMap[name] = [];
} }
for (var i = 0; i < componentOption.length; i++) { for (var i = 0; i < componentOption.length; i++) {
var componentModel = components[name][i]; var componentModel = componentsMap[name][i];
if (componentModel) { if (componentModel) {
componentModel.mergeOption( componentModel.mergeOption(
componentOption[i], this componentOption[i], this
...@@ -142,7 +155,8 @@ define(function (require) { ...@@ -142,7 +155,8 @@ define(function (require) {
componentModel = ComponentModel.create( componentModel = ComponentModel.create(
name, componentOption[i], this name, componentOption[i], this
); );
components[name][i] = componentModel; componentsMap[name][i] = componentModel;
components.push(componentModel);
} }
if (componentModel) { if (componentModel) {
// 同步 Option // 同步 Option
...@@ -170,16 +184,25 @@ define(function (require) { ...@@ -170,16 +184,25 @@ define(function (require) {
* @return {module:echarts/model/Component} * @return {module:echarts/model/Component}
*/ */
getComponent: function (type, idx) { getComponent: function (type, idx) {
var list = this._components[type]; var list = this._componentsMap[type];
if (list) { if (list) {
return list[idx || 0]; return list[idx || 0];
} }
}, },
/**
* @param {string} type
* @param {Function} cb
* @param {*} context
*/
eachComponent: function (type, cb, context) { eachComponent: function (type, cb, context) {
zrUtil.each(this._components[type], cb, context); zrUtil.each(this._componentsMap[type], cb, context);
}, },
/**
* @param {string} name
* @return {Array.<module:echarts/model/Series>}
*/
getSeriesByName: function (name) { getSeriesByName: function (name) {
return this._seriesMap[name]; return this._seriesMap[name];
}, },
...@@ -206,15 +229,55 @@ define(function (require) { ...@@ -206,15 +229,55 @@ define(function (require) {
* @return {Array.<module:echarts/model/Series>} * @return {Array.<module:echarts/model/Series>}
*/ */
getSeriesAll: function () { getSeriesAll: function () {
return this._series; return this._series.slice();
}, },
/**
* @param {Function} cb
* @param {*} context
*/
eachSeries: function (cb, context) { eachSeries: function (cb, context) {
zrUtil.each(this._series, cb, context); zrUtil.each(this._series, cb, context);
}, },
/**
* @param {Function} cb
* @param {*} context
*/
filterSeries: function (cb, context) { filterSeries: function (cb, context) {
this._series = zrUtil.filter(this._series, cb, context); this._series = zrUtil.filter(this._series, cb, context);
},
save: function () {
this._stack.push({
series: this._series.slice()
});
var components = this._components;
var series = this._series;
var i;
for (i = 0; i < components.length; i++) {
components[i].save();
}
for (i = 0; i < series.length; i++) {
series[i].save();
}
},
restore: function () {
if (this._stack.length) {
this._series = this._stack.pop().series;
}
var components = this._components;
var series = this._series;
var i;
for (i = 0; i < components.length; i++) {
components[i].restore();
}
for (i = 0; i < series.length; i++) {
series[i].restore();
}
} }
}); });
......
...@@ -104,6 +104,8 @@ define(function (require) { ...@@ -104,6 +104,8 @@ define(function (require) {
this._visual[key] = val; this._visual[key] = val;
}, },
save: function () {},
restore: function () {}, restore: function () {},
// Pending // Pending
......
...@@ -25,13 +25,22 @@ define(function(require) { ...@@ -25,13 +25,22 @@ define(function(require) {
init: function (seriesOption, parentModel, ecModel, seriesIndex) { init: function (seriesOption, parentModel, ecModel, seriesIndex) {
/**
* @type {number}
*/
this.seriesIndex = seriesIndex; this.seriesIndex = seriesIndex;
zrUtil.merge(seriesOption, ecModel.getTheme().get(this.type)); zrUtil.merge(seriesOption, ecModel.getTheme().get(this.type));
zrUtil.merge(seriesOption, this.defaultOption); zrUtil.merge(seriesOption, this.defaultOption);
/**
* @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}
* @private
*/
this._data = this.getInitialData(seriesOption); this._data = this.getInitialData(seriesOption);
this._stack = [];
}, },
mergeOption: function (newSeriesOption) { mergeOption: function (newSeriesOption) {
...@@ -46,6 +55,18 @@ define(function(require) { ...@@ -46,6 +55,18 @@ define(function(require) {
getData: function () { getData: function () {
return this._data; return this._data;
},
save: function () {
this._stack.push({
data: this._data.clone()
});
},
restore: function () {
if (this._stack.length) {
this._data = this._stack.pop().data;
}
} }
}); });
......
...@@ -40,6 +40,19 @@ define(function (require) { ...@@ -40,6 +40,19 @@ define(function (require) {
* @return {number} * @return {number}
*/ */
function parsePercent(percent, all) { function parsePercent(percent, all) {
switch (percent) {
case 'center':
percent = '50%';
break;
case 'left':
case 'top':
percent = '0%';
break;
case 'right':
case 'bottom':
percent = '100%';
break;
}
if (typeof percent === 'string') { if (typeof percent === 'string') {
if (_trim(percent).match(/%$/)) { if (_trim(percent).match(/%$/)) {
return parseFloat(percent) / 100 * all; return parseFloat(percent) / 100 * all;
...@@ -51,10 +64,36 @@ define(function (require) { ...@@ -51,10 +64,36 @@ define(function (require) {
return +percent; return +percent;
} }
/**
* 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.<number>} val
*/
function normalizeCssArray(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;
}
return { return {
linearMap: linearMap, linearMap: linearMap,
parsePercent: parsePercent parsePercent: parsePercent,
normalizeCssArray: normalizeCssArray
} }
}); });
\ No newline at end of file
define(function (require) { define(function (require) {
return function (ecModel) { return function (ecModel) {
ecModel.eachSeries(function (seriesModel, idx) { ecModel.eachSeries(function (seriesModel) {
var colorList = ecModel.get('color'); var colorList = ecModel.get('color');
seriesModel.setVisual( seriesModel.setVisual(
'color', seriesModel.get('itemStyle.normal.color') || colorList[idx] 'color', seriesModel.get('itemStyle.normal.color')
|| colorList[seriesModel.seriesIndex]
); );
}); });
} }
......
...@@ -19,11 +19,15 @@ ...@@ -19,11 +19,15 @@
var chart = echarts.init(document.getElementById('main')); var chart = echarts.init(document.getElementById('main'));
var xAxisData = []; var xAxisData = [];
var data = []; var data1 = [];
var data2 = [];
var data3 = [];
for (var i = 0; i < 10000; i++) { for (var i = 0; i < 20; i++) {
xAxisData.push(Math.random()); xAxisData.push(Math.random());
data.push(Math.random()); data1.push(Math.random());
data2.push(Math.random());
data3.push(Math.random());
} }
console.profile('setOption'); console.profile('setOption');
...@@ -33,10 +37,13 @@ ...@@ -33,10 +37,13 @@
name: 'bar', name: 'bar',
itemStyle: { itemStyle: {
normal: { normal: {
color: 'blue' // color: 'blue'
} }
} }
}] }, 'bar2', 'bar3'],
selected: {
'bar': false
}
}, },
xAxis: { xAxis: {
// data: ['类目1', '类目2', '类目3', '类目4', '类目5',] // data: ['类目1', '类目2', '类目3', '类目4', '类目5',]
...@@ -48,7 +55,17 @@ ...@@ -48,7 +55,17 @@
name: 'bar', name: 'bar',
type: 'bar', type: 'bar',
// data: [0, 1, 2, 3, 4] // data: [0, 1, 2, 3, 4]
data: data data: data1
}, {
name: 'bar2',
type: 'bar',
// data: [0, 1, 2, 3, 4]
data: data2
}, {
name: 'bar3',
type: 'bar',
// data: [0, 1, 2, 3, 4]
data: data3
}] }]
}); });
console.profileEnd('setOption'); console.profileEnd('setOption');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册