Skip to content

Instantly share code, notes, and snippets.

@e7h4n
Created December 30, 2013 10:35
Show Gist options
  • Select an option

  • Save e7h4n/8180426 to your computer and use it in GitHub Desktop.

Select an option

Save e7h4n/8180426 to your computer and use it in GitHub Desktop.
/**
* TrendChart.js, May 31, 2013
*
* Copyright 2013 fenbi.com. All rights reserved.
* FENBI.COM PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/**
* @author zhangyc <zhangyc@fenbi.com>
*/
'use strict';
var raphael = require('../../common/lib/raphael');
var _ = require('../../common/lib/underscore');
var DateUtil = require('../../common/util/DateUtil');
var Raphael = require('../../common/lib/raphael');
/*jshint maxparams: 6*/
var TrendChart = {
init: function () {
Raphael.fn.drawGrid = function (x, y, w, h, wv, hvs) {
var path = ['M', Math.round(x) + 0.5, Math.round(y) + 0.5, 'L', Math.round(x + w) + 0.5, Math.round(y) + 0.5, Math.round(x + w) + 0.5, Math.round(y + h) + 0.5, Math.round(x) + 0.5, Math.round(y + h) + 0.5, Math.round(x) + 0.5, Math.round(y) + 0.5];
var columnWidth = w / wv;
hvs.forEach(function (hv) {
var rowHeight = hv * h;
path = path.concat(['M', Math.round(x) + 0.5, Math.round(y + rowHeight) + 0.5, 'H', Math.round(x + w) + 0.5]);
});
for (var i = 1; i < wv; i++) {
path = path.concat(['M', Math.round(x + i * columnWidth) + 0.5, Math.round(y) + 0.5, 'V', Math.round(y + h) + 0.5]);
}
return this.path(path.join(',')).attr({
stroke: '#D7D7D7',
'stroke-dasharray': '-'
}).toBack();
};
},
draw: function ($el, options) {
options = _.extend({
gutter: [15, 15, 15, 45]
}, options);
TrendChart.init();
var trendPoints = $el.data('trendPoints');
var fullMark = Math.max.apply(Math, [$el.data('fullMark')].concat(trendPoints.map(function (point) {
return point.score;
})));
// { draw chart & label
var paper = raphael($el.get(0));
var gutter = options.gutter;
var chartWidth = paper.width - gutter[3] - gutter[1];
var chartHeight = paper.height - gutter[0] - gutter[2];
var yGridGap = (function () {
if (fullMark < 60) {
return 10;
} else if (fullMark < 120) {
return 20;
}
return 30;
}());
var yGridStop = Math.round(fullMark / yGridGap);
var yLabels = _.range(yGridStop + 1).map(function (i) {
return yGridGap * (yGridStop - i);
});
yLabels[0] = fullMark;
setTimeout(function () {
paper.drawGrid(gutter[3], gutter[0], chartWidth, chartHeight, Math.min(4, trendPoints.length), yLabels.map(function (label) {
return 1 - label / fullMark;
}));
}, 25);
var scores = trendPoints.map(function (x) {
return x.score;
});
setTimeout(function () {
yLabels.forEach(function (label) {
var y = gutter[0] + chartHeight * (fullMark - label) / fullMark;
paper.text(gutter[3] - 18, y, label).attr({
fill: '#3A8FFB',
'font-size': 14,
'font-family': 'Arial, Helvetica, sans-serif',
'text-anchor': 'end'
});
});
}, 50);
// }
if (trendPoints.length === 0) {
return;
}
// get points {
var xStep = scores.length > 1 ? chartWidth / (scores.length - 1) : 0;
var points = trendPoints.map(function (dataItem, idx) {
var x = Math.round(gutter[3] + xStep * idx);
var y = Math.round(gutter[0] + (1 - dataItem.score / fullMark) * chartHeight);
return {
x: x,
y: y
};
});
// }
// draw line {
var path = null;
points.forEach(function (point, idx) {
if (idx === 0) {
path = ['M', point.x, point.y, 'L'];
} else if (idx < trendPoints.length - 1) {
path = path.concat(['L', point.x, point.y]);
} else {
path = path.concat([point.x, point.y]);
}
});
if (points.length === 1) {
paper.circle(points[0].x, points[0].y, 6).attr({
fill: '#52D075',
'stroke-width': 0
}).glow({
width: 4,
color: '#050000',
opacity: 0.3,
offsety: 2
});
} else {
paper.path().attr({
path: path,
stroke: '#52D075',
'stroke-width': 6
}).glow({
width: 4,
color: '#050000',
opacity: 0.3,
offsety: 2
});
}
// }
// draw event rect
var currentIndex = null;
var $popup = $el.find('.popup');
var wrapOffset = $popup.parent().offset();
$popup.detach().show();
var $eventLayer = $el.find('.event-layer');
var eventOffset = $eventLayer.offset();
var hideTimer = null;
$eventLayer.css({
height: $eventLayer.height(),
width: $eventLayer.width(),
position: 'absolute',
'z-index': 3
}).appendTo(document.body);
$eventLayer.offset(eventOffset);
$eventLayer.on('mousemove', _.debounce(function (evt) {
clearTimeout(hideTimer);
var mouseX = evt.offsetX;
var idx = null;
if (points.length > 1) {
points.forEach(function (point, currIdx) {
if (mouseX > point.x - xStep / 2 && mouseX <= point.x + xStep / 2) {
idx = currIdx;
}
});
} else {
idx = 0;
}
if (idx === null) {
return;
}
if (currentIndex === idx) {
return;
}
currentIndex = idx;
var point = points[idx];
$popup.appendTo(document.body);
$popup.find('.score').text(Math.round(trendPoints[idx].score));
$popup.find('.time').text(DateUtil.formatTimestamp(trendPoints[idx].time || Date.now(), {
isWithTime: true
}));
$popup.css({
left: wrapOffset.left + point.x,
top: wrapOffset.top + point.y
});
}, 10)).on('mouseleave', _.debounce(function () {
clearTimeout(hideTimer);
hideTimer = setTimeout(function () {
$popup.detach();
currentIndex = null;
}, 50);
}, 50));
// }
}
};
TrendChart.init = _.once(TrendChart.init);
TrendChart.initPopup = _.once(TrendChart.initPopup);
module.exports = TrendChart;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment