This commit is contained in:
Jackson Tian 2012-11-21 18:09:35 +08:00
parent 4f061b9ee6
commit 54b07f816e
14 changed files with 3226 additions and 1750 deletions

View File

@ -4,6 +4,10 @@ DataV组件库的设计
## DataV结构
- Chart
- Widget
- Component
## API设计
## 数据映射

View File

@ -6,15 +6,25 @@
<script src="../../build/deps.js"></script>
<script src="../../deps/seajs/sea.js"></script>
<style type="text/css">
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
#chart {
border-top: 1px dashed #F00;
border-bottom: 1px dashed #F00;
padding-left: 20px;
border-top: 1px dashed #F00;
border-bottom: 1px dashed #F00;
padding-left: 20px;
}
</style>
</head>
<body>
<div id="chart">
<div id="chart" class="clearfix">
</div>
<script type="text/template">
<div class="legend">
</div>
<div>
@ -27,7 +37,7 @@
</div>
</div>
</div>
</div>
</script>
<script>
//http://planetozh.com/blog/2008/04/javascript-basename-and-dirname/
var dir = location.href.replace(/\\/g,'/').replace(/\/[^\/]*$/, '');
@ -35,20 +45,34 @@
alias: {
'DataV': dir + '/../../lib/datav.js',
'Axis': dir + '/../../lib/charts/axis.js',
'StreamAxis': dir + '/../../lib/charts/stream_axis.js',
'Legend': dir + '/../../lib/charts/legend.js',
'Navi': dir + '/../../lib/charts/navi.js',
'Tip': dir + '/../../lib/charts/tip.js',
'Percentage': dir + '/../../lib/charts/percentage.js',
'Stream': dir + '/../../lib/charts/stream.refine.js'
'HoverLine': dir + '/../../lib/charts/hover_line.js',
'PathLabel': dir + '/../../lib/charts/path_label.js',
'Cover': dir + '/../../lib/charts/cover.js',
'Stream': dir + '/../../lib/charts/stream_chart.js',
'StreamComponent': dir + '/../../lib/charts/stream.refine.js'
}
});
seajs.use(["Stream", "DataV"], function (Stream, DataV) {
seajs.use(["StreamComponent", "DataV"], function (Stream, DataV) {
DataV.changeTheme("theme0");
var stream = new Stream("chart", {"width": 800});
stream.setOptions({"more": false, "legendPosition": "left"});
DataV.csv("streamDataExample.csv", function (source) {
stream.setSource(source);
stream.render();
var component = new StreamComponent("chart", {"width": 800});
component.setOptions({"legendPosition": "left"});
var source = [
['2012-10-21','book', 100],
['2012-10-21','food', 110],
['2012-10-22','book', 30],
['2012-10-22','food', 140]
];
component.setSource(source, {
x: 0,
type: 1,
value: 2
});
component.render();
});
</script>
</body>

36
lib/charts/cover.js Normal file
View File

@ -0,0 +1,36 @@
/*global Raphael, d3, $, define, _ */
/*!
* StreamLegend的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Cover', function (require) {
var DataV = require('DataV');
//cover
var Cover = DataV.extend(DataV.Chart, {
initialize: function (container) {
var conf = this.defaults;
this.node = $(container);
this.node.css({
"position": "absolute",
"left": 0,
"top": 0,
"width": conf.chartWidth,
"height": conf.chartHeight,
"zIndex": 100,
"visibility": "hidden"
}).bind("mousemove", $.proxy(function (e) {
this.mouse = {x: e.pageX, y: e.pageY};
e.stopPropagation();
}, this)).bind("mouseleave", $.proxy(function () {
this.mouse = undefined;
}, this));
}
});
return Cover;
});

69
lib/charts/hover_line.js Normal file
View File

@ -0,0 +1,69 @@
/*global Raphael, d3, $, define, _ */
/*!
* StreamLegend的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('HoverLine', function (require) {
var DataV = require('DataV');
var HoverLine = DataV.extend(DataV.Widget, {
initialize: function () {
}
});
HoverLine.prototype.render = function () {
this.clear();
var paper = this.owner.paper;
var conf = this.owner.defaults;
this.indicatorLine = paper.path("M0 0V" + conf.chartHeight).attr({
stroke: "none",
"stroke-width": 1,
"stroke-dasharray": "- "
});
this.highlightLine = paper.path("M0 0V" + conf.chartHeight).attr({
stroke: "none",
"stroke-width": 2
});
};
HoverLine.prototype.hidden = function () {
this.indicatorLine.attr({"stroke": "none"});
this.highlightLine.attr({"stroke": "none"});
};
HoverLine.prototype.show = function () {
this.indicatorLine.attr({"stroke": "#000"});
this.highlightLine.attr({"stroke": "white"});
};
HoverLine.prototype.refresh = function (xIdx, pathIndex) {
//refresh lines' position
var owner = this.owner;
var pathSource = owner.pathSource;
var lineX = owner.defaults.chartWidth * xIdx / (owner.source[0].length - 1);
var pathSourceCell = pathSource[pathSource.length - 1][xIdx];
this.indicatorLine.attr({
path: "M" + lineX + " " + (pathSourceCell.y0 - pathSourceCell.y) + "V" + pathSource[0][xIdx].y0
});
pathSourceCell = pathSource[pathIndex][xIdx];
this.highlightLine.attr({
path: "M" + lineX + " " + (pathSourceCell.y0 - pathSourceCell.y) + "V" + pathSourceCell.y0
});
if (pathIndex === 0 && owner.getDisplayRowInfo(pathIndex).rowIndex === -1) {
this.highlightLine.attr({"cursor": "pointer"});
} else {
this.highlightLine.attr({"cursor": "auto"});
}
};
HoverLine.prototype.clear = function () {
this.indicatorLine && this.indicatorLine.remove();
this.highlightLine && this.highlightLine.remove();
};
return HoverLine;
});

View File

@ -11,12 +11,37 @@
})('Legend', function (require) {
var DataV = require('DataV');
var Legend = DataV.extend(DataV.Widget, {
var Legend = DataV.extend(DataV.Chart, {
initialize: function (container) {
this.legendIndent = 21;
this.legendIndent = 20;
this.node = $(container);
/**
* 类型纬度
*/
this.dimension.type = {
type: "string",
required: true,
index: 1
};
/**
* 时间纬度
*/
this.dimension.x = {
type: "string",
required: true,
index: 0
};
/**
* 值纬度
*/
this.dimension.value = {
type: "number",
required: true,
index: 2
};
}
});
Legend.prototype.init = function () {
var conf = this.owner.defaults;
this.legend = $("<div></div>");
@ -28,14 +53,18 @@
this.node.append(this.legend);
};
Legend.prototype.setSource = function (source, map) {
map = this.map(map);
this.list = _.keys(_.groupBy(source, map.type));
};
Legend.prototype.render = function () {
var that = this;
this.init();
this.clear();
this.legends = [];
var owner = this.owner;
var colorFunc = owner.getColor();
var colorArray = [],
var colorFunc = this.defaults.colorFunc,
hoverIn = function (e) {
var index = e.data.index;
owner.fire('hoverIn', index);
@ -54,19 +83,14 @@
});
var ul = $("<ul></ul>").css({
"margin": "0px 0 0px 10px",
"padding-left": "0"
"margin": "0 0 0 10px",
"paddingLeft": 0
});
var i, l;
for (i = 0, l = owner.displayData.allInfos.length; i < l; i++) {
colorArray.push(colorFunc(i));
}
for (i = 0, l = owner.displayData.allInfos.length; i < l; i++) {
var color = colorArray[owner.displayData.rowIndex[i].slicedData];
var li = $('<li style="color: ' + color + '"><span style="color: black">' + owner.getDisplayRowInfo(i).rowName + '</span></li>');
for (var i = 0, l = this.list.length; i < l && i < this.legendIndent; i++) {
var color = colorFunc(i);
var li = $('<li style="color: ' + color + '"><span style="color: black">' + this.list[i] + '</span></li>');
li.mouseenter({"index": i}, $.proxy(hoverIn, this)).mouseleave({"index": i}, $.proxy(hoverOut, this));
ul.append(li);
li.mouseenter({"index": i}, $.proxy(hoverIn, this));
li.mouseleave({"index": i}, $.proxy(hoverOut, this));
this.legends.push(li);
}

View File

@ -9,11 +9,17 @@
this[name] = definition(function (id) { return this[id];});
}
})('Navi', function (require) {
var Navi = function (owner, container) {
this.node = $(container);
this.owner = owner;
var DataV = require('DataV');
var Navi = DataV.extend(DataV.Chart, {
initialize: function (container) {
this.node = $(container);
}
});
Navi.prototype.init = function () {
this.naviBackWidth = 80;
var conf = this.owner.defaults;
var conf = this.defaults;
this.node.css({
"border-top": "1px solid #ddd",
"border-bottom": "1px solid #ddd",
@ -52,9 +58,10 @@
that.owner.fire('changeLevel');
});
};
Navi.prototype.render = function () {
var owner = this.owner;
var level = owner.defaults.moreConfig.level;
this.init();
var level = this.defaults.moreConfig.level;
this.clear();
for (var i = 0; i <= level; i++) {
this.naviTrace.append($("<span> &gt; </span>"));

141
lib/charts/path_label.js Normal file
View File

@ -0,0 +1,141 @@
/*global Raphael, d3, $, define, _ */
/*!
* PathLabel的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('PathLabel', function (require) {
var DataV = require('DataV');
//pathLabel
var PathLabel = DataV.extend(DataV.Chart, {
initialize: function (stream) {
this.stream = stream;
}
});
PathLabel.prototype.render = function () {
this.clear();
var stream = this.stream;
var paths = stream.chart.paths;
var conf = stream.defaults;
var pathSource = stream.chart.pathSource;
var labels = [];
var getLabelLocation = function (locArray, el) {
var x = 0,
y = 0,
i;
var ratioMargin = 0.15;
var index = 0;
var max = 0;
var box = el.getBBox();
var xInterval;
var minTop, maxBottom;
var showLabel = true;
var loc;
var height;
xInterval = Math.ceil(box.width / (locArray[1].x - locArray[0].x) / 2);
if (xInterval === 0) {
xInterval = 1;
}
locArray.forEach(function (d, i, array) {
var m = Math.max(ratioMargin * array.length, xInterval);
if (i >= m && i <= array.length - m) {
if (d.y > max) {
minTop = d.y0 - d.y;
maxBottom = d.y0;
max = d.y;
index = i;
}
}
});
for (i = index - xInterval; i <= index + xInterval; i++) {
if (i < 0 || i >= locArray.length) {
height = 0;
showLabel = false;
break;
}
loc = locArray[i];
//top's y is small
if (loc.y0 - loc.y > minTop) {
minTop = loc.y0 - loc.y;
}
if (loc.y0 < maxBottom) {
maxBottom = loc.y0;
}
}
if (showLabel && maxBottom - minTop >= box.height * 0.8) {
x = locArray[index].x;
y = (minTop + maxBottom) / 2;
} else {
showLabel = false;
}
return {
x: x,
y: y,
showLabel: showLabel
};
};
stream.labels = labels;
var i, l, label, path;
for (i = 0, l = paths.length; i < l; i++) {
path = paths[i];
label = stream.chart.paper.text(0, 0,
conf.pathLabel ?
stream.getDisplayRowInfo(i).rowName + " " + (Math.round(stream.getDisplayRowInfo(i).rowSum * 10000) / 100) + "%" : "")
.attr({
"text-anchor": "middle",
"fill": "white",
"font-size": conf.fontSize,
"font-family": "微软雅黑"
});
label.labelLoc = getLabelLocation(pathSource[i], label);
if (label.labelLoc.showLabel) {
label.attr({
"x": label.labelLoc.x,
"y": label.labelLoc.y
});
} else {
label.attr({"opacity": 0});
}
if (i === 0 && stream.getDisplayRowInfo(i).rowIndex === -1) {
path.attr({"cursor": "pointer"});
label.attr({"cursor": "pointer"});
} else {
path.attr({"cursor": "auto"});
label.attr({"cursor": "auto"});
}
labels.push(label);
}
};
PathLabel.prototype.hidden = function () {
this.stream.labels.forEach(function (d) {
d.hide();
});
};
PathLabel.prototype.show = function () {
this.stream.labels.forEach(function (d) {
if (d.labelLoc.showLabel) {
d.show();
}
});
};
PathLabel.prototype.clear = function () {
var stream = this.stream;
if (stream.labels) {
stream.labels.forEach(function (d) {
d.remove();
});
}
};
return PathLabel;
});

View File

@ -11,52 +11,71 @@
})('Percentage', function (require) {
var DataV = require('DataV');
var Percentage = DataV.extend(DataV.Widget, {
var Percentage = DataV.extend(DataV.Chart, {
initialize: function (container) {
this.node = $(container);
this.limit = 20;
this.from = 0;
this.to = 0;
/**
* 类型纬度
*/
this.dimension.type = {
type: "string",
required: true,
index: 1
};
/**
* 值纬度
*/
this.dimension.value = {
type: "number",
required: true,
index: 2
};
}
});
Percentage.prototype.init = function () {
var owner = this.owner;
var conf = owner.defaults;
var conf = this.defaults;
this.paper = new Raphael(this.node[0], conf.percentageWidth, conf.chartHeight);
this.node.css({
"width": conf.percentageWidth + "px",
"height": conf.chartHeight + "px",
"width": conf.percentageWidth,
"height": conf.chartHeight,
"float": "left",
"margin-bottom": "0px",
"border-bottom": "0px",
"padding-bottom": "0px"
});
this.statDataMaxY = d3.max(owner.statisticData.columnSum);
};
Percentage.prototype.setSource = function (source, map) {
map = this.map(map);
this.grouped = _.groupBy(source, map.type);
this.types = _.keys(this.grouped);
if (this.types.length > this.limit) {
this.to = this.limit;
}
};
Percentage.prototype.render = function () {
this.init();
var owner = this.owner;
if (!owner.defaults.moreConfig.more) {
return;
}
var conf = owner.defaults;
var maxY = owner.chart.getMaxY() / this.statDataMaxY;
var y = maxY > 0.1 ? (1 - maxY) * conf.chartHeight + conf.fontSize * 2 / 3
: (1 - maxY) * conf.chartHeight - conf.fontSize * 2 / 3;
var conf = this.defaults;
var y = conf.fontSize * 2 / 3;
if (!this.rect) {//init
this.rect = this.paper.rect(0, (1 - maxY) * conf.chartHeight, conf.percentageWidth, maxY * conf.chartHeight)
this.rect = this.paper.rect(0, 0, conf.percentageWidth, conf.chartHeight)
.attr({
"fill": "#f4f4f4",
"stroke": "#aaa",
"stroke-width": 0.5
});
this.text = this.paper.text(conf.percentageWidth / 2, y, Math.round(maxY * 100) + "%")
this.text = this.paper.text(conf.percentageWidth / 2, y, Math.round(100) + "%")
.attr({"text-anchor": "middle"});
}
this.rect.animate({"y": (1 - maxY) * conf.chartHeight, "height": maxY * conf.chartHeight}, 750);
this.text.attr({
"text": Math.round(maxY * 100) + "%"
}).animate({"y": y}, 750);
// this.rect.animate({"y": (1 - maxY) * conf.chartHeight, "height": maxY * conf.chartHeight}, 750);
// this.text.attr({
// "text": Math.round(maxY * 100) + "%"
// }).animate({"y": y}, 300);
};
return Percentage;

2113
lib/charts/stream.js.bak Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

126
lib/charts/stream_axis.js Normal file
View File

@ -0,0 +1,126 @@
/*global Raphael, d3, $, define, _ */
/*!
* Stream的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('StreamAxis', function (require) {
var DataV = require('DataV');
DataV.Axis = require('Axis');
var Axis = DataV.extend(DataV.Chart, {
initialize: function (container) {
this.node = $(container);
/**
* 时间纬度
*/
this.dimension.x = {
type: "string",
required: true,
index: 0
};
}
});
Axis.prototype.setSource = function (source, map) {
map = this.map(map);
this.grouped = _.groupBy(source, map.x);
this.axis = _.keys(this.grouped);
};
Axis.prototype.init = function () {
var conf = this.defaults;
this.paper = new Raphael(this.node[0], conf.legendBesidesWidth, conf.axisHeight);
this.node.css({
"margin-top": "0px",
"border-top": "1px solid #ddd",
"height": conf.axisHeight + "px"
});
};
Axis.prototype.render = function () {
this.init();
this.clear();
//all date strings' format are same, string length are same
var conf = this.defaults,
that = this;
getPopPath = function (El) {
//down pop
var x = 0,
y = 0,
size = 4,
cw = 23,
bb = {height: 8};
if (El) {
bb = El.getBBox();
bb.height *= 0.6;
cw = bb.width / 2 - size;
}
return [
'M', x, y,
'l', size, size, cw, 0,
'a', size, size, 0, 0, 1, size, size,
'l', 0, bb.height,
'a', size, size, 0, 0, 1, -size, size,
'l', -(size * 2 + cw * 2), 0,
'a', size, size, 0, 0, 1, -size, -size,
'l', 0, -bb.height,
'a', size, size, 0, 0, 1, size, -size,
'l', cw, 0,
'z'
].join(',');
};
var left = conf.percentageWidth,
right = conf.legendBesidesWidth - conf.percentageWidth;
var tempWord = this.paper.text(0, 0, this.axis[0]);
var tickNumber = Math.floor((right - left) / tempWord.getBBox().width / 2) + 1;
tempWord.remove();
this.dateScale = d3.scale.linear()
.domain([0, this.axis.length - 1])
.range([left, right]);
DataV.Axis().scale(this.dateScale)
.ticks(tickNumber)
.tickSize(6, 3, 3)
.tickAttr({"stroke": "none"})
.minorTickAttr({"stroke": "none"})
.domainAttr({"stroke": "none"})
.tickFormat(function (d) {
return that.axis[d] || "";
})(this.paper);
// this.axisPopText = this.paper.text(0, 11, '')
// .attr({
// "text-anchor": "middle",
// "fill": "#fff",
// "transform": "t" + left + ",0"
// }).hide();
// this.axisPopBubble = this.paper.path(getPopPath(this.axisPopText))
// .attr({
// "fill": "#000",
// "transform": "t" + (-10000) + ",0"
// }).toBack()
// .hide();
};
Axis.prototype.hideTab = function () {
this.axisPopText.hide();
this.axisPopBubble.hide();
};
Axis.prototype.showTab = function () {
this.axisPopText.show();
this.axisPopBubble.show();
};
Axis.prototype.refreshTab = function (timeText, transX) {
this.axisPopText.attr({
"text": timeText
}).transform("t" + transX + ",0");
this.axisPopBubble.transform("t" + transX + ",0");
};
Axis.prototype.clear = function () {
this.paper.clear();
};
return Axis;
});

459
lib/charts/stream_chart.js Normal file
View File

@ -0,0 +1,459 @@
/*global Raphael, d3, $, define, _ */
/*!
* Stream的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Stream', function (require) {
var DataV = require('DataV');
var HoverLine = require('HoverLine');
//streamChart
var Stream = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.node = this.checkContainer(node);
/**
* 类型纬度
*/
this.dimension.type = {
type: "string",
required: true,
index: 1
};
/**
* 时间纬度
*/
this.dimension.x = {
type: "string",
required: true,
index: 0
};
/**
* 值纬度
*/
this.dimension.value = {
type: "number",
required: true,
index: 2
};
this.defaults.width = 500;
this.defaults.height = 300;
this.defaults.offset = "expand";//zero, expand, silhou-ette, wiggle;
this.defaults.order = "default";//default, reverse, inside-out //in this Stream application, it will always be default, the real order is adjusted in Stream's data-process.
this.defaults.animateDuration = 750;
this.defaults.animateOrder = undefined;
this.paths = undefined;
this.source = undefined;
this.layoutData = undefined;
this.pathSource = undefined;
this.setOptions(options);
this.createPaper();
}
});
Stream.prototype.createPaper = function () {
var conf = this.defaults;
this.paper = new Raphael(this.node, conf.width, conf.height);
};
Stream.prototype.setSource = function (source) {
this.source = source;
this.layoutData = this.remapSource(source.slice());
};
Stream.prototype.remapSource = function (data) {
var row = data.length;
var column = data[0].length;
var remap = [];
for (var i = 0; i < row; i++) {
remap[i] = [];
for (var j = 0; j < column; j++) {
remap[i][j] = {};
remap[i][j].x = j;
remap[i][j].y = data[i][j];
}
}
return remap;
};
Stream.prototype.layout = function () {
var conf = this.defaults;
d3.layout.stack().offset(conf.offset).order(conf.order)(this.layoutData);
};
Stream.prototype.generateChartElements = function () {
var conf = this.defaults;
var paper = this.paper,
paths = [],
area = this.generateArea(),
areaString,
colorFunc = this.getColor(),
color,
path;
// set div's background instread;
paper.rect(0, 0, conf.width, conf.height).attr({
"stroke": "none",
"fill": "#e0e0e0"
});
for (var i = 0, l = this.layoutData.length; i < l; i++) {
areaString = area(this.pathSource[i]);
color = colorFunc(i);
path = paper.path(areaString).attr({
fill: color,
stroke: color,
"stroke-width": 1
});
paths[i] = path;
}
this.paths = paths;
};
Stream.prototype.render = function (animate) {
if (animate !== "animate") {
this.clear();
this.layout();
this.generateChartElements();
} else {
this.layout();
this.animate();
}
//hoverLine
this.hoverLine = this.own(new HoverLine());
this.hoverLine.render();//lines should be to front, so at last
};
Stream.prototype.animate = function () {
var time = 0,
area,
colorFunc,
color,
i, l,
_area,
paths = [],
order,
anim,
count = this.paths.length;
var that = this;
var animateCallback = function () {
count -= 1;
if (count > 0) {
return;
}
that.animateCallback();
};
if (typeof this.defaults.animateDuration !== 'undefined') {
time = this.defaults.animateDuration;
}
// if paths have not been created
if (typeof this.paths === 'undefined') {
this.generateChartElements();
}
area = this.generateArea();
colorFunc = this.getColor();
if (typeof this.defaults.animateOrder !== 'undefined') {
order = this.defaults.animateOrder;
} else {
order = d3.range(this.pathSource.length);
}
for (i = 0, l = this.pathSource.length; i < l; i++) {
_area = area(this.pathSource[i]);
paths.push(_area);
}
for (i = 0, l = this.pathSource.length; i < l; i++) {
color = colorFunc(i);
anim = Raphael.animation({"path": paths[i]}, time, animateCallback);
this.paths[order[i]].animate(anim);
}
};
Stream.prototype.animateCallback = function () {
var newOrderPaths = [];
var that = this;
if (typeof this.defaults.animateOrder !== 'undefined') {
this.defaults.animateOrder.forEach(function (d, i) {
newOrderPaths[i] = that.paths[d];
});
this.paths = newOrderPaths;
}
};
Stream.prototype.clear = function () {
this.paper.clear();
};
Stream.prototype.getColor = function (colorJson) {
var colorMatrix = DataV.getColor();
var color;
var colorStyle = colorJson || {};
var colorMode = colorStyle.mode || 'default';
var i, l;
switch (colorMode) {
case "gradient":
l = this.source.length;
// 最大为 colorMatrix.length - 1
var colorL = Math.min(Math.round(l / 5), colorMatrix.length - 1);
var testColor = [colorMatrix[0][0], colorMatrix[colorL][0]];
var test1 = DataV.gradientColor(testColor, "special");
var testColorMatrix = [];
var testColorMatrix1 = [];
for (i = 0; i < l; i++) {
testColorMatrix.push([test1(i / (l - 1)), test1(i / (l - 1))]);
}
for (i = l - 1; i >= 0; i--) {
testColorMatrix1.push(testColorMatrix[i]);
}
colorMatrix = testColorMatrix;
break;
case "random":
case "default":
break;
}
var ratio = colorStyle.ratio || 0;
ratio = Math.max(ratio, 0);
ratio = Math.min(ratio, 1);
var colorArray = colorMatrix.map(function () {
return d3.interpolateRgb.apply(null, [colorMatrix[i][0], colorMatrix[i][1]])(ratio);
});
color = d3.scale.ordinal().range(colorArray);
return color;
};
/*
*/
Stream.prototype.getColor = function () {
var count = this.defaults.colorCount;
var color = this.defaults.gradientColor || ["#8be62f", "#1F4FD8"];
var gradientColor = DataV.gradientColor(color, "special");
var percent = 1 / count;
var gotColors = [];
for (var i = 0; i < count; i++) {
gotColors.push(gradientColor(i * percent));
}
var midderNum = Math.round(count / 2);
return function (num) {
return num % 2 === 0 ? gotColors[midderNum + num / 2] : gotColors[midderNum - (num + 1) / 2];
};
};
Stream.prototype.getMaxY = function () {
return d3.max(this.layoutData, function (d) {
return d3.max(d, function (d) {
return d.y0 + d.y;
});
});
};
Stream.prototype.mapPathSource = function () {
var conf = this.defaults,
maxX = this.layoutData[0].length - 1,//this.digitData[0].length - 1,
maxY = this.getMaxY(),
width = conf.width,
height = conf.height;
var i, j, l, l2, s, ps;
this.pathSource = [];
for (i = 0, l = this.layoutData.length; i < l; i++) {
this.pathSource[i] = [];
for (j = 0, l2 = this.layoutData[0].length; j < l2; j++) {
s = this.layoutData[i][j];
ps = this.pathSource[i][j] = {};
ps.x = s.x * width / maxX;
ps.y0 = height - s.y0 * height / maxY;
ps.y = s.y * height / maxY;
}
}
};
Stream.prototype.generateArea = function () {
this.mapPathSource();
var area = d3.svg.area().x(function (d) {
return d.x;
}).y0(function (d) {
return d.y0;
}).y1(function (d) {
return d.y0 - d.y;
});
return area;
};
Stream.prototype.createInteractive = function () {
$(this.paper.canvas).unbind();//prevent event rebind.
//refactor stream chart's animate function, especially change the callback
var stream = this;
this.animateCallback = function () {
var newOrderPaths = [];
var that = this;
if (typeof this.defaults.animateOrder !== 'undefined') {
this.defaults.animateOrder.forEach(function (d, i) {
newOrderPaths[i] = that.paths[d];
});
this.paths = newOrderPaths;
}
stream.cover.hidden();
if (typeof stream.cover.mouse !== 'undefined') {
stream.hoverLine.show();
stream.floatTag.show();
var mouse = stream.cover.mouse;
$(stream.paper.canvas).trigger("mousemove", [mouse.x, mouse.y]);
$(stream.floatTag).trigger("mousemove", [mouse.x, mouse.y]);
stream.cover.mouse = undefined;
}
stream.pathLabel.show();
};
//chart mouseenter
var mouseenter = function () {
stream.hoverLine.show();
stream.fire('enter');
};
//chart mouseleave
var mouseleave = function () {
stream.hoverLine.hidden();
var index;
//recover prepath;
if (typeof stream.prePath !== 'undefined') {
stream.prePath.attr({"opacity": 1, "stroke-width": 1});
// set legend
index = stream.prePath.index;
stream.prePath = undefined;
}
stream.fire('leave', index);
};
//chart click
var click = function (e) {
var stream = e.data.stream;
var count = stream.paths.length;
var animateCallback = function () {
count -= 1;
if (count > 0) {
return;
}
stream.cover.hidden();
if (typeof stream.cover.mouse !== 'undefined') {
stream.hoverLine.show();
stream.floatTag.show();
var canvas = $(stream.paper.canvas);
var mouse = stream.cover.mouse;
canvas.trigger("mousemove", [mouse.x, mouse.y]);
canvas.trigger("mousemove", [mouse.x, mouse.y]);
stream.cover.mouse = undefined;
}
stream.pathLabel.show();
};
//more expand
var path = stream.prePath;
if (typeof path !== 'undefined' && path.index === 0 && stream.getDisplayRowInfo(path.index).rowIndex === -1) {
stream.defaults.moreConfig.level += 1;
stream.cover.show();
stream.cover.mouse = {x: e.pageX, y: e.pageY};
//redraw
stream.processData("slicedData");
stream.render("renderComponents");
//hidden
stream.hoverLine.hidden();
stream.floatTag.hidden();
stream.pathLabel.hidden();
stream.paths.forEach(function (d) {
d.attr({transform: "s1,0.001,0," + stream.defaults.chartHeight});
d.animate({transform: "t0,0"}, 750, "linear", animateCallback);
});
}
//drop
if (typeof stream.prePath !== 'undefined' && stream.prePath.index > 0) {
(function (index) {
var order = d3.range(stream.displayData.digitData.length);
order.forEach(function (d, i, array) {
if (i === 0) {
array[i] = index;
} else if (i <= index) {
array[i] = i - 1;
}
});
stream.cover.show();
stream.cover.mouse = {x: e.pageX, y: e.pageY};
//stream.displayDataDropReorder(stream.prePath.index);
stream.getDisplayData({"type": "changeOrder", "order": order});
stream.chart.setOptions({"animateOrder": order});
stream.render("renderComponents", "animate");
stream.pathLabel.hidden();
}(stream.prePath.index));
}
};
//chart mousemove
var mousemove = function (e, pageX, pageY) {
var offset = $(this).parent().offset();
var x = (e.pageX || pageX) - offset.left,
y = (e.pageY || pageY) - offset.top;
var path,
pathSource = stream.pathSource,
pathIndex;
var xIdx = Math.floor((x / (stream.defaults.chartWidth / (stream.source[0].length - 1) / 2) + 1) / 2);
//get path and pathIndex
for (var i = 0, l = pathSource.length; i < l; i++) {
if (y >= pathSource[i][xIdx].y0 - pathSource[i][xIdx].y && y <= pathSource[i][xIdx].y0) {
path = stream.paths[i];
pathIndex = i;
break;
}
}
if (typeof path === 'undefined') {
return;
}
var pre;
//recover prepath;
if (typeof stream.prePath !== 'undefined') {
stream.prePath.attr({"opacity": 1, "stroke-width": 1});
pre = stream.prePath.index;
}
//change new path;
stream.prePath = path;
stream.prePath.index = pathIndex;
path.attr({"opacity": 0.5, "stroke-width": 0});
stream.fire('move', pre, pathIndex, xIdx);
//set indicator and highlight line new position
stream.hoverLine.refresh(xIdx, pathIndex);
//customevent;
if (stream.defaults.customEventHandle.mousemove) {
stream.defaults.customEventHandle.mousemove.call(stream,
{"timeIndex": xIdx, "pathIndex": pathIndex});
}
};
$(this.paper.canvas).bind("mouseenter", mouseenter)
.bind("mouseleave", mouseleave)
.bind("click", click)
.bind("mousemove", mousemove);
};
return Stream;
});

34
lib/charts/tip.js Normal file
View File

@ -0,0 +1,34 @@
/*global Raphael, d3, $, define, _ */
/*!
* StreamLegend的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Tip', function (require) {
var DataV = require('DataV');
//floatTag
var Tip = DataV.extend(DataV.Chart, {
initialize: function (container) {
this.container = container;
this.node = DataV.FloatTag()(this.container);
this.hidden();
},
getContent: function (index) {
return "呵呵";
}
});
// stream.floatTag.setContent(stream.getFloatTagContent(stream.displayData.allInfos[i][0]));
Tip.prototype.setContent = function (index) {
var html = this.getContent(index);
this.node.html(html);
};
Tip.prototype.setCss = function (cssJson) {
this.node.css(cssJson);
};
return Tip;
});

View File

@ -532,28 +532,25 @@
* 拥有一个组件
*/
Chart.prototype.own = function (widget) {
// 传递defaults给子组件
widget.setOptions(this.defaults);
widget.owner = this;
this.widgets.push(widget);
return widget;
};
Chart.prototype.show = function () {
$(this.node).css('visibility', 'visible');
return this;
};
Chart.prototype.hidden = function () {
$(this.node).css('visibility', 'hidden');
return this;
};
DataV.Chart = Chart;
var Widget = DataV.extend(EventProxy, {
defaults: {}
});
Widget.prototype.show = function () {
this.node.css('visibility', 'visible');
return this;
};
Widget.prototype.hidden = function () {
this.node.css('visibility', 'hidden');
return this;
};
DataV.Widget = Widget;
/**
* 浮动标签
*/