mirror of
https://github.com/TBEDP/datavjs.git
synced 2025-12-08 19:45:52 +00:00
337 lines
12 KiB
JavaScript
337 lines
12 KiB
JavaScript
/*global Raphael, d3 */
|
|
/*!
|
|
* Bullet的兼容性定义
|
|
*/
|
|
;(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];});
|
|
}
|
|
})('Bullet', function (require) {
|
|
var DataV = require('DataV');
|
|
var Axis = require('Axis');
|
|
|
|
/*
|
|
* Bullet构造函数
|
|
* Options:
|
|
*
|
|
* - `width` 宽度,默认为节点宽度
|
|
*
|
|
* Examples:
|
|
* ```
|
|
* //Create bullet in a dom node with id "chart", width is 500; height is 600px;
|
|
* var bullet = new Bullet("chart", {
|
|
* "width": 500,
|
|
* "height": 600,
|
|
* "margin": [10, 10, 20, 70]
|
|
* });
|
|
* //Create bullet with log base;
|
|
* var log = new Bullet("chart2", {
|
|
* width: 300,
|
|
* height: 60,
|
|
* margin: [10, 10, 20, 70],
|
|
* backgroundColor: ["#66f", "#ddf"],
|
|
* measureColor: ["#000", "#000"],
|
|
* markerColor: "#44f",
|
|
* axisStyle: "log",
|
|
* logBase: 10
|
|
* });
|
|
* ```
|
|
* @param {Mix} node The dom node or dom node Id
|
|
* @param {Object} options options json object for determin stream style.
|
|
*/
|
|
var Bullet = DataV.extend(DataV.Chart, {
|
|
initialize: function (node, options) {
|
|
this.type = "Bullet";
|
|
this.node = this.checkContainer(node);
|
|
this.defaults = {};
|
|
// Properties
|
|
this.defaults.orient = "horizonal"; // "horizonal", "vertical"
|
|
this.defaults.axisStyle = "linear"; // "linear", "log"
|
|
this.defaults.logBase = Math.E;
|
|
this.defaults.margin = [10, 10, 20, 80];//top, right, bottom, left
|
|
this.defaults.centerBarRatio = 0.3;
|
|
this.defaults.markerWidth = 4;
|
|
this.defaults.markerRatio = 0.7;
|
|
this.defaults.titleRatio = 0.6; //title's text height : subtitle's text height = 6:4
|
|
this.defaults.backgroundColor = ["#666", "#ddd"]; //dark, light
|
|
this.defaults.measureColor = ["steelblue", "#B0C4DE"]; //dark, light
|
|
this.defaults.markerColor = "#000";
|
|
this.defaults.tickDivide = 5;
|
|
|
|
// canvas
|
|
this.defaults.width = 200;
|
|
this.defaults.height = 80;
|
|
this.setOptions(options);
|
|
this.createCanvas();
|
|
}
|
|
});
|
|
|
|
/*!
|
|
* 创建画布
|
|
*/
|
|
Bullet.prototype.createCanvas = function () {
|
|
var conf = this.defaults;
|
|
this.canvas = new Raphael(this.node, conf.width, conf.height);
|
|
};
|
|
|
|
/**
|
|
* 设置数据源
|
|
* Examples:
|
|
* ```
|
|
* bullet.setSource({
|
|
* title: "Sample",
|
|
* subtitle: "ratio",
|
|
* ranges: [0, 0.5, 0.8, 1],
|
|
* measures: [0.7, 0.9],
|
|
* markers: [0.6],
|
|
* rangeTitles: ["below 50%", "top 20% - 50%", "top 20%"],
|
|
* measureTitles: ["value is 0.7", "value is 0.9"],
|
|
* markerTitles: ["mean is 0.6"]
|
|
* })
|
|
* ```
|
|
* @param {Object} source 数据源
|
|
*/
|
|
Bullet.prototype.setSource = function (source) {
|
|
var conf = this.defaults,
|
|
range,
|
|
axisOrient;
|
|
this.data = source;
|
|
if (conf.orient === "horizonal") {
|
|
axisOrient = "bottom";
|
|
range = [conf.margin[3], conf.width - conf.margin[1]];
|
|
} else if (conf.orient === "vertical") {
|
|
axisOrient = "left";
|
|
range = [conf.height - conf.margin[2], conf.margin[0]];
|
|
}
|
|
|
|
if (conf.axisStyle === "linear") {
|
|
this.scale = d3.scale.linear();
|
|
} else if (conf.axisStyle === "log") {
|
|
this.scale = d3.scale.log();
|
|
}
|
|
|
|
this.data.min = this.data.ranges[0];
|
|
this.data.max = this.data.ranges[this.data.ranges.length - 1];
|
|
this.scale.domain([this.data.min, this.data.max])
|
|
.range(range);
|
|
|
|
if (conf.axisStyle === "linear") {
|
|
this.axis = Axis().scale(this.scale).orient(axisOrient).ticks(conf.tickDivide).domainAttr({"stroke": "none"});
|
|
} else if (conf.axisStyle === "log") {
|
|
this.logScale = d3.scale.linear()
|
|
.domain([Math.log(this.data.min)/Math.log(conf.logBase), Math.log(this.data.max)/Math.log(conf.logBase)])
|
|
.range(range);
|
|
this.axis = Axis()
|
|
.orient(axisOrient)
|
|
.scale(this.logScale)
|
|
.ticks(conf.tickDivide)
|
|
.tickFormat(function (d) {return Math.round(Math.pow(conf.logBase, d));})
|
|
.domainAttr({"stroke": "none"});
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* generate bullet dom path
|
|
*/
|
|
Bullet.prototype.generatePaths = function () {
|
|
var conf = this.defaults;
|
|
//get color function
|
|
if (conf.backgroundColor) {
|
|
this.color = d3.interpolateRgb.apply(null, [conf.backgroundColor[0], conf.backgroundColor[1]]);
|
|
}
|
|
if (conf.measureColor) {
|
|
this.measureColor = d3.interpolateRgb.apply(null, [conf.measureColor[0], conf.measureColor[1]]);
|
|
}
|
|
|
|
if (conf.orient === "horizonal") {
|
|
this.paintHorizonal();
|
|
} else if (conf.orient === "vertical") {
|
|
this.paintVertical();
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* paint orient horizonal bullet
|
|
*/
|
|
Bullet.prototype.paintHorizonal = function () {
|
|
var conf = this.defaults;
|
|
var paper = this.canvas,
|
|
data = this.data,
|
|
m = conf.margin,
|
|
ranges = [],
|
|
measures = [],
|
|
markers = [],
|
|
rangeTitles = [],
|
|
i,
|
|
l,
|
|
rect,
|
|
titleRatio,
|
|
w,
|
|
h = conf.height - m[0] - m[2],
|
|
left;
|
|
|
|
//axis
|
|
this.axis(paper).attr({transform: "t" + 0 + ',' + (conf.height - m[2])});
|
|
//color rect
|
|
ranges = data.ranges;
|
|
if (data.rangeTitles) {
|
|
rangeTitles = data.rangeTitles;
|
|
}
|
|
left = m[3];
|
|
for (i = 0, l = ranges.length - 1; i < l; i++) {
|
|
w = this.scale(ranges[i + 1]) - this.scale(ranges[i]);
|
|
rect = paper.rect(left, m[0], w, h)
|
|
.attr({"stroke": "none",
|
|
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
|
|
"title": rangeTitles[i] ? rangeTitles[i] : ""});
|
|
left += w;
|
|
}
|
|
|
|
//measure bar
|
|
data.measures.forEach(function (d, i) {
|
|
var mTitles = data.measureTitles;
|
|
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
|
|
measures.push({measure: d, measureTitle: mTitle});
|
|
});
|
|
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
|
|
left = this.scale(data.min);
|
|
for (i = 0, l = measures.length; i < l; i++) {
|
|
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
|
|
w = this.scale(value) - left;
|
|
paper.rect(left,
|
|
m[0] + h * (1 - conf.centerBarRatio) / 2,
|
|
w,
|
|
h * conf.centerBarRatio)
|
|
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
|
|
left += w;
|
|
}
|
|
|
|
//marker bar
|
|
markers = data.markers;
|
|
for (i = 0, l = markers.length; i < l; i++) {
|
|
paper.rect(this.scale(markers[i]) - conf.markerWidth / 2,
|
|
m[0] + h * (1 - conf.markerRatio) / 2,
|
|
conf.markerWidth,
|
|
h * conf.markerRatio)
|
|
.attr({"stroke": "none", "fill": conf.markerColor,
|
|
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
|
|
}
|
|
|
|
//title
|
|
if (data.title) {
|
|
titleRatio = data.subtitle ? conf.titleRatio : 1;
|
|
this.title = paper.text(m[3] - 5, m[0] + h / 2, data.title)
|
|
.attr({"text-anchor": "end", "font-weight": "bold", "font-size": h * titleRatio * 0.9});
|
|
}
|
|
|
|
//subtitle
|
|
if (data.subtitle) {
|
|
this.subtitle = paper.text(m[3] - 5, conf.height - m[2], data.subtitle)
|
|
.attr({"text-anchor": "end", "font-size": h * (1 - conf.titleRatio) * 0.9});
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* paint orient vertical bullet
|
|
*/
|
|
Bullet.prototype.paintVertical = function () {
|
|
var conf = this.defaults;
|
|
var paper = this.canvas,
|
|
data = this.data,
|
|
m = conf.margin,
|
|
ranges = [],
|
|
measures = [],
|
|
markers = [],
|
|
rangeTitles = [],
|
|
i,
|
|
l,
|
|
rect,
|
|
titleRatio,
|
|
w = conf.width - m[1] - m[3],
|
|
h,
|
|
bottom;
|
|
|
|
//axis
|
|
this.axis(paper).attr({transform: "t" + m[3] + ',' + 0});
|
|
|
|
//color rect
|
|
ranges = data.ranges;
|
|
if (data.rangeTitles) {
|
|
rangeTitles = data.rangeTitles;
|
|
}
|
|
bottom = conf.height - m[2];
|
|
for (i = 0, l = ranges.length - 1; i < l; i++) {
|
|
h = -this.scale(ranges[i + 1]) + this.scale(ranges[i]);
|
|
rect = paper.rect(m[3], bottom - h, w, h)
|
|
.attr({"stroke": "none",
|
|
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
|
|
"title": rangeTitles[i] ? rangeTitles[i] : ""});
|
|
bottom -= h;
|
|
}
|
|
|
|
//measure bar
|
|
data.measures.forEach(function (d, i) {
|
|
var mTitles = data.measureTitles;
|
|
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
|
|
measures.push({measure: d, measureTitle: mTitle});
|
|
});
|
|
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
|
|
bottom = this.scale(data.min);
|
|
for (i = 0, l = measures.length; i < l; i++) {
|
|
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
|
|
h = -this.scale(value) + bottom;
|
|
paper.rect(m[3] + w * (1 - conf.centerBarRatio) / 2,
|
|
bottom - h,
|
|
w * conf.centerBarRatio,
|
|
h)
|
|
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
|
|
bottom -= h;
|
|
}
|
|
|
|
//marker bar
|
|
markers = data.markers;
|
|
for (i = 0, l = markers.length; i < l; i++) {
|
|
paper.rect(m[3] + w * (1 - conf.markerRatio) / 2,
|
|
this.scale(markers[i]) - conf.markerWidth / 2,
|
|
w * conf.markerRatio,
|
|
conf.markerWidth)
|
|
.attr({"stroke": "none", "fill": conf.markerColor,
|
|
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
|
|
}
|
|
|
|
//title
|
|
if (data.title) {
|
|
titleRatio = data.subtitle ? conf.titleRatio : 1;
|
|
m[0] *= 0.9; //some ratio adjust;
|
|
this.title = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * titleRatio / 2, data.title)
|
|
.attr({"text-anchor": "middle", "font-weight": "bold", "font-size": m[0] * titleRatio * 0.8});
|
|
}
|
|
|
|
//subtitle
|
|
if (data.subtitle) {
|
|
this.subtitle = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * (1 - (1 - titleRatio) / 2), data.subtitle)
|
|
.attr({"text-anchor": "middle", "font-size": m[0] * (1 - titleRatio) * 0.8});
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* clean canvas
|
|
*/
|
|
Bullet.prototype.clearCanvas = function () {
|
|
this.canvas.clear();
|
|
};
|
|
|
|
/**
|
|
* render bullet
|
|
*/
|
|
Bullet.prototype.render = function (options) {
|
|
this.setOptions(options);
|
|
this.generatePaths();
|
|
};
|
|
|
|
return Bullet;
|
|
});
|
|
|