Created
December 30, 2013 10:35
-
-
Save e7h4n/8180426 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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