mirror of
https://github.com/TBEDP/datavjs.git
synced 2026-01-25 15:07:00 +00:00
commit
1d2c16f94c
@ -1,39 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Column</title>
|
||||
<style type="text/css"></style>
|
||||
</head>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Column</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="../../build/deps.js"></script>
|
||||
<script src="../../deps/seajs/sea.js"></script>
|
||||
<script>
|
||||
var dir = location.href.replace(/\\/g, '/').replace(/\/[^\/]*$/, '');
|
||||
seajs.config({
|
||||
alias: {
|
||||
'DataV': dir + '/../../lib/datav.js',
|
||||
'Column': dir + '/../../lib/charts/column.js'
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<div id="chart"></div>
|
||||
<script>
|
||||
seajs.use(["DataV", "Column"], function (DataV, Column) {
|
||||
var column = new Column("chart", {
|
||||
"width": 1024,
|
||||
"height": 600,
|
||||
"margin": 30,
|
||||
"typeNames": ["Y", "Z"]
|
||||
});
|
||||
DataV.csv("DataExample.csv", function (dataSource) {
|
||||
column.setSource(dataSource);
|
||||
column.render();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
<body>
|
||||
<script src="../../build/deps.js"></script>
|
||||
<script src="../../lib/datav.js"></script>
|
||||
<script src="../../lib/charts/column.js"></script>
|
||||
<div id="chart"></div>
|
||||
<script>
|
||||
var source = [
|
||||
['X','2012/3/1',18],
|
||||
['Y','2012/3/1',102],
|
||||
['Z','2012/3/1',102],
|
||||
['X','2012/3/2',60],
|
||||
['Y','2012/3/2',46],
|
||||
['Z','2012/3/2',102],
|
||||
['X','2012/3/3',200],
|
||||
['Z','2012/3/3',102],
|
||||
['Y','2012/3/3',12],
|
||||
['X','2012/3/4',86],
|
||||
['Z','2012/3/4',102],
|
||||
['Y','2012/3/4',158],
|
||||
['X','2012/3/5',4],
|
||||
['Y','2012/3/5',190],
|
||||
['Z','2012/3/5',102],
|
||||
['X','2012/3/6',314],
|
||||
['Y','2012/3/6',336],
|
||||
['Z','2012/3/6',336],
|
||||
['X','2012/3/7',72],
|
||||
['Y','2012/3/7',124],
|
||||
['Z','2012/3/7',336],
|
||||
['X','2012/3/8',42],
|
||||
['Y','2012/3/8',74],
|
||||
['Z','2012/3/8',336],
|
||||
['X','2012/3/9',418],
|
||||
['Y','2012/3/9',418],
|
||||
['Z','2012/3/9',418],
|
||||
['X','2012/3/10',68],
|
||||
['Y','2012/3/10',324],
|
||||
['Z','2012/3/10',336],
|
||||
['X','2012/3/11',68],
|
||||
['Y','2012/3/11',68],
|
||||
['Z','2012/3/11',68]
|
||||
];
|
||||
|
||||
var column = new Column("chart", {
|
||||
"width": 980,
|
||||
"height": 600,
|
||||
"gap": 10,
|
||||
"yBase": 50
|
||||
});
|
||||
column.setSource(source, {
|
||||
column: 0,
|
||||
x: 1,
|
||||
value: 2
|
||||
});
|
||||
column.render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,65 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Column</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="../../build/deps.js"></script>
|
||||
<script src="../../lib/datav.js"></script>
|
||||
<script src="../../lib/charts/column.js"></script>
|
||||
<div id="chart"></div>
|
||||
<script>
|
||||
var source = [
|
||||
['X','2012/3/1',18],
|
||||
['Y','2012/3/1',102],
|
||||
['Z','2012/3/1',102],
|
||||
['X','2012/3/2',60],
|
||||
['Y','2012/3/2',46],
|
||||
['Z','2012/3/2',102],
|
||||
['X','2012/3/3',200],
|
||||
['Z','2012/3/3',102],
|
||||
['Y','2012/3/3',12],
|
||||
['X','2012/3/4',86],
|
||||
['Z','2012/3/4',102],
|
||||
['Y','2012/3/4',158],
|
||||
['X','2012/3/5',4],
|
||||
['Y','2012/3/5',190],
|
||||
['Z','2012/3/5',102],
|
||||
['X','2012/3/6',314],
|
||||
['Y','2012/3/6',336],
|
||||
['Z','2012/3/6',336],
|
||||
['X','2012/3/7',72],
|
||||
['Y','2012/3/7',124],
|
||||
['Z','2012/3/7',336],
|
||||
['X','2012/3/8',42],
|
||||
['Y','2012/3/8',74],
|
||||
['Z','2012/3/8',336],
|
||||
['X','2012/3/9',418],
|
||||
['Y','2012/3/9',418],
|
||||
['Z','2012/3/9',418],
|
||||
['X','2012/3/10',68],
|
||||
['Y','2012/3/10',324],
|
||||
['Z','2012/3/10',336],
|
||||
['X','2012/3/11',68],
|
||||
['Y','2012/3/11',68],
|
||||
['Z','2012/3/11',68]
|
||||
];
|
||||
|
||||
var column = new Column("chart", {
|
||||
"width": 980,
|
||||
"height": 600,
|
||||
"margin": 50,
|
||||
"gap": 20,
|
||||
"yBase": 50
|
||||
});
|
||||
column.setSource(source, {
|
||||
column: 0,
|
||||
x: 1,
|
||||
value: 2
|
||||
});
|
||||
column.render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -13,12 +13,20 @@
|
||||
|
||||
/**
|
||||
* Column构造函数
|
||||
* Creates Column in a DOM node with id "chart", default width is 522; height is 522px;
|
||||
* Creates Column in a DOM node with id "chart"
|
||||
* Options:
|
||||
*
|
||||
* - `width` 宽度,默认为节点宽度
|
||||
* - `yBase` 纵坐标的基线值,有的以0为起始值,有的则以数据中的最小值为起始值
|
||||
* - `width` 宽度,默认为522,单位像素
|
||||
* - `height` 高度,默认为522,单位像素
|
||||
* - `yBase` 纵坐标的基线值,默认为0,可以设置为任意数值;为undefined时,以数据中的最小值为起始值
|
||||
* - `gap` 组与组之间的缝隙宽度
|
||||
* - `showLegend` 是否显示图例
|
||||
* - `legendWidth` 图例的宽度
|
||||
* - `margin` 图表的间距,依次为上右下左
|
||||
* - `xTickNumber` 横轴刻度数
|
||||
* - `yTickNumber` 纵轴刻度数
|
||||
* - `formatLabel` 横轴提示格式化函数,传入横轴值,默认函数传出原始值
|
||||
* - `formatYScale` 纵轴刻度格式化函数,传入纵轴刻度值,
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
@ -38,7 +46,7 @@
|
||||
this.dimension.column = {
|
||||
type: "string",
|
||||
required: true,
|
||||
index: 0
|
||||
index: undefined
|
||||
};
|
||||
/**
|
||||
* 横向纬度
|
||||
@ -61,20 +69,33 @@
|
||||
// canvas parameters
|
||||
this.defaults.width = 522;
|
||||
this.defaults.height = 522;
|
||||
this.defaults.margin = 50;
|
||||
|
||||
this.defaults.margin = [50, 50, 50, 50];
|
||||
|
||||
this.defaults.gap = 15;
|
||||
this.defaults.circleR = 3;
|
||||
this.defaults.barColor = ["#308BE6","#8EEC00","#DDDF0D"];
|
||||
this.defaults.xTickNumber = 5;
|
||||
this.defaults.yTickNumber = 5;
|
||||
|
||||
this.defaults.yBase = undefined;
|
||||
this.defaults.yBase = 0;
|
||||
|
||||
this.defaults.showLegend = true;
|
||||
this.defaults.legendWidth = 100;
|
||||
//图例区域的左上顶点坐标x,y,宽,高
|
||||
this.defaults.legendArea = [422, 50, 472, 220];
|
||||
//散点矩阵区域的左上顶点坐标x,y,宽,高
|
||||
this.defaults.diagramArea = [50, 50, 422, 472];
|
||||
this.columnSet = [];
|
||||
this.formatLabel = function (text) {
|
||||
return text;
|
||||
};
|
||||
this.formatYScale = function (text) {
|
||||
return text;
|
||||
};
|
||||
this.formatValue = function (value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
this.setOptions(options);
|
||||
this.createCanvas();
|
||||
@ -145,20 +166,26 @@
|
||||
} else {
|
||||
dataTable = source;
|
||||
}
|
||||
this.columns = _.groupBy(dataTable, map.column);
|
||||
// 不指定列,将当前数据作为一列
|
||||
this.columns = (typeof map.column === 'undefined') ? {column: dataTable} : _.groupBy(dataTable, map.column);
|
||||
var that = this;
|
||||
_.each(this.columns, function (group, key) {
|
||||
that.columns[key] = _.sortBy(group, map.x);
|
||||
});
|
||||
this.columnCount = _.keys(this.columns).length;
|
||||
|
||||
conf.xAxisData = _.pluck(_.first(_.values(this.columns)), map.x);
|
||||
conf.xTickNumber = Math.min(conf.xAxisData.length, conf.xTickNumber);
|
||||
// 纵坐标的范围
|
||||
conf.yExtent = d3.extent(dataTable, function (item) {
|
||||
var yExtent = d3.extent(dataTable, function (item) {
|
||||
return item[map.value];
|
||||
});
|
||||
// 纵坐标基线值
|
||||
if (conf.yBase !== undefined) {
|
||||
conf.yExtent.push(conf.yBase);
|
||||
conf.yExtent = d3.extent(conf.yExtent);
|
||||
if (typeof conf.yBase !== 'undefined') {
|
||||
yExtent.push(conf.yBase);
|
||||
}
|
||||
yExtent = d3.extent(yExtent);
|
||||
// 最大值放大1/10
|
||||
conf.yExtent = [yExtent[0], yExtent[1] * 1.1];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -166,16 +193,20 @@
|
||||
*/
|
||||
Column.prototype.setAxis = function () {
|
||||
var conf = this.defaults;
|
||||
var tagWidth = conf.width / 5 > 50 ? 50 : conf.width / 5;
|
||||
conf.legendArea = [conf.width - tagWidth - conf.margin, 0, conf.width, conf.height];
|
||||
conf.diagramArea = [0, 0, conf.width - tagWidth - conf.margin, conf.height];
|
||||
var w = conf.diagramArea[2] - 2 * conf.margin;
|
||||
var h = conf.diagramArea[3] - conf.margin;
|
||||
if (conf.showLegend) {
|
||||
conf.legendArea = [conf.width - conf.legendWidth, 0, conf.width, conf.height];
|
||||
} else {
|
||||
conf.legendWidth = 0;
|
||||
conf.legendArea = [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
var margin = conf.margin;
|
||||
conf.diagramArea = [margin[3], margin[0], conf.width - conf.legendWidth - margin[1], conf.height - margin[2]];
|
||||
|
||||
//设置x轴
|
||||
this.x = d3.scale.linear().domain([0, conf.xAxisData.length]).range([conf.margin, w]);
|
||||
this.x = d3.scale.linear().domain([0, conf.xAxisData.length]).range([conf.diagramArea[0], conf.diagramArea[2]]);
|
||||
//设置y轴
|
||||
this.value = d3.scale.linear().domain(conf.yExtent).range([h, conf.margin]);
|
||||
this.value = d3.scale.linear().domain(conf.yExtent).range([conf.diagramArea[3], conf.diagramArea[1]]);
|
||||
var xRange = this.x.range();
|
||||
var valueRange = this.value.range();
|
||||
var axis = this.axisPosition = {
|
||||
@ -187,7 +218,9 @@
|
||||
var columnsMaxLen = _.max(this.columns, function (column) {
|
||||
return column.length;
|
||||
}).length;
|
||||
this.barWidth = (axis.right - axis.left - columnsMaxLen * conf.gap) / columnsMaxLen / _.keys(this.columns).length;
|
||||
var width = conf.diagramArea[2] - conf.diagramArea[0];
|
||||
var height = conf.diagramArea[3] - conf.diagramArea[1];
|
||||
this.barWidth = width / columnsMaxLen / this.columnCount - conf.gap;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -202,18 +235,18 @@
|
||||
var axisLines = paper.set();
|
||||
var tickText = paper.set();
|
||||
var axis = this.axisPosition;
|
||||
var ticks;
|
||||
// X轴
|
||||
ticks = this.x.ticks(conf.xTickNumber);
|
||||
console.log(ticks);
|
||||
var range = this.x.range();
|
||||
var ticks = this.x.ticks(conf.xTickNumber);
|
||||
var formatLabel = conf.formatLabel || this.formatLabel;
|
||||
|
||||
// 修复显示不从第一个x轴单位显示的bug
|
||||
for (j = 0; j < ticks.length; j++) {
|
||||
// 修改x轴单位显示在所有Column组的中间位置
|
||||
// 修复x轴单位对于柱位置的偏移
|
||||
var x = this.x(ticks[j]) + conf.gap / 2 + this.columnCount * Math.floor(this.barWidth) / 2;
|
||||
tickText.push(paper.text(x, axis.down + 14, conf.xAxisData[ticks[j]]).rotate(0, x, axis.up));
|
||||
var x = this.x(ticks[j]) + conf.gap / 2 + this.columnCount * this.barWidth / 2;
|
||||
var text = conf.xAxisData[ticks[j]];
|
||||
tickText.push(paper.text(x, axis.down + 14, formatLabel(text)).rotate(0, x, axis.up));
|
||||
// 画x轴刻度线
|
||||
axisLines.push(paper.path("M" + x + "," + axis.down + "L" + x + "," + (axis.down + 5)));
|
||||
}
|
||||
|
||||
@ -224,6 +257,7 @@
|
||||
"text-anchor": "middle"
|
||||
});
|
||||
|
||||
// 绘制Y轴
|
||||
axisLines.push(paper.path("M" + axis.left + "," + axis.up + "L" + axis.left + "," + axis.down));
|
||||
axisLines.attr({
|
||||
"stroke": "#D7D7D7",
|
||||
@ -231,8 +265,9 @@
|
||||
});
|
||||
//Y轴
|
||||
ticks = this.value.ticks(conf.yTickNumber);
|
||||
var formatYScale = conf.formatYScale || this.formatYScale;
|
||||
for (j = 0; j < ticks.length; j++) {
|
||||
tickText.push(paper.text(axis.left - 8, this.value(ticks[j]), ticks[j]).attr({
|
||||
tickText.push(paper.text(axis.left - 8, this.value(ticks[j]), formatYScale(ticks[j])).attr({
|
||||
"fill": "#878791",
|
||||
"fill-opacity": 0.7,
|
||||
"font-size": 12,
|
||||
@ -254,7 +289,7 @@
|
||||
}
|
||||
hLines.attr({
|
||||
"stroke": "#ECECEC",
|
||||
"stroke-width": 1
|
||||
"stroke-width": 0.1
|
||||
});
|
||||
};
|
||||
|
||||
@ -286,12 +321,17 @@
|
||||
return that.clicked ? that.clickedColumnIndex === columnIndex : true;
|
||||
});
|
||||
currentSet.forEach(function (set, columnIndex) {
|
||||
set.animate({
|
||||
"fill-opacity": 0.3
|
||||
}, 10);
|
||||
set[xIndex].animate({
|
||||
"fill-opacity":1
|
||||
}, 10);
|
||||
set.forEach(function (bar, index) {
|
||||
if (index === xIndex) {
|
||||
bar.stop().attr({
|
||||
"fill-opacity": 1
|
||||
});
|
||||
} else {
|
||||
bar.stop().animate({
|
||||
"fill-opacity": 0.3
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var hovered = currentSet.map(function (set) {
|
||||
@ -320,9 +360,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
var formatValue = conf.formatValue || that.formatValue;
|
||||
hovered.forEach(function (item, columnIndex) {
|
||||
var yPos = y[columnIndex];
|
||||
var valueLabel = '' + values[columnIndex][xIndex][dim.value.index];
|
||||
var valueLabel = '' + formatValue(values[columnIndex][xIndex][dim.value.index]);
|
||||
var textWidth = 5 * valueLabel.length + 20;
|
||||
|
||||
var rect = paper.rect(xPos, yPos - 10, textWidth, 20, 2).attr({
|
||||
@ -334,7 +375,7 @@
|
||||
"fill" : conf.barColor[columnIndex],
|
||||
"stroke" : conf.barColor[columnIndex]
|
||||
});
|
||||
var text = paper.text(xPos + 16, yPos, valueLabel).attr({
|
||||
var text = paper.text(xPos + textWidth / 2, yPos, valueLabel).attr({
|
||||
"fill": "#ffffff",
|
||||
"fill-opacity": 1,
|
||||
"font-weight": "bold",
|
||||
@ -347,7 +388,8 @@
|
||||
xPos = hovered.reduce(function (pre, cur) {
|
||||
return pre + cur.attrs.x;
|
||||
}, 0) / hovered.length + barWidth / 2;
|
||||
var xLabel = '' + values[columnIndex][xIndex][dim.x.index];
|
||||
var formatLabel = conf.formatLabel || this.formatLabel;
|
||||
var xLabel = formatLabel(values[columnIndex][xIndex][dim.x.index]);
|
||||
var textWidth = 6 * xLabel.length + 20;
|
||||
//axis x rect
|
||||
var rect = paper.rect(xPos - textWidth / 2, axis.down + 8, textWidth, 20, 2).attr({
|
||||
@ -364,9 +406,9 @@
|
||||
"text-anchor": "middle"
|
||||
});
|
||||
var arrow = paper.path("M" + (xPos - 4) + "," + (axis.down + 8) + "L" + xPos + "," + axis.down +
|
||||
"L" + (xPos + 4) + "," + (axis.down + 8) + "H" + xPos + "Z").attr({
|
||||
"fill": "#5F5F5F",
|
||||
"stroke": "#5F5F5F"
|
||||
"L" + (xPos + 4) + "," + (axis.down + 8) + "H" + xPos + "Z").attr({
|
||||
"fill": "#5F5F5F",
|
||||
"stroke": "#5F5F5F"
|
||||
});
|
||||
tagSet.push(rect, text, arrow);
|
||||
};
|
||||
@ -377,11 +419,11 @@
|
||||
var currentSet = columnSet.filter(function (set, columnIndex) {
|
||||
return that.clicked ? that.clickedColumnIndex === columnIndex : true;
|
||||
});
|
||||
tagSet.animate({"opacity": 0}, 1000, function () {
|
||||
tagSet.stop().animate({"opacity": 0}, 300, function () {
|
||||
tagSet.remove();
|
||||
});
|
||||
currentSet.forEach(function (set, columnIndex) {
|
||||
set.attr({"fill-opacity": 1});
|
||||
set.stop().animate({"fill-opacity": 1}, 100);
|
||||
});
|
||||
};
|
||||
|
||||
@ -397,8 +439,8 @@
|
||||
"stroke": "none"
|
||||
});
|
||||
rect.data('column', index).data('index', i);
|
||||
rect.mouseover(mouseOverBar);
|
||||
rect.mouseout(mouseOutBar);
|
||||
rect.mouseover(_.debounce(mouseOverBar, 300));
|
||||
rect.mouseout(_.debounce(mouseOutBar, 300));
|
||||
columnSet[index].push(rect);
|
||||
});
|
||||
});
|
||||
@ -496,12 +538,15 @@
|
||||
* @param {Object} options options json object for determin column style.
|
||||
*/
|
||||
Column.prototype.render = function (options) {
|
||||
var conf = this.defaults;
|
||||
this.setOptions(options);
|
||||
this.canvas.clear();
|
||||
this.setAxis();
|
||||
this.drawAxis();
|
||||
this.drawDiagram();
|
||||
this.drawLegend();
|
||||
if (conf.showLegend) {
|
||||
this.drawLegend();
|
||||
}
|
||||
};
|
||||
/*!
|
||||
* 导出
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "datavjs",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/TBEDP/datavjs.git"
|
||||
@ -11,10 +11,12 @@
|
||||
"author": "DataV",
|
||||
"license": "MIT",
|
||||
"description": "DataV.js is a JavaScript library for data visualization",
|
||||
"dependencies": {
|
||||
"uglify-js": "*"
|
||||
"devDependencies": {
|
||||
"uglify-js": "*",
|
||||
"anywhere": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run build & anywhere 8888",
|
||||
"build": "node bin/build.js"
|
||||
},
|
||||
"tracker": "UA-17170593-4"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user