로그인 기본 틀 완성
This commit is contained in:
parent
60103953ba
commit
57bec7eb1a
1
app/assets/javascripts/js/datepicker/daterangepicker.js
Executable file
1
app/assets/javascripts/js/datepicker/daterangepicker.js
Executable file
File diff suppressed because one or more lines are too long
483
app/assets/javascripts/js/flot/curvedLines.js
Executable file
483
app/assets/javascripts/js/flot/curvedLines.js
Executable file
@ -0,0 +1,483 @@
|
||||
/* The MIT License
|
||||
|
||||
Copyright (c) 2011 by Michael Zinsmaier and nergal.dev
|
||||
Copyright (c) 2012 by Thomas Ritou
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
____________________________________________________
|
||||
|
||||
what it is:
|
||||
____________________________________________________
|
||||
|
||||
curvedLines is a plugin for flot, that tries to display lines in a smoother way.
|
||||
This is achieved through adding of more data points. The plugin is a data processor and can thus be used
|
||||
in combination with standard line / point rendering options.
|
||||
|
||||
=> 1) with large data sets you may get trouble
|
||||
=> 2) if you want to display the points too, you have to plot them as 2nd data series over the lines
|
||||
=> 3) consecutive x data points are not allowed to have the same value
|
||||
|
||||
Feel free to further improve the code
|
||||
|
||||
____________________________________________________
|
||||
|
||||
how to use it:
|
||||
____________________________________________________
|
||||
|
||||
var d1 = [[5,5],[7,3],[9,12]];
|
||||
|
||||
var options = { series: { curvedLines: { active: true }}};
|
||||
|
||||
$.plot($("#placeholder"), [{data: d1, lines: { show: true}, curvedLines: {apply: true}}], options);
|
||||
|
||||
_____________________________________________________
|
||||
|
||||
options:
|
||||
_____________________________________________________
|
||||
|
||||
active: bool true => plugin can be used
|
||||
apply: bool true => series will be drawn as curved line
|
||||
monotonicFit: bool true => uses monotone cubic interpolation (preserve monotonicity)
|
||||
tension: int defines the tension parameter of the hermite spline interpolation (no effect if monotonicFit is set)
|
||||
nrSplinePoints: int defines the number of sample points (of the spline) in between two consecutive points
|
||||
|
||||
deprecated options from flot prior to 1.0.0:
|
||||
------------------------------------------------
|
||||
legacyOverride bool true => use old default
|
||||
OR
|
||||
legacyOverride optionArray
|
||||
{
|
||||
fit: bool true => forces the max,mins of the curve to be on the datapoints
|
||||
curvePointFactor int defines how many "virtual" points are used per "real" data point to
|
||||
emulate the curvedLines (points total = real points * curvePointFactor)
|
||||
fitPointDist: int defines the x axis distance of the additional two points that are used
|
||||
} to enforce the min max condition.
|
||||
*/
|
||||
|
||||
/*
|
||||
* v0.1 initial commit
|
||||
* v0.15 negative values should work now (outcommented a negative -> 0 hook hope it does no harm)
|
||||
* v0.2 added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi)
|
||||
* v0.3 improved saddle handling and added basic handling of Dates
|
||||
* v0.4 rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug
|
||||
* v0.5 rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou).
|
||||
* This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill,
|
||||
* shadow) are now supported out of the box
|
||||
* v0.6 flot 0.8 compatibility and some bug fixes
|
||||
* v0.6.x changed versioning schema
|
||||
*
|
||||
* v1.0.0 API Break marked existing implementation/options as deprecated
|
||||
* v1.1.0 added the new curved line calculations based on hermite splines
|
||||
* v1.1.1 added a rough parameter check to make sure the new options are used
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var options = {
|
||||
series : {
|
||||
curvedLines : {
|
||||
active : false,
|
||||
apply : false,
|
||||
monotonicFit : false,
|
||||
tension : 0.5,
|
||||
nrSplinePoints : 20,
|
||||
legacyOverride : undefined
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
|
||||
plot.hooks.processOptions.push(processOptions);
|
||||
|
||||
//if the plugin is active register processDatapoints method
|
||||
function processOptions(plot, options) {
|
||||
if (options.series.curvedLines.active) {
|
||||
plot.hooks.processDatapoints.unshift(processDatapoints);
|
||||
}
|
||||
}
|
||||
|
||||
//only if the plugin is active
|
||||
function processDatapoints(plot, series, datapoints) {
|
||||
var nrPoints = datapoints.points.length / datapoints.pointsize;
|
||||
var EPSILON = 0.005;
|
||||
|
||||
//detects missplaced legacy parameters (prior v1.x.x) in the options object
|
||||
//this can happen if somebody upgrades to v1.x.x without adjusting the parameters or uses old examples
|
||||
var invalidLegacyOptions = hasInvalidParameters(series.curvedLines);
|
||||
|
||||
if (!invalidLegacyOptions && series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) {
|
||||
if (series.lines.fill) {
|
||||
|
||||
var pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1);
|
||||
var pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2);
|
||||
//flot makes sure for us that we've got a second y point if fill is true !
|
||||
|
||||
//Merge top and bottom curve
|
||||
datapoints.pointsize = 3;
|
||||
datapoints.points = [];
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var i = 0;
|
||||
var ps = 2;
|
||||
while (i < pointsTop.length || j < pointsBottom.length) {
|
||||
if (pointsTop[i] == pointsBottom[j]) {
|
||||
datapoints.points[k] = pointsTop[i];
|
||||
datapoints.points[k + 1] = pointsTop[i + 1];
|
||||
datapoints.points[k + 2] = pointsBottom[j + 1];
|
||||
j += ps;
|
||||
i += ps;
|
||||
|
||||
} else if (pointsTop[i] < pointsBottom[j]) {
|
||||
datapoints.points[k] = pointsTop[i];
|
||||
datapoints.points[k + 1] = pointsTop[i + 1];
|
||||
datapoints.points[k + 2] = k > 0 ? datapoints.points[k - 1] : null;
|
||||
i += ps;
|
||||
} else {
|
||||
datapoints.points[k] = pointsBottom[j];
|
||||
datapoints.points[k + 1] = k > 1 ? datapoints.points[k - 2] : null;
|
||||
datapoints.points[k + 2] = pointsBottom[j + 1];
|
||||
j += ps;
|
||||
}
|
||||
k += 3;
|
||||
}
|
||||
} else if (series.lines.lineWidth > 0) {
|
||||
datapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1);
|
||||
datapoints.pointsize = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) {
|
||||
if ( typeof curvedLinesOptions.legacyOverride != 'undefined' && curvedLinesOptions.legacyOverride != false) {
|
||||
var defaultOptions = {
|
||||
fit : false,
|
||||
curvePointFactor : 20,
|
||||
fitPointDist : undefined
|
||||
};
|
||||
var legacyOptions = jQuery.extend(defaultOptions, curvedLinesOptions.legacyOverride);
|
||||
return calculateLegacyCurvePoints(datapoints, legacyOptions, yPos);
|
||||
}
|
||||
|
||||
return calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos);
|
||||
}
|
||||
|
||||
function calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos) {
|
||||
var points = datapoints.points;
|
||||
var ps = datapoints.pointsize;
|
||||
|
||||
//create interpolant fuction
|
||||
var splines = createHermiteSplines(datapoints, curvedLinesOptions, yPos);
|
||||
var result = [];
|
||||
|
||||
//sample the function
|
||||
// (the result is intependent from the input data =>
|
||||
// it is ok to alter the input after this method)
|
||||
var j = 0;
|
||||
for (var i = 0; i < points.length - ps; i += ps) {
|
||||
var curX = i;
|
||||
var curY = i + yPos;
|
||||
|
||||
var xStart = points[curX];
|
||||
var xEnd = points[curX + ps];
|
||||
var xStep = (xEnd - xStart) / Number(curvedLinesOptions.nrSplinePoints);
|
||||
|
||||
//add point
|
||||
result.push(points[curX]);
|
||||
result.push(points[curY]);
|
||||
|
||||
//add curve point
|
||||
for (var x = (xStart += xStep); x < xEnd; x += xStep) {
|
||||
result.push(x);
|
||||
result.push(splines[j](x));
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
//add last point
|
||||
result.push(points[points.length - ps]);
|
||||
result.push(points[points.length - ps + yPos]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Creates an array of splines, one for each segment of the original curve. Algorithm based on the wikipedia articles:
|
||||
//
|
||||
// http://de.wikipedia.org/w/index.php?title=Kubisch_Hermitescher_Spline&oldid=130168003 and
|
||||
// http://en.wikipedia.org/w/index.php?title=Monotone_cubic_interpolation&oldid=622341725 and the description of Fritsch-Carlson from
|
||||
// http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation
|
||||
// for a detailed description see https://github.com/MichaelZinsmaier/CurvedLines/docu
|
||||
function createHermiteSplines(datapoints, curvedLinesOptions, yPos) {
|
||||
var points = datapoints.points;
|
||||
var ps = datapoints.pointsize;
|
||||
|
||||
// preparation get length (x_{k+1} - x_k) and slope s=(p_{k+1} - p_k) / (x_{k+1} - x_k) of the segments
|
||||
var segmentLengths = [];
|
||||
var segmentSlopes = [];
|
||||
|
||||
for (var i = 0; i < points.length - ps; i += ps) {
|
||||
var curX = i;
|
||||
var curY = i + yPos;
|
||||
var dx = points[curX + ps] - points[curX];
|
||||
var dy = points[curY + ps] - points[curY];
|
||||
|
||||
segmentLengths.push(dx);
|
||||
segmentSlopes.push(dy / dx);
|
||||
}
|
||||
|
||||
//get the values for the desired gradients m_k for all points k
|
||||
//depending on the used method the formula is different
|
||||
var gradients = [segmentSlopes[0]];
|
||||
if (curvedLinesOptions.monotonicFit) {
|
||||
// Fritsch Carlson
|
||||
for (var i = 1; i < segmentLengths.length; i++) {
|
||||
var slope = segmentSlopes[i];
|
||||
var prev_slope = segmentSlopes[i - 1];
|
||||
if (slope * prev_slope <= 0) { // sign(prev_slope) != sign(slpe)
|
||||
gradients.push(0);
|
||||
} else {
|
||||
var length = segmentLengths[i];
|
||||
var prev_length = segmentLengths[i - 1];
|
||||
var common = length + prev_length;
|
||||
//m = 3 (prev_length + length) / ((2 length + prev_length) / prev_slope + (length + 2 prev_length) / slope)
|
||||
gradients.push(3 * common / ((common + length) / prev_slope + (common + prev_length) / slope));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Cardinal spline with t € [0,1]
|
||||
// Catmull-Rom for t = 0
|
||||
for (var i = ps; i < points.length - ps; i += ps) {
|
||||
var curX = i;
|
||||
var curY = i + yPos;
|
||||
gradients.push(Number(curvedLinesOptions.tension) * (points[curY + ps] - points[curY - ps]) / (points[curX + ps] - points[curX - ps]));
|
||||
}
|
||||
}
|
||||
gradients.push(segmentSlopes[segmentSlopes.length - 1]);
|
||||
|
||||
//get the two major coefficients (c'_{oef1} and c'_{oef2}) for each segment spline
|
||||
var coefs1 = [];
|
||||
var coefs2 = [];
|
||||
for (i = 0; i < segmentLengths.length; i++) {
|
||||
var m_k = gradients[i];
|
||||
var m_k_plus = gradients[i + 1];
|
||||
var slope = segmentSlopes[i];
|
||||
var invLength = 1 / segmentLengths[i];
|
||||
var common = m_k + m_k_plus - slope - slope;
|
||||
|
||||
coefs1.push(common * invLength * invLength);
|
||||
coefs2.push((slope - common - m_k) * invLength);
|
||||
}
|
||||
|
||||
//create functions with from the coefficients and capture the parameters
|
||||
var ret = [];
|
||||
for (var i = 0; i < segmentLengths.length; i ++) {
|
||||
var spline = function (x_k, coef1, coef2, coef3, coef4) {
|
||||
// spline for a segment
|
||||
return function (x) {
|
||||
var diff = x - x_k;
|
||||
var diffSq = diff * diff;
|
||||
return coef1 * diff * diffSq + coef2 * diffSq + coef3 * diff + coef4;
|
||||
};
|
||||
};
|
||||
|
||||
ret.push(spline(points[i * ps], coefs1[i], coefs2[i], gradients[i], points[i * ps + yPos]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
//no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226
|
||||
//if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code.
|
||||
function calculateLegacyCurvePoints(datapoints, curvedLinesOptions, yPos) {
|
||||
|
||||
var points = datapoints.points;
|
||||
var ps = datapoints.pointsize;
|
||||
var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / ps);
|
||||
|
||||
var xdata = new Array;
|
||||
var ydata = new Array;
|
||||
|
||||
var curX = -1;
|
||||
var curY = -1;
|
||||
var j = 0;
|
||||
|
||||
if (curvedLinesOptions.fit) {
|
||||
//insert a point before and after the "real" data point to force the line
|
||||
//to have a max,min at the data point.
|
||||
|
||||
var fpDist;
|
||||
if ( typeof curvedLinesOptions.fitPointDist == 'undefined') {
|
||||
//estimate it
|
||||
var minX = points[0];
|
||||
var maxX = points[points.length - ps];
|
||||
fpDist = (maxX - minX) / (500 * 100);
|
||||
//x range / (estimated pixel length of placeholder * factor)
|
||||
} else {
|
||||
//use user defined value
|
||||
fpDist = Number(curvedLinesOptions.fitPointDist);
|
||||
}
|
||||
|
||||
for (var i = 0; i < points.length; i += ps) {
|
||||
|
||||
var frontX;
|
||||
var backX;
|
||||
curX = i;
|
||||
curY = i + yPos;
|
||||
|
||||
//add point X s
|
||||
frontX = points[curX] - fpDist;
|
||||
backX = points[curX] + fpDist;
|
||||
|
||||
var factor = 2;
|
||||
while (frontX == points[curX] || backX == points[curX]) {
|
||||
//inside the ulp
|
||||
frontX = points[curX] - (fpDist * factor);
|
||||
backX = points[curX] + (fpDist * factor);
|
||||
factor++;
|
||||
}
|
||||
|
||||
//add curve points
|
||||
xdata[j] = frontX;
|
||||
ydata[j] = points[curY];
|
||||
j++;
|
||||
|
||||
xdata[j] = points[curX];
|
||||
ydata[j] = points[curY];
|
||||
j++;
|
||||
|
||||
xdata[j] = backX;
|
||||
ydata[j] = points[curY];
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
//just use the datapoints
|
||||
for (var i = 0; i < points.length; i += ps) {
|
||||
curX = i;
|
||||
curY = i + yPos;
|
||||
|
||||
xdata[j] = points[curX];
|
||||
ydata[j] = points[curY];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
var n = xdata.length;
|
||||
|
||||
var y2 = new Array();
|
||||
var delta = new Array();
|
||||
y2[0] = 0;
|
||||
y2[n - 1] = 0;
|
||||
delta[0] = 0;
|
||||
|
||||
for (var i = 1; i < n - 1; ++i) {
|
||||
var d = (xdata[i + 1] - xdata[i - 1]);
|
||||
if (d == 0) {
|
||||
//point before current point and after current point need some space in between
|
||||
return [];
|
||||
}
|
||||
|
||||
var s = (xdata[i] - xdata[i - 1]) / d;
|
||||
var p = s * y2[i - 1] + 2;
|
||||
y2[i] = (s - 1) / p;
|
||||
delta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]);
|
||||
delta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p;
|
||||
}
|
||||
|
||||
for (var j = n - 2; j >= 0; --j) {
|
||||
y2[j] = y2[j] * y2[j + 1] + delta[j];
|
||||
}
|
||||
|
||||
// xmax - xmin / #points
|
||||
var step = (xdata[n - 1] - xdata[0]) / (num - 1);
|
||||
|
||||
var xnew = new Array;
|
||||
var ynew = new Array;
|
||||
var result = new Array;
|
||||
|
||||
xnew[0] = xdata[0];
|
||||
ynew[0] = ydata[0];
|
||||
|
||||
result.push(xnew[0]);
|
||||
result.push(ynew[0]);
|
||||
|
||||
for ( j = 1; j < num; ++j) {
|
||||
//new x point (sampling point for the created curve)
|
||||
xnew[j] = xnew[0] + j * step;
|
||||
|
||||
var max = n - 1;
|
||||
var min = 0;
|
||||
|
||||
while (max - min > 1) {
|
||||
var k = Math.round((max + min) / 2);
|
||||
if (xdata[k] > xnew[j]) {
|
||||
max = k;
|
||||
} else {
|
||||
min = k;
|
||||
}
|
||||
}
|
||||
|
||||
//found point one to the left and one to the right of generated new point
|
||||
var h = (xdata[max] - xdata[min]);
|
||||
|
||||
if (h == 0) {
|
||||
//similar to above two points from original x data need some space between them
|
||||
return [];
|
||||
}
|
||||
|
||||
var a = (xdata[max] - xnew[j]) / h;
|
||||
var b = (xnew[j] - xdata[min]) / h;
|
||||
|
||||
ynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6;
|
||||
|
||||
result.push(xnew[j]);
|
||||
result.push(ynew[j]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function hasInvalidParameters(curvedLinesOptions) {
|
||||
if (typeof curvedLinesOptions.fit != 'undefined' ||
|
||||
typeof curvedLinesOptions.curvePointFactor != 'undefined' ||
|
||||
typeof curvedLinesOptions.fitPointDist != 'undefined') {
|
||||
throw new Error("CurvedLines detected illegal parameters. The CurvedLines API changed with version 1.0.0 please check the options object.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}//end init
|
||||
|
||||
|
||||
$.plot.plugins.push({
|
||||
init : init,
|
||||
options : options,
|
||||
name : 'curvedLines',
|
||||
version : '1.1.1'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
104
app/assets/javascripts/js/flot/date.js
Executable file
104
app/assets/javascripts/js/flot/date.js
Executable file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Version: 1.0 Alpha-1
|
||||
* Build Date: 13-Nov-2007
|
||||
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
|
||||
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
|
||||
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
|
||||
*/
|
||||
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
|
||||
Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
|
||||
return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
|
||||
return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
|
||||
return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
|
||||
if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
|
||||
var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
|
||||
if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
|
||||
if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
|
||||
if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
|
||||
if(x.month||x.months){this.addMonths(x.month||x.months);}
|
||||
if(x.year||x.years){this.addYears(x.year||x.years);}
|
||||
if(x.day||x.days){this.addDays(x.day||x.days);}
|
||||
return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
|
||||
return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
|
||||
if(!x.second&&x.second!==0){x.second=-1;}
|
||||
if(!x.minute&&x.minute!==0){x.minute=-1;}
|
||||
if(!x.hour&&x.hour!==0){x.hour=-1;}
|
||||
if(!x.day&&x.day!==0){x.day=-1;}
|
||||
if(!x.month&&x.month!==0){x.month=-1;}
|
||||
if(!x.year&&x.year!==0){x.year=-1;}
|
||||
if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
|
||||
if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
|
||||
if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
|
||||
if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
|
||||
if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
|
||||
if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
|
||||
if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
|
||||
if(x.timezone){this.setTimezone(x.timezone);}
|
||||
if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
|
||||
return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
|
||||
var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
|
||||
return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
|
||||
Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
|
||||
return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
|
||||
var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
|
||||
return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
|
||||
var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
|
||||
return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
|
||||
(function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
|
||||
break;}
|
||||
return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
|
||||
rx.push(r[0]);s=r[1];}
|
||||
return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
|
||||
return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
|
||||
throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
|
||||
return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
|
||||
if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
|
||||
try{r=(px[i].call(this,s));}catch(e){r=null;}
|
||||
if(r){return r;}}
|
||||
throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
|
||||
try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
|
||||
rx.push(r[0]);s=r[1];}
|
||||
return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
|
||||
return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
|
||||
rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
|
||||
s=q[1];}
|
||||
if(!r){throw new $P.Exception(s);}
|
||||
if(q){throw new $P.Exception(q[1]);}
|
||||
if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
|
||||
return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
|
||||
rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
|
||||
if(!last&&q[1].length===0){last=true;}
|
||||
if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
|
||||
p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
|
||||
if(rx[1].length<best[1].length){best=rx;}
|
||||
if(best[1].length===0){break;}}
|
||||
if(best[0].length===0){return best;}
|
||||
if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
|
||||
best[1]=q[1];}
|
||||
return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
|
||||
return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
|
||||
if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
|
||||
var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
|
||||
return rx;};Date.Grammar={};Date.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=((s.length==3)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
|
||||
this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
|
||||
var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
|
||||
return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
|
||||
for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
|
||||
if(this.now){return new Date();}
|
||||
var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
|
||||
if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
|
||||
if(!this.unit){this.unit="day";}
|
||||
if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
|
||||
if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
|
||||
this[this.unit+"s"]=this.value*orient;}
|
||||
return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
|
||||
if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
|
||||
if(this.month&&!this.day){this.day=1;}
|
||||
return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
|
||||
fn=_C[keys]=_.any.apply(null,px);}
|
||||
return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.mm,g.ss],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
|
||||
return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
|
||||
return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
|
||||
try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
|
||||
return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
|
||||
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
|
2
app/assets/javascripts/js/flot/jquery.flot.js
Executable file
2
app/assets/javascripts/js/flot/jquery.flot.js
Executable file
File diff suppressed because one or more lines are too long
201
app/assets/javascripts/js/flot/jquery.flot.orderBars.js
Executable file
201
app/assets/javascripts/js/flot/jquery.flot.orderBars.js
Executable file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Flot plugin to order bars side by side.
|
||||
*
|
||||
* Released under the MIT license by Benjamin BUFFET, 20-Sep-2010.
|
||||
* Modifications made by Steven Hall <github.com/emmerich>, 01-May-2013.
|
||||
*
|
||||
* This plugin is an alpha version.
|
||||
*
|
||||
* To activate the plugin you must specify the parameter "order" for the specific serie :
|
||||
*
|
||||
* $.plot($("#placeholder"), [{ data: [ ... ], bars :{ order = null or integer }])
|
||||
*
|
||||
* If 2 series have the same order param, they are ordered by the position in the array;
|
||||
*
|
||||
* The plugin adjust the point by adding a value depanding of the barwidth
|
||||
* Exemple for 3 series (barwidth : 0.1) :
|
||||
*
|
||||
* first bar décalage : -0.15
|
||||
* second bar décalage : -0.05
|
||||
* third bar décalage : 0.05
|
||||
*
|
||||
*/
|
||||
|
||||
// INFO: decalage/decallage is French for gap. It's used to denote the spacing applied to each
|
||||
// bar.
|
||||
(function($){
|
||||
function init(plot){
|
||||
var orderedBarSeries;
|
||||
var nbOfBarsToOrder;
|
||||
var borderWidth;
|
||||
var borderWidthInXabsWidth;
|
||||
var pixelInXWidthEquivalent = 1;
|
||||
var isHorizontal = false;
|
||||
|
||||
// A mapping of order integers to decallage.
|
||||
var decallageByOrder = {};
|
||||
|
||||
/*
|
||||
* This method add shift to x values
|
||||
*/
|
||||
function reOrderBars(plot, serie, datapoints){
|
||||
var shiftedPoints = null;
|
||||
|
||||
if(serieNeedToBeReordered(serie)){
|
||||
checkIfGraphIsHorizontal(serie);
|
||||
calculPixel2XWidthConvert(plot);
|
||||
retrieveBarSeries(plot);
|
||||
calculBorderAndBarWidth(serie);
|
||||
|
||||
if(nbOfBarsToOrder >= 2){
|
||||
var position = findPosition(serie);
|
||||
var decallage = 0;
|
||||
|
||||
var centerBarShift = calculCenterBarShift();
|
||||
|
||||
// If we haven't already calculated the decallage for this order value, do it.
|
||||
if(typeof decallageByOrder[serie.bars.order] === 'undefined') {
|
||||
if (isBarAtLeftOfCenter(position)){
|
||||
decallageByOrder[serie.bars.order] = -1*(sumWidth(orderedBarSeries,position-1,Math.floor(nbOfBarsToOrder / 2)-1)) - centerBarShift;
|
||||
}else{
|
||||
decallageByOrder[serie.bars.order] = sumWidth(orderedBarSeries,Math.ceil(nbOfBarsToOrder / 2),position-2) + centerBarShift + borderWidthInXabsWidth*2;
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup the decallage based on the series' order value.
|
||||
decallage = decallageByOrder[serie.bars.order];
|
||||
|
||||
shiftedPoints = shiftPoints(datapoints,serie,decallage);
|
||||
datapoints.points = shiftedPoints;
|
||||
}
|
||||
}
|
||||
return shiftedPoints;
|
||||
}
|
||||
|
||||
function serieNeedToBeReordered(serie){
|
||||
return serie.bars != null
|
||||
&& serie.bars.show
|
||||
&& serie.bars.order != null;
|
||||
}
|
||||
|
||||
function calculPixel2XWidthConvert(plot){
|
||||
var gridDimSize = isHorizontal ? plot.getPlaceholder().innerHeight() : plot.getPlaceholder().innerWidth();
|
||||
var minMaxValues = isHorizontal ? getAxeMinMaxValues(plot.getData(),1) : getAxeMinMaxValues(plot.getData(),0);
|
||||
var AxeSize = minMaxValues[1] - minMaxValues[0];
|
||||
pixelInXWidthEquivalent = AxeSize / gridDimSize;
|
||||
}
|
||||
|
||||
function getAxeMinMaxValues(series,AxeIdx){
|
||||
var minMaxValues = new Array();
|
||||
for(var i = 0; i < series.length; i++){
|
||||
minMaxValues[0] = (series[i].data[0]) ? series[i].data[0][AxeIdx]: null;
|
||||
minMaxValues[1] = (series[i].data[series[i].data.length - 1]) ? series[i].data[series[i].data.length - 1][AxeIdx]: null;
|
||||
}
|
||||
return minMaxValues;
|
||||
}
|
||||
|
||||
function retrieveBarSeries(plot){
|
||||
orderedBarSeries = findOthersBarsToReOrders(plot.getData());
|
||||
nbOfBarsToOrder = orderedBarSeries.length;
|
||||
}
|
||||
|
||||
function findOthersBarsToReOrders(series){
|
||||
var retSeries = new Array();
|
||||
var orderValuesSeen = [];
|
||||
|
||||
for(var i = 0; i < series.length; i++){
|
||||
if(series[i].bars.order != null && series[i].bars.show &&
|
||||
orderValuesSeen.indexOf(series[i].bars.order) < 0){
|
||||
|
||||
orderValuesSeen.push(series[i].bars.order);
|
||||
retSeries.push(series[i]);
|
||||
}
|
||||
}
|
||||
return retSeries.sort(sortByOrder);
|
||||
}
|
||||
|
||||
function sortByOrder(serie1,serie2){
|
||||
var x = serie1.bars.order;
|
||||
var y = serie2.bars.order;
|
||||
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
|
||||
}
|
||||
|
||||
function calculBorderAndBarWidth(serie){
|
||||
borderWidth = typeof serie.bars.lineWidth !== 'undefined' ? serie.bars.lineWidth : 2;
|
||||
borderWidthInXabsWidth = borderWidth * pixelInXWidthEquivalent;
|
||||
}
|
||||
|
||||
function checkIfGraphIsHorizontal(serie){
|
||||
if(serie.bars.horizontal){
|
||||
isHorizontal = true;
|
||||
}
|
||||
}
|
||||
|
||||
function findPosition(serie){
|
||||
var pos = 0
|
||||
for (var i = 0; i < orderedBarSeries.length; ++i) {
|
||||
if (serie == orderedBarSeries[i]){
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
function calculCenterBarShift(){
|
||||
var width = 0;
|
||||
|
||||
if(nbOfBarsToOrder%2 != 0)
|
||||
width = (orderedBarSeries[Math.ceil(nbOfBarsToOrder / 2)].bars.barWidth)/2;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
function isBarAtLeftOfCenter(position){
|
||||
return position <= Math.ceil(nbOfBarsToOrder / 2);
|
||||
}
|
||||
|
||||
function sumWidth(series,start,end){
|
||||
var totalWidth = 0;
|
||||
|
||||
for(var i = start; i <= end; i++){
|
||||
totalWidth += series[i].bars.barWidth+borderWidthInXabsWidth*2;
|
||||
}
|
||||
|
||||
return totalWidth;
|
||||
}
|
||||
|
||||
function shiftPoints(datapoints,serie,dx){
|
||||
var ps = datapoints.pointsize;
|
||||
var points = datapoints.points;
|
||||
var j = 0;
|
||||
for(var i = isHorizontal ? 1 : 0;i < points.length; i += ps){
|
||||
points[i] += dx;
|
||||
//Adding the new x value in the serie to be abble to display the right tooltip value,
|
||||
//using the index 3 to not overide the third index.
|
||||
serie.data[j][3] = points[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
plot.hooks.processDatapoints.push(reOrderBars);
|
||||
|
||||
}
|
||||
|
||||
var options = {
|
||||
series : {
|
||||
bars: {order: null} // or number/string
|
||||
}
|
||||
};
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: "orderBars",
|
||||
version: "0.2"
|
||||
});
|
||||
|
||||
})(jQuery);
|
820
app/assets/javascripts/js/flot/jquery.flot.pie.js
Executable file
820
app/assets/javascripts/js/flot/jquery.flot.pie.js
Executable file
@ -0,0 +1,820 @@
|
||||
/* Flot plugin for rendering pie charts.
|
||||
|
||||
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||
Licensed under the MIT license.
|
||||
|
||||
The plugin assumes that each series has a single data value, and that each
|
||||
value is a positive integer or zero. Negative numbers don't make sense for a
|
||||
pie chart, and have unpredictable results. The values do NOT need to be
|
||||
passed in as percentages; the plugin will calculate the total and per-slice
|
||||
percentages internally.
|
||||
|
||||
* Created by Brian Medendorp
|
||||
|
||||
* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars
|
||||
|
||||
The plugin supports these options:
|
||||
|
||||
series: {
|
||||
pie: {
|
||||
show: true/false
|
||||
radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
|
||||
innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
|
||||
startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
|
||||
tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
|
||||
offset: {
|
||||
top: integer value to move the pie up or down
|
||||
left: integer value to move the pie left or right, or 'auto'
|
||||
},
|
||||
stroke: {
|
||||
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
|
||||
width: integer pixel width of the stroke
|
||||
},
|
||||
label: {
|
||||
show: true/false, or 'auto'
|
||||
formatter: a user-defined function that modifies the text/style of the label text
|
||||
radius: 0-1 for percentage of fullsize, or a specified pixel length
|
||||
background: {
|
||||
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
|
||||
opacity: 0-1
|
||||
},
|
||||
threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
|
||||
},
|
||||
combine: {
|
||||
threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
|
||||
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
|
||||
label: any text value of what the combined slice should be labeled
|
||||
}
|
||||
highlight: {
|
||||
opacity: 0-1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
More detail and specific examples can be found in the included HTML file.
|
||||
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
// Maximum redraw attempts when fitting labels within the plot
|
||||
|
||||
var REDRAW_ATTEMPTS = 10;
|
||||
|
||||
// Factor by which to shrink the pie when fitting labels within the plot
|
||||
|
||||
var REDRAW_SHRINK = 0.95;
|
||||
|
||||
function init(plot) {
|
||||
|
||||
var canvas = null,
|
||||
target = null,
|
||||
options = null,
|
||||
maxRadius = null,
|
||||
centerLeft = null,
|
||||
centerTop = null,
|
||||
processed = false,
|
||||
ctx = null;
|
||||
|
||||
// interactive variables
|
||||
|
||||
var highlights = [];
|
||||
|
||||
// add hook to determine if pie plugin in enabled, and then perform necessary operations
|
||||
|
||||
plot.hooks.processOptions.push(function(plot, options) {
|
||||
if (options.series.pie.show) {
|
||||
|
||||
options.grid.show = false;
|
||||
|
||||
// set labels.show
|
||||
|
||||
if (options.series.pie.label.show == "auto") {
|
||||
if (options.legend.show) {
|
||||
options.series.pie.label.show = false;
|
||||
} else {
|
||||
options.series.pie.label.show = true;
|
||||
}
|
||||
}
|
||||
|
||||
// set radius
|
||||
|
||||
if (options.series.pie.radius == "auto") {
|
||||
if (options.series.pie.label.show) {
|
||||
options.series.pie.radius = 3/4;
|
||||
} else {
|
||||
options.series.pie.radius = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure sane tilt
|
||||
|
||||
if (options.series.pie.tilt > 1) {
|
||||
options.series.pie.tilt = 1;
|
||||
} else if (options.series.pie.tilt < 0) {
|
||||
options.series.pie.tilt = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
plot.hooks.bindEvents.push(function(plot, eventHolder) {
|
||||
var options = plot.getOptions();
|
||||
if (options.series.pie.show) {
|
||||
if (options.grid.hoverable) {
|
||||
eventHolder.unbind("mousemove").mousemove(onMouseMove);
|
||||
}
|
||||
if (options.grid.clickable) {
|
||||
eventHolder.unbind("click").click(onClick);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) {
|
||||
var options = plot.getOptions();
|
||||
if (options.series.pie.show) {
|
||||
processDatapoints(plot, series, data, datapoints);
|
||||
}
|
||||
});
|
||||
|
||||
plot.hooks.drawOverlay.push(function(plot, octx) {
|
||||
var options = plot.getOptions();
|
||||
if (options.series.pie.show) {
|
||||
drawOverlay(plot, octx);
|
||||
}
|
||||
});
|
||||
|
||||
plot.hooks.draw.push(function(plot, newCtx) {
|
||||
var options = plot.getOptions();
|
||||
if (options.series.pie.show) {
|
||||
draw(plot, newCtx);
|
||||
}
|
||||
});
|
||||
|
||||
function processDatapoints(plot, series, datapoints) {
|
||||
if (!processed) {
|
||||
processed = true;
|
||||
canvas = plot.getCanvas();
|
||||
target = $(canvas).parent();
|
||||
options = plot.getOptions();
|
||||
plot.setData(combine(plot.getData()));
|
||||
}
|
||||
}
|
||||
|
||||
function combine(data) {
|
||||
|
||||
var total = 0,
|
||||
combined = 0,
|
||||
numCombined = 0,
|
||||
color = options.series.pie.combine.color,
|
||||
newdata = [];
|
||||
|
||||
// Fix up the raw data from Flot, ensuring the data is numeric
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
|
||||
var value = data[i].data;
|
||||
|
||||
// If the data is an array, we'll assume that it's a standard
|
||||
// Flot x-y pair, and are concerned only with the second value.
|
||||
|
||||
// Note how we use the original array, rather than creating a
|
||||
// new one; this is more efficient and preserves any extra data
|
||||
// that the user may have stored in higher indexes.
|
||||
|
||||
if ($.isArray(value) && value.length == 1) {
|
||||
value = value[0];
|
||||
}
|
||||
|
||||
if ($.isArray(value)) {
|
||||
// Equivalent to $.isNumeric() but compatible with jQuery < 1.7
|
||||
if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) {
|
||||
value[1] = +value[1];
|
||||
} else {
|
||||
value[1] = 0;
|
||||
}
|
||||
} else if (!isNaN(parseFloat(value)) && isFinite(value)) {
|
||||
value = [1, +value];
|
||||
} else {
|
||||
value = [1, 0];
|
||||
}
|
||||
|
||||
data[i].data = [value];
|
||||
}
|
||||
|
||||
// Sum up all the slices, so we can calculate percentages for each
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
total += data[i].data[0][1];
|
||||
}
|
||||
|
||||
// Count the number of slices with percentages below the combine
|
||||
// threshold; if it turns out to be just one, we won't combine.
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var value = data[i].data[0][1];
|
||||
if (value / total <= options.series.pie.combine.threshold) {
|
||||
combined += value;
|
||||
numCombined++;
|
||||
if (!color) {
|
||||
color = data[i].color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var value = data[i].data[0][1];
|
||||
if (numCombined < 2 || value / total > options.series.pie.combine.threshold) {
|
||||
newdata.push(
|
||||
$.extend(data[i], { /* extend to allow keeping all other original data values
|
||||
and using them e.g. in labelFormatter. */
|
||||
data: [[1, value]],
|
||||
color: data[i].color,
|
||||
label: data[i].label,
|
||||
angle: value * Math.PI * 2 / total,
|
||||
percent: value / (total / 100)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (numCombined > 1) {
|
||||
newdata.push({
|
||||
data: [[1, combined]],
|
||||
color: color,
|
||||
label: options.series.pie.combine.label,
|
||||
angle: combined * Math.PI * 2 / total,
|
||||
percent: combined / (total / 100)
|
||||
});
|
||||
}
|
||||
|
||||
return newdata;
|
||||
}
|
||||
|
||||
function draw(plot, newCtx) {
|
||||
|
||||
if (!target) {
|
||||
return; // if no series were passed
|
||||
}
|
||||
|
||||
var canvasWidth = plot.getPlaceholder().width(),
|
||||
canvasHeight = plot.getPlaceholder().height(),
|
||||
legendWidth = target.children().filter(".legend").children().width() || 0;
|
||||
|
||||
ctx = newCtx;
|
||||
|
||||
// WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE!
|
||||
|
||||
// When combining smaller slices into an 'other' slice, we need to
|
||||
// add a new series. Since Flot gives plugins no way to modify the
|
||||
// list of series, the pie plugin uses a hack where the first call
|
||||
// to processDatapoints results in a call to setData with the new
|
||||
// list of series, then subsequent processDatapoints do nothing.
|
||||
|
||||
// The plugin-global 'processed' flag is used to control this hack;
|
||||
// it starts out false, and is set to true after the first call to
|
||||
// processDatapoints.
|
||||
|
||||
// Unfortunately this turns future setData calls into no-ops; they
|
||||
// call processDatapoints, the flag is true, and nothing happens.
|
||||
|
||||
// To fix this we'll set the flag back to false here in draw, when
|
||||
// all series have been processed, so the next sequence of calls to
|
||||
// processDatapoints once again starts out with a slice-combine.
|
||||
// This is really a hack; in 0.9 we need to give plugins a proper
|
||||
// way to modify series before any processing begins.
|
||||
|
||||
processed = false;
|
||||
|
||||
// calculate maximum radius and center point
|
||||
|
||||
maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
|
||||
centerTop = canvasHeight / 2 + options.series.pie.offset.top;
|
||||
centerLeft = canvasWidth / 2;
|
||||
|
||||
if (options.series.pie.offset.left == "auto") {
|
||||
if (options.legend.position.match("w")) {
|
||||
centerLeft += legendWidth / 2;
|
||||
} else {
|
||||
centerLeft -= legendWidth / 2;
|
||||
}
|
||||
if (centerLeft < maxRadius) {
|
||||
centerLeft = maxRadius;
|
||||
} else if (centerLeft > canvasWidth - maxRadius) {
|
||||
centerLeft = canvasWidth - maxRadius;
|
||||
}
|
||||
} else {
|
||||
centerLeft += options.series.pie.offset.left;
|
||||
}
|
||||
|
||||
var slices = plot.getData(),
|
||||
attempts = 0;
|
||||
|
||||
// Keep shrinking the pie's radius until drawPie returns true,
|
||||
// indicating that all the labels fit, or we try too many times.
|
||||
|
||||
do {
|
||||
if (attempts > 0) {
|
||||
maxRadius *= REDRAW_SHRINK;
|
||||
}
|
||||
attempts += 1;
|
||||
clear();
|
||||
if (options.series.pie.tilt <= 0.8) {
|
||||
drawShadow();
|
||||
}
|
||||
} while (!drawPie() && attempts < REDRAW_ATTEMPTS)
|
||||
|
||||
if (attempts >= REDRAW_ATTEMPTS) {
|
||||
clear();
|
||||
target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
|
||||
}
|
||||
|
||||
if (plot.setSeries && plot.insertLegend) {
|
||||
plot.setSeries(slices);
|
||||
plot.insertLegend();
|
||||
}
|
||||
|
||||
// we're actually done at this point, just defining internal functions at this point
|
||||
|
||||
function clear() {
|
||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
target.children().filter(".pieLabel, .pieLabelBackground").remove();
|
||||
}
|
||||
|
||||
function drawShadow() {
|
||||
|
||||
var shadowLeft = options.series.pie.shadow.left;
|
||||
var shadowTop = options.series.pie.shadow.top;
|
||||
var edge = 10;
|
||||
var alpha = options.series.pie.shadow.alpha;
|
||||
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
|
||||
|
||||
if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) {
|
||||
return; // shadow would be outside canvas, so don't draw it
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(shadowLeft,shadowTop);
|
||||
ctx.globalAlpha = alpha;
|
||||
ctx.fillStyle = "#000";
|
||||
|
||||
// center and rotate to starting position
|
||||
|
||||
ctx.translate(centerLeft,centerTop);
|
||||
ctx.scale(1, options.series.pie.tilt);
|
||||
|
||||
//radius -= edge;
|
||||
|
||||
for (var i = 1; i <= edge; i++) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
|
||||
ctx.fill();
|
||||
radius -= i;
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawPie() {
|
||||
|
||||
var startAngle = Math.PI * options.series.pie.startAngle;
|
||||
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
|
||||
|
||||
// center and rotate to starting position
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(centerLeft,centerTop);
|
||||
ctx.scale(1, options.series.pie.tilt);
|
||||
//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
|
||||
|
||||
// draw slices
|
||||
|
||||
ctx.save();
|
||||
var currentAngle = startAngle;
|
||||
for (var i = 0; i < slices.length; ++i) {
|
||||
slices[i].startAngle = currentAngle;
|
||||
drawSlice(slices[i].angle, slices[i].color, true);
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// draw slice outlines
|
||||
|
||||
if (options.series.pie.stroke.width > 0) {
|
||||
ctx.save();
|
||||
ctx.lineWidth = options.series.pie.stroke.width;
|
||||
currentAngle = startAngle;
|
||||
for (var i = 0; i < slices.length; ++i) {
|
||||
drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// draw donut hole
|
||||
|
||||
drawDonutHole(ctx);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
// Draw the labels, returning true if they fit within the plot
|
||||
|
||||
if (options.series.pie.label.show) {
|
||||
return drawLabels();
|
||||
} else return true;
|
||||
|
||||
function drawSlice(angle, color, fill) {
|
||||
|
||||
if (angle <= 0 || isNaN(angle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fill) {
|
||||
ctx.fillStyle = color;
|
||||
} else {
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineJoin = "round";
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
if (Math.abs(angle - Math.PI * 2) > 0.000000001) {
|
||||
ctx.moveTo(0, 0); // Center of the pie
|
||||
}
|
||||
|
||||
//ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera
|
||||
ctx.arc(0, 0, radius,currentAngle, currentAngle + angle / 2, false);
|
||||
ctx.arc(0, 0, radius,currentAngle + angle / 2, currentAngle + angle, false);
|
||||
ctx.closePath();
|
||||
//ctx.rotate(angle); // This doesn't work properly in Opera
|
||||
currentAngle += angle;
|
||||
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
} else {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function drawLabels() {
|
||||
|
||||
var currentAngle = startAngle;
|
||||
var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius;
|
||||
|
||||
for (var i = 0; i < slices.length; ++i) {
|
||||
if (slices[i].percent >= options.series.pie.label.threshold * 100) {
|
||||
if (!drawLabel(slices[i], currentAngle, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
currentAngle += slices[i].angle;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
function drawLabel(slice, startAngle, index) {
|
||||
|
||||
if (slice.data[0][1] == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// format label text
|
||||
|
||||
var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
|
||||
|
||||
if (lf) {
|
||||
text = lf(slice.label, slice);
|
||||
} else {
|
||||
text = slice.label;
|
||||
}
|
||||
|
||||
if (plf) {
|
||||
text = plf(text, slice);
|
||||
}
|
||||
|
||||
var halfAngle = ((startAngle + slice.angle) + startAngle) / 2;
|
||||
var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
|
||||
var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
|
||||
|
||||
var html = "<span class='pieLabel' id='pieLabel" + index + "' style='position:absolute;top:" + y + "px;left:" + x + "px;'>" + text + "</span>";
|
||||
target.append(html);
|
||||
|
||||
var label = target.children("#pieLabel" + index);
|
||||
var labelTop = (y - label.height() / 2);
|
||||
var labelLeft = (x - label.width() / 2);
|
||||
|
||||
label.css("top", labelTop);
|
||||
label.css("left", labelLeft);
|
||||
|
||||
// check to make sure that the label is not outside the canvas
|
||||
|
||||
if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.series.pie.label.background.opacity != 0) {
|
||||
|
||||
// put in the transparent background separately to avoid blended labels and label boxes
|
||||
|
||||
var c = options.series.pie.label.background.color;
|
||||
|
||||
if (c == null) {
|
||||
c = slice.color;
|
||||
}
|
||||
|
||||
var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;";
|
||||
$("<div class='pieLabelBackground' style='position:absolute;width:" + label.width() + "px;height:" + label.height() + "px;" + pos + "background-color:" + c + ";'></div>")
|
||||
.css("opacity", options.series.pie.label.background.opacity)
|
||||
.insertBefore(label);
|
||||
}
|
||||
|
||||
return true;
|
||||
} // end individual label function
|
||||
} // end drawLabels function
|
||||
} // end drawPie function
|
||||
} // end draw function
|
||||
|
||||
// Placed here because it needs to be accessed from multiple locations
|
||||
|
||||
function drawDonutHole(layer) {
|
||||
if (options.series.pie.innerRadius > 0) {
|
||||
|
||||
// subtract the center
|
||||
|
||||
layer.save();
|
||||
var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
|
||||
layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color
|
||||
layer.beginPath();
|
||||
layer.fillStyle = options.series.pie.stroke.color;
|
||||
layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
|
||||
layer.fill();
|
||||
layer.closePath();
|
||||
layer.restore();
|
||||
|
||||
// add inner stroke
|
||||
|
||||
layer.save();
|
||||
layer.beginPath();
|
||||
layer.strokeStyle = options.series.pie.stroke.color;
|
||||
layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
|
||||
layer.stroke();
|
||||
layer.closePath();
|
||||
layer.restore();
|
||||
|
||||
// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
|
||||
}
|
||||
}
|
||||
|
||||
//-- Additional Interactive related functions --
|
||||
|
||||
function isPointInPoly(poly, pt) {
|
||||
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
|
||||
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
|
||||
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
|
||||
&& (c = !c);
|
||||
return c;
|
||||
}
|
||||
|
||||
function findNearbySlice(mouseX, mouseY) {
|
||||
|
||||
var slices = plot.getData(),
|
||||
options = plot.getOptions(),
|
||||
radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius,
|
||||
x, y;
|
||||
|
||||
for (var i = 0; i < slices.length; ++i) {
|
||||
|
||||
var s = slices[i];
|
||||
|
||||
if (s.pie.show) {
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0); // Center of the pie
|
||||
//ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
|
||||
ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false);
|
||||
ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false);
|
||||
ctx.closePath();
|
||||
x = mouseX - centerLeft;
|
||||
y = mouseY - centerTop;
|
||||
|
||||
if (ctx.isPointInPath) {
|
||||
if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) {
|
||||
ctx.restore();
|
||||
return {
|
||||
datapoint: [s.percent, s.data],
|
||||
dataIndex: 0,
|
||||
series: s,
|
||||
seriesIndex: i
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
||||
// excanvas for IE doesn;t support isPointInPath, this is a workaround.
|
||||
|
||||
var p1X = radius * Math.cos(s.startAngle),
|
||||
p1Y = radius * Math.sin(s.startAngle),
|
||||
p2X = radius * Math.cos(s.startAngle + s.angle / 4),
|
||||
p2Y = radius * Math.sin(s.startAngle + s.angle / 4),
|
||||
p3X = radius * Math.cos(s.startAngle + s.angle / 2),
|
||||
p3Y = radius * Math.sin(s.startAngle + s.angle / 2),
|
||||
p4X = radius * Math.cos(s.startAngle + s.angle / 1.5),
|
||||
p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5),
|
||||
p5X = radius * Math.cos(s.startAngle + s.angle),
|
||||
p5Y = radius * Math.sin(s.startAngle + s.angle),
|
||||
arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]],
|
||||
arrPoint = [x, y];
|
||||
|
||||
// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
|
||||
|
||||
if (isPointInPoly(arrPoly, arrPoint)) {
|
||||
ctx.restore();
|
||||
return {
|
||||
datapoint: [s.percent, s.data],
|
||||
dataIndex: 0,
|
||||
series: s,
|
||||
seriesIndex: i
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
triggerClickHoverEvent("plothover", e);
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
triggerClickHoverEvent("plotclick", e);
|
||||
}
|
||||
|
||||
// trigger click or hover event (they send the same parameters so we share their code)
|
||||
|
||||
function triggerClickHoverEvent(eventname, e) {
|
||||
|
||||
var offset = plot.offset();
|
||||
var canvasX = parseInt(e.pageX - offset.left);
|
||||
var canvasY = parseInt(e.pageY - offset.top);
|
||||
var item = findNearbySlice(canvasX, canvasY);
|
||||
|
||||
if (options.grid.autoHighlight) {
|
||||
|
||||
// clear auto-highlights
|
||||
|
||||
for (var i = 0; i < highlights.length; ++i) {
|
||||
var h = highlights[i];
|
||||
if (h.auto == eventname && !(item && h.series == item.series)) {
|
||||
unhighlight(h.series);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight the slice
|
||||
|
||||
if (item) {
|
||||
highlight(item.series, eventname);
|
||||
}
|
||||
|
||||
// trigger any hover bind events
|
||||
|
||||
var pos = { pageX: e.pageX, pageY: e.pageY };
|
||||
target.trigger(eventname, [pos, item]);
|
||||
}
|
||||
|
||||
function highlight(s, auto) {
|
||||
//if (typeof s == "number") {
|
||||
// s = series[s];
|
||||
//}
|
||||
|
||||
var i = indexOfHighlight(s);
|
||||
|
||||
if (i == -1) {
|
||||
highlights.push({ series: s, auto: auto });
|
||||
plot.triggerRedrawOverlay();
|
||||
} else if (!auto) {
|
||||
highlights[i].auto = false;
|
||||
}
|
||||
}
|
||||
|
||||
function unhighlight(s) {
|
||||
if (s == null) {
|
||||
highlights = [];
|
||||
plot.triggerRedrawOverlay();
|
||||
}
|
||||
|
||||
//if (typeof s == "number") {
|
||||
// s = series[s];
|
||||
//}
|
||||
|
||||
var i = indexOfHighlight(s);
|
||||
|
||||
if (i != -1) {
|
||||
highlights.splice(i, 1);
|
||||
plot.triggerRedrawOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
function indexOfHighlight(s) {
|
||||
for (var i = 0; i < highlights.length; ++i) {
|
||||
var h = highlights[i];
|
||||
if (h.series == s)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function drawOverlay(plot, octx) {
|
||||
|
||||
var options = plot.getOptions();
|
||||
|
||||
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
|
||||
|
||||
octx.save();
|
||||
octx.translate(centerLeft, centerTop);
|
||||
octx.scale(1, options.series.pie.tilt);
|
||||
|
||||
for (var i = 0; i < highlights.length; ++i) {
|
||||
drawHighlight(highlights[i].series);
|
||||
}
|
||||
|
||||
drawDonutHole(octx);
|
||||
|
||||
octx.restore();
|
||||
|
||||
function drawHighlight(series) {
|
||||
|
||||
if (series.angle <= 0 || isNaN(series.angle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
|
||||
octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor
|
||||
octx.beginPath();
|
||||
if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) {
|
||||
octx.moveTo(0, 0); // Center of the pie
|
||||
}
|
||||
octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false);
|
||||
octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false);
|
||||
octx.closePath();
|
||||
octx.fill();
|
||||
}
|
||||
}
|
||||
} // end init (plugin body)
|
||||
|
||||
// define pie specific options and their default values
|
||||
|
||||
var options = {
|
||||
series: {
|
||||
pie: {
|
||||
show: false,
|
||||
radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
|
||||
innerRadius: 0, /* for donut */
|
||||
startAngle: 3/2,
|
||||
tilt: 1,
|
||||
shadow: {
|
||||
left: 5, // shadow left offset
|
||||
top: 15, // shadow top offset
|
||||
alpha: 0.02 // shadow alpha
|
||||
},
|
||||
offset: {
|
||||
top: 0,
|
||||
left: "auto"
|
||||
},
|
||||
stroke: {
|
||||
color: "#fff",
|
||||
width: 1
|
||||
},
|
||||
label: {
|
||||
show: "auto",
|
||||
formatter: function(label, slice) {
|
||||
return "<div style='font-size:13px;text-align:center;padding:2px;color:" + slice.color + ";'>" + label + " " + Math.round(slice.percent) + "%</div>";
|
||||
}, // formatter function
|
||||
radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
|
||||
background: {
|
||||
color: null,
|
||||
opacity: 0
|
||||
},
|
||||
threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
|
||||
},
|
||||
combine: {
|
||||
threshold: -1, // percentage at which to combine little slices into one larger slice
|
||||
color: null, // color to give the new slice (auto-generated if null)
|
||||
label: "Other" // label to give the new slice
|
||||
},
|
||||
highlight: {
|
||||
//color: "#fff", // will add this functionality once parseColor is available
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: "pie",
|
||||
version: "1.1"
|
||||
});
|
||||
|
||||
})(jQuery);
|
57
app/assets/javascripts/js/flot/jquery.flot.resize.js
Executable file
57
app/assets/javascripts/js/flot/jquery.flot.resize.js
Executable file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Flot plugin for automatically redrawing plots when the placeholder
|
||||
size changes, e.g. on window resizes.
|
||||
|
||||
It works by listening for changes on the placeholder div (through the
|
||||
jQuery resize event plugin) - if the size changes, it will redraw the
|
||||
plot.
|
||||
|
||||
There are no options. If you need to disable the plugin for some
|
||||
plots, you can just fix the size of their placeholders.
|
||||
*/
|
||||
|
||||
|
||||
/* Inline dependency:
|
||||
* jQuery resize event - v1.2 - 3/14/2010
|
||||
* http://benalman.com/projects/jquery-resize-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
|
||||
|
||||
|
||||
(function ($) {
|
||||
var redrawing = 0;
|
||||
var options = { }; // no options
|
||||
|
||||
function init(plot) {
|
||||
function bindEvents(plot, eventHolder) {
|
||||
if (!redrawing)
|
||||
plot.getPlaceholder().resize(onResize);
|
||||
|
||||
function onResize() {
|
||||
var placeholder = plot.getPlaceholder();
|
||||
|
||||
// somebody might have hidden us and we can't plot
|
||||
// when we don't have the dimensions
|
||||
if (placeholder.width() == 0 || placeholder.height() == 0)
|
||||
return;
|
||||
|
||||
++redrawing;
|
||||
$.plot(placeholder, plot.getData(), plot.getOptions());
|
||||
--redrawing;
|
||||
}
|
||||
}
|
||||
|
||||
plot.hooks.bindEvents.push(bindEvents);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'resize',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
212
app/assets/javascripts/js/flot/jquery.flot.spline.js
Executable file
212
app/assets/javascripts/js/flot/jquery.flot.spline.js
Executable file
@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Flot plugin that provides spline interpolation for line graphs
|
||||
* author: Alex Bardas < alex.bardas@gmail.com >
|
||||
* modified by: Avi Kohn https://github.com/AMKohn
|
||||
* based on the spline interpolation described at:
|
||||
* http://scaledinnovation.com/analytics/splines/aboutSplines.html
|
||||
*
|
||||
* Example usage: (add in plot options series object)
|
||||
* for linespline:
|
||||
* series: {
|
||||
* ...
|
||||
* lines: {
|
||||
* show: false
|
||||
* },
|
||||
* splines: {
|
||||
* show: true,
|
||||
* tension: x, (float between 0 and 1, defaults to 0.5),
|
||||
* lineWidth: y (number, defaults to 2),
|
||||
* fill: z (float between 0 .. 1 or false, as in flot documentation)
|
||||
* },
|
||||
* ...
|
||||
* }
|
||||
* areaspline:
|
||||
* series: {
|
||||
* ...
|
||||
* lines: {
|
||||
* show: true,
|
||||
* lineWidth: 0, (line drawing will not execute)
|
||||
* fill: x, (float between 0 .. 1, as in flot documentation)
|
||||
* ...
|
||||
* },
|
||||
* splines: {
|
||||
* show: true,
|
||||
* tension: 0.5 (float between 0 and 1)
|
||||
* },
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @param {Number} x0, y0, x1, y1: coordinates of the end (knot) points of the segment
|
||||
* @param {Number} x2, y2: the next knot (not connected, but needed to calculate p2)
|
||||
* @param {Number} tension: control how far the control points spread
|
||||
* @return {Array}: p1 -> control point, from x1 back toward x0
|
||||
* p2 -> the next control point, returned to become the next segment's p1
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
function getControlPoints(x0, y0, x1, y1, x2, y2, tension) {
|
||||
|
||||
var pow = Math.pow,
|
||||
sqrt = Math.sqrt,
|
||||
d01, d12, fa, fb, p1x, p1y, p2x, p2y;
|
||||
|
||||
// Scaling factors: distances from this knot to the previous and following knots.
|
||||
d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
|
||||
d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
|
||||
|
||||
fa = tension * d01 / (d01 + d12);
|
||||
fb = tension - fa;
|
||||
|
||||
p1x = x1 + fa * (x0 - x2);
|
||||
p1y = y1 + fa * (y0 - y2);
|
||||
|
||||
p2x = x1 - fb * (x0 - x2);
|
||||
p2y = y1 - fb * (y0 - y2);
|
||||
|
||||
return [p1x, p1y, p2x, p2y];
|
||||
}
|
||||
|
||||
var line = [];
|
||||
|
||||
function drawLine(points, ctx, height, fill, seriesColor) {
|
||||
var c = $.color.parse(seriesColor);
|
||||
|
||||
c.a = typeof fill == "number" ? fill : .3;
|
||||
c.normalize();
|
||||
c = c.toString();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(points[0][0], points[0][1]);
|
||||
|
||||
var plength = points.length;
|
||||
|
||||
for (var i = 0; i < plength; i++) {
|
||||
ctx[points[i][3]].apply(ctx, points[i][2]);
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
ctx.lineWidth = 0;
|
||||
ctx.lineTo(points[plength - 1][0], height);
|
||||
ctx.lineTo(points[0][0], height);
|
||||
|
||||
ctx.closePath();
|
||||
|
||||
if (fill !== false) {
|
||||
ctx.fillStyle = c;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} ctx: canvas context
|
||||
* @param {String} type: accepted strings: 'bezier' or 'quadratic' (defaults to quadratic)
|
||||
* @param {Array} points: 2 points for which to draw the interpolation
|
||||
* @param {Array} cpoints: control points for those segment points
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
function queue(ctx, type, points, cpoints) {
|
||||
if (type === void 0 || (type !== 'bezier' && type !== 'quadratic')) {
|
||||
type = 'quadratic';
|
||||
}
|
||||
type = type + 'CurveTo';
|
||||
|
||||
if (line.length == 0) line.push([points[0], points[1], cpoints.concat(points.slice(2)), type]);
|
||||
else if (type == "quadraticCurveTo" && points.length == 2) {
|
||||
cpoints = cpoints.slice(0, 2).concat(points);
|
||||
|
||||
line.push([points[0], points[1], cpoints, type]);
|
||||
}
|
||||
else line.push([points[2], points[3], cpoints.concat(points.slice(2)), type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} plot
|
||||
* @param {Object} ctx: canvas context
|
||||
* @param {Object} series
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function drawSpline(plot, ctx, series) {
|
||||
// Not interested if spline is not requested
|
||||
if (series.splines.show !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cp = [],
|
||||
// array of control points
|
||||
tension = series.splines.tension || 0.5,
|
||||
idx, x, y, points = series.datapoints.points,
|
||||
ps = series.datapoints.pointsize,
|
||||
plotOffset = plot.getPlotOffset(),
|
||||
len = points.length,
|
||||
pts = [];
|
||||
|
||||
line = [];
|
||||
|
||||
// Cannot display a linespline/areaspline if there are less than 3 points
|
||||
if (len / ps < 4) {
|
||||
$.extend(series.lines, series.splines);
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < len; idx += ps) {
|
||||
x = points[idx];
|
||||
y = points[idx + 1];
|
||||
if (x == null || x < series.xaxis.min || x > series.xaxis.max || y < series.yaxis.min || y > series.yaxis.max) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pts.push(series.xaxis.p2c(x) + plotOffset.left, series.yaxis.p2c(y) + plotOffset.top);
|
||||
}
|
||||
|
||||
len = pts.length;
|
||||
|
||||
// Draw an open curve, not connected at the ends
|
||||
for (idx = 0; idx < len - 2; idx += 2) {
|
||||
cp = cp.concat(getControlPoints.apply(this, pts.slice(idx, idx + 6).concat([tension])));
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.strokeStyle = series.color;
|
||||
ctx.lineWidth = series.splines.lineWidth;
|
||||
|
||||
queue(ctx, 'quadratic', pts.slice(0, 4), cp.slice(0, 2));
|
||||
|
||||
for (idx = 2; idx < len - 3; idx += 2) {
|
||||
queue(ctx, 'bezier', pts.slice(idx, idx + 4), cp.slice(2 * idx - 2, 2 * idx + 2));
|
||||
}
|
||||
|
||||
queue(ctx, 'quadratic', pts.slice(len - 2, len), [cp[2 * len - 10], cp[2 * len - 9], pts[len - 4], pts[len - 3]]);
|
||||
|
||||
drawLine(line, ctx, plot.height() + 10, series.splines.fill, series.color);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: function(plot) {
|
||||
plot.hooks.drawSeries.push(drawSpline);
|
||||
},
|
||||
options: {
|
||||
series: {
|
||||
splines: {
|
||||
show: false,
|
||||
lineWidth: 2,
|
||||
tension: 0.5,
|
||||
fill: false
|
||||
}
|
||||
}
|
||||
},
|
||||
name: 'spline',
|
||||
version: '0.8.2'
|
||||
});
|
||||
})(jQuery);
|
188
app/assets/javascripts/js/flot/jquery.flot.stack.js
Executable file
188
app/assets/javascripts/js/flot/jquery.flot.stack.js
Executable file
@ -0,0 +1,188 @@
|
||||
/* Flot plugin for stacking data sets rather than overlyaing them.
|
||||
|
||||
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||
Licensed under the MIT license.
|
||||
|
||||
The plugin assumes the data is sorted on x (or y if stacking horizontally).
|
||||
For line charts, it is assumed that if a line has an undefined gap (from a
|
||||
null point), then the line above it should have the same gap - insert zeros
|
||||
instead of "null" if you want another behaviour. This also holds for the start
|
||||
and end of the chart. Note that stacking a mix of positive and negative values
|
||||
in most instances doesn't make sense (so it looks weird).
|
||||
|
||||
Two or more series are stacked when their "stack" attribute is set to the same
|
||||
key (which can be any number or string or just "true"). To specify the default
|
||||
stack, you can set the stack option like this:
|
||||
|
||||
series: {
|
||||
stack: null/false, true, or a key (number/string)
|
||||
}
|
||||
|
||||
You can also specify it for a single series, like this:
|
||||
|
||||
$.plot( $("#placeholder"), [{
|
||||
data: [ ... ],
|
||||
stack: true
|
||||
}])
|
||||
|
||||
The stacking order is determined by the order of the data series in the array
|
||||
(later series end up on top of the previous).
|
||||
|
||||
Internally, the plugin modifies the datapoints in each series, adding an
|
||||
offset to the y value. For line series, extra data points are inserted through
|
||||
interpolation. If there's a second y value, it's also adjusted (e.g for bar
|
||||
charts or filled areas).
|
||||
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
series: { stack: null } // or number/string
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
function findMatchingSeries(s, allseries) {
|
||||
var res = null;
|
||||
for (var i = 0; i < allseries.length; ++i) {
|
||||
if (s == allseries[i])
|
||||
break;
|
||||
|
||||
if (allseries[i].stack == s.stack)
|
||||
res = allseries[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function stackData(plot, s, datapoints) {
|
||||
if (s.stack == null || s.stack === false)
|
||||
return;
|
||||
|
||||
var other = findMatchingSeries(s, plot.getData());
|
||||
if (!other)
|
||||
return;
|
||||
|
||||
var ps = datapoints.pointsize,
|
||||
points = datapoints.points,
|
||||
otherps = other.datapoints.pointsize,
|
||||
otherpoints = other.datapoints.points,
|
||||
newpoints = [],
|
||||
px, py, intery, qx, qy, bottom,
|
||||
withlines = s.lines.show,
|
||||
horizontal = s.bars.horizontal,
|
||||
withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),
|
||||
withsteps = withlines && s.lines.steps,
|
||||
fromgap = true,
|
||||
keyOffset = horizontal ? 1 : 0,
|
||||
accumulateOffset = horizontal ? 0 : 1,
|
||||
i = 0, j = 0, l, m;
|
||||
|
||||
while (true) {
|
||||
if (i >= points.length)
|
||||
break;
|
||||
|
||||
l = newpoints.length;
|
||||
|
||||
if (points[i] == null) {
|
||||
// copy gaps
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
i += ps;
|
||||
}
|
||||
else if (j >= otherpoints.length) {
|
||||
// for lines, we can't use the rest of the points
|
||||
if (!withlines) {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
}
|
||||
i += ps;
|
||||
}
|
||||
else if (otherpoints[j] == null) {
|
||||
// oops, got a gap
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(null);
|
||||
fromgap = true;
|
||||
j += otherps;
|
||||
}
|
||||
else {
|
||||
// cases where we actually got two points
|
||||
px = points[i + keyOffset];
|
||||
py = points[i + accumulateOffset];
|
||||
qx = otherpoints[j + keyOffset];
|
||||
qy = otherpoints[j + accumulateOffset];
|
||||
bottom = 0;
|
||||
|
||||
if (px == qx) {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
|
||||
newpoints[l + accumulateOffset] += qy;
|
||||
bottom = qy;
|
||||
|
||||
i += ps;
|
||||
j += otherps;
|
||||
}
|
||||
else if (px > qx) {
|
||||
// we got past point below, might need to
|
||||
// insert interpolated extra point
|
||||
if (withlines && i > 0 && points[i - ps] != null) {
|
||||
intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);
|
||||
newpoints.push(qx);
|
||||
newpoints.push(intery + qy);
|
||||
for (m = 2; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
bottom = qy;
|
||||
}
|
||||
|
||||
j += otherps;
|
||||
}
|
||||
else { // px < qx
|
||||
if (fromgap && withlines) {
|
||||
// if we come from a gap, we just skip this point
|
||||
i += ps;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
|
||||
// we might be able to interpolate a point below,
|
||||
// this can give us a better y
|
||||
if (withlines && j > 0 && otherpoints[j - otherps] != null)
|
||||
bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
|
||||
|
||||
newpoints[l + accumulateOffset] += bottom;
|
||||
|
||||
i += ps;
|
||||
}
|
||||
|
||||
fromgap = false;
|
||||
|
||||
if (l != newpoints.length && withbottom)
|
||||
newpoints[l + 2] += bottom;
|
||||
}
|
||||
|
||||
// maintain the line steps invariant
|
||||
if (withsteps && l != newpoints.length && l > 0
|
||||
&& newpoints[l] != null
|
||||
&& newpoints[l] != newpoints[l - ps]
|
||||
&& newpoints[l + 1] != newpoints[l - ps + 1]) {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints[l + ps + m] = newpoints[l + m];
|
||||
newpoints[l + 1] = newpoints[l - ps + 1];
|
||||
}
|
||||
}
|
||||
|
||||
datapoints.points = newpoints;
|
||||
}
|
||||
|
||||
plot.hooks.processDatapoints.push(stackData);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'stack',
|
||||
version: '1.2'
|
||||
});
|
||||
})(jQuery);
|
1
app/assets/javascripts/js/flot/jquery.flot.time.min.js
vendored
Executable file
1
app/assets/javascripts/js/flot/jquery.flot.time.min.js
vendored
Executable file
@ -0,0 +1 @@
|
||||
(function(a){var i={};function d(k,j){return j*Math.floor(k/j)}function h(q,l,o,k){if(typeof q.strftime=="function"){return q.strftime(l)}var u=function(w,r){w=""+w;r=""+(r==null?"0":r);return w.length==1?r+w:w};var j=[];var v=false;var t=q.getHours();var p=t<12;if(o==null){o=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(k==null){k=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]}var m;if(t>12){m=t-12}else{if(t==0){m=12}else{m=t}}for(var n=0;n<l.length;++n){var s=l.charAt(n);if(v){switch(s){case"a":s=""+k[q.getDay()];break;case"b":s=""+o[q.getMonth()];break;case"d":s=u(q.getDate());break;case"e":s=u(q.getDate()," ");break;case"H":s=u(t);break;case"I":s=u(m);break;case"l":s=u(m," ");break;case"m":s=u(q.getMonth()+1);break;case"M":s=u(q.getMinutes());break;case"S":s=u(q.getSeconds());break;case"y":s=u(q.getFullYear()%100);break;case"Y":s=""+q.getFullYear();break;case"p":s=(p)?("am"):("pm");break;case"P":s=(p)?("AM"):("PM");break;case"w":s=""+q.getDay();break}j.push(s);v=false}else{if(s=="%"){v=true}else{j.push(s)}}}return j.join("")}function g(n){function j(q,p,o,r){q[p]=function(){return o[r].apply(o,arguments)}}var l={date:n};if(n.strftime!=undefined){j(l,"strftime",n,"strftime")}j(l,"getTime",n,"getTime");j(l,"setTime",n,"setTime");var k=["Date","Day","FullYear","Hours","Milliseconds","Minutes","Month","Seconds"];for(var m=0;m<k.length;m++){j(l,"get"+k[m],n,"getUTC"+k[m]);j(l,"set"+k[m],n,"setUTC"+k[m])}return l}function c(k,j){if(j.timezone=="browser"){return new Date(k)}else{if(!j.timezone||j.timezone=="utc"){return g(new Date(k))}else{if(typeof timezoneJS!="undefined"&&typeof timezoneJS.Date!="undefined"){var l=new timezoneJS.Date();l.setTimezone(j.timezone);l.setTime(k);return l}else{return g(new Date(k))}}}}var b={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var e=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];function f(j){j.hooks.processDatapoints.push(function(m,k,l){a.each(m.getAxes(),function(p,n){var o=n.options;if(o.mode=="time"){n.tickGenerator=function(w){var C=[],B=c(w.min,o),t=0;if(o.minTickSize!=null){if(typeof o.tickSize=="number"){t=o.tickSize}else{t=o.minTickSize[0]*b[o.minTickSize[1]]}}for(var A=0;A<e.length-1;++A){if(w.delta<(e[A][0]*b[e[A][1]]+e[A+1][0]*b[e[A+1][1]])/2&&e[A][0]*b[e[A][1]]>=t){break}}var G=e[A][0];var D=e[A][1];if(D=="year"){if(o.minTickSize!=null&&o.minTickSize[1]=="year"){G=Math.floor(o.minTickSize[0])}else{var r=Math.pow(10,Math.floor(Math.log(w.delta/b.year)/Math.LN10));var q=(w.delta/b.year)/r;if(q<1.5){G=1}else{if(q<3){G=2}else{if(q<7.5){G=5}else{G=10}}}G*=r}if(G<1){G=1}}w.tickSize=o.tickSize||[G,D];var z=w.tickSize[0];D=w.tickSize[1];var u=z*b[D];if(D=="second"){B.setSeconds(d(B.getSeconds(),z))}if(D=="minute"){B.setMinutes(d(B.getMinutes(),z))}if(D=="hour"){B.setHours(d(B.getHours(),z))}if(D=="month"){B.setMonth(d(B.getMonth(),z))}if(D=="year"){B.setFullYear(d(B.getFullYear(),z))}B.setMilliseconds(0);if(u>=b.minute){B.setSeconds(0)}if(u>=b.hour){B.setMinutes(0)}if(u>=b.day){B.setHours(0)}if(u>=b.day*4){B.setDate(1)}if(u>=b.year){B.setMonth(0)}var F=0,E=Number.NaN,x;do{x=E;E=B.getTime();C.push(E);if(D=="month"){if(z<1){B.setDate(1);var s=B.getTime();B.setMonth(B.getMonth()+1);var y=B.getTime();B.setTime(E+F*b.hour+(y-s)*z);F=B.getHours();B.setHours(0)}else{B.setMonth(B.getMonth()+z)}}else{if(D=="year"){B.setFullYear(B.getFullYear()+z)}else{B.setTime(E+u)}}}while(E<w.max&&E!=x);return C};n.tickFormatter=function(r,w){var y=c(r,w.options);if(o.timeformat!=null){return h(y,o.timeformat,o.monthNames,o.dayNames)}var s=w.tickSize[0]*b[w.tickSize[1]];var u=w.max-w.min;var x=(o.twelveHourClock)?" %p":"";var z=(o.twelveHourClock)?"%I":"%H";if(s<b.minute){fmt=z+":%M:%S"+x}else{if(s<b.day){if(u<2*b.day){fmt=z+":%M"+x}else{fmt="%b %d "+z+":%M"+x}}else{if(s<b.month){fmt="%b %d"}else{if(s<b.year){if(u<b.year){fmt="%b"}else{fmt="%b %Y"}}else{fmt="%Y"}}}}var q=h(y,fmt,o.monthNames,o.dayNames);return q}}})})}a.plot.plugins.push({init:f,options:i,name:"time",version:"1.0"})})(jQuery);
|
12
app/assets/javascripts/js/flot/jquery.flot.tooltip.min.js
vendored
Executable file
12
app/assets/javascripts/js/flot/jquery.flot.tooltip.min.js
vendored
Executable file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* jquery.flot.tooltip
|
||||
*
|
||||
* description: easy-to-use tooltips for Flot charts
|
||||
* version: 0.6
|
||||
* author: Krzysztof Urbas @krzysu [myviews.pl]
|
||||
* website: https://github.com/krzysu/flot.tooltip
|
||||
*
|
||||
* build on 2013-01-07
|
||||
* released under MIT License, 2012
|
||||
*/
|
||||
(function(a){var b={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(a,b){}}},c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){var c=this;b.hooks.bindEvents.push(function(b,d){c.plotOptions=b.getOptions();if(c.plotOptions.tooltip===!1||typeof c.plotOptions.tooltip=="undefined")return;c.tooltipOptions=c.plotOptions.tooltipOpts;var e=c.getDomElement();a(b.getPlaceholder()).bind("plothover",function(a,b,d){if(d){var f;f=c.stringFormat(c.tooltipOptions.content,d),e.html(f).css({left:c.tipPosition.x+c.tooltipOptions.shifts.x,top:c.tipPosition.y+c.tooltipOptions.shifts.y}).show(),typeof c.tooltipOptions.onHover=="function"&&c.tooltipOptions.onHover(d,e)}else e.hide().html("")}),d.mousemove(function(a){var b={};b.x=a.pageX,b.y=a.pageY,c.updateTooltipPosition(b)})})},c.prototype.getDomElement=function(){var b;return a("#flotTip").length>0?b=a("#flotTip"):(b=a("<div />").attr("id","flotTip"),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"100",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111"})),b},c.prototype.updateTooltipPosition=function(a){this.tipPosition.x=a.x,this.tipPosition.y=a.y},c.prototype.stringFormat=function(a,b){var c=/%p\.{0,1}(\d{0,})/,d=/%s/,e=/%x\.{0,1}(\d{0,})/,f=/%y\.{0,1}(\d{0,})/;return typeof a=="function"&&(a=a(b.series.data[b.dataIndex][0],b.series.data[b.dataIndex][1])),typeof b.series.percent!="undefined"&&(a=this.adjustValPrecision(c,a,b.series.percent)),typeof b.series.label!="undefined"&&(a=a.replace(d,b.series.label)),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(e,this.timestampToDate(b.series.data[b.dataIndex][0],this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(f,this.timestampToDate(b.series.data[b.dataIndex][1],this.tooltipOptions.yDateFormat))),typeof b.series.data[b.dataIndex][0]=="number"&&(a=this.adjustValPrecision(e,a,b.series.data[b.dataIndex][0])),typeof b.series.data[b.dataIndex][1]=="number"&&(a=this.adjustValPrecision(f,a,b.series.data[b.dataIndex][1])),typeof b.series.xaxis.tickFormatter!="undefined"&&(a=a.replace(e,b.series.xaxis.tickFormatter(b.series.data[b.dataIndex][0],b.series.xaxis))),typeof b.series.yaxis.tickFormatter!="undefined"&&(a=a.replace(f,b.series.yaxis.tickFormatter(b.series.data[b.dataIndex][1],b.series.yaxis))),a},c.prototype.isTimeMode=function(a,b){return typeof b.series[a].options.mode!="undefined"&&b.series[a].options.mode==="time"},c.prototype.isXDateFormat=function(a){return typeof this.tooltipOptions.xDateFormat!="undefined"&&this.tooltipOptions.xDateFormat!==null},c.prototype.isYDateFormat=function(a){return typeof this.tooltipOptions.yDateFormat!="undefined"&&this.tooltipOptions.yDateFormat!==null},c.prototype.timestampToDate=function(b,c){var d=new Date(b);return a.plot.formatDate(d,c)},c.prototype.adjustValPrecision=function(a,b,c){var d;return b.match(a)!==null&&RegExp.$1!==""&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b};var d=[],e=function(a){d.push(new c(a))};a.plot.plugins.push({init:e,options:b,name:"tooltip",version:"0.6"})})(jQuery);
|
1
app/assets/javascripts/js/gauge/gauge.min.js
vendored
Executable file
1
app/assets/javascripts/js/gauge/gauge.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
21
app/assets/javascripts/js/gauge/gauge_demo.js
Executable file
21
app/assets/javascripts/js/gauge/gauge_demo.js
Executable file
@ -0,0 +1,21 @@
|
||||
var opts = {
|
||||
lines: 12, // The number of lines to draw
|
||||
angle: 0, // The length of each line
|
||||
lineWidth: 0.4, // The line thickness
|
||||
pointer: {
|
||||
length: 0.75, // The radius of the inner circle
|
||||
strokeWidth: 0.042, // The rotation offset
|
||||
color: '#1D212A' // Fill color
|
||||
},
|
||||
limitMax: 'false', // If true, the pointer will not go past the end of the gauge
|
||||
colorStart: '#1ABC9C', // Colors
|
||||
colorStop: '#1ABC9C', // just experiment with them
|
||||
strokeColor: '#F0F3F3', // to see which ones work best for you
|
||||
generateGradient: true
|
||||
};
|
||||
var target = document.getElementById('foo'); // your canvas element
|
||||
var gauge = new Gauge(target).setOptions(opts); // create sexy gauge!
|
||||
gauge.maxValue = 6000; // set max gauge value
|
||||
gauge.animationSpeed = 32; // set animation speed (32 is default value)
|
||||
gauge.set(3200); // set actual value
|
||||
gauge.setTextField(document.getElementById("gauge-text"));
|
11
app/assets/javascripts/js/icheck/icheck.min.js
vendored
Executable file
11
app/assets/javascripts/js/icheck/icheck.min.js
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
/*! iCheck v1.0.2 by Damir Sultanov, http://git.io/arlzeA, MIT Licensed */
|
||||
(function(f){function A(a,b,d){var c=a[0],g=/er/.test(d)?_indeterminate:/bl/.test(d)?n:k,e=d==_update?{checked:c[k],disabled:c[n],indeterminate:"true"==a.attr(_indeterminate)||"false"==a.attr(_determinate)}:c[g];if(/^(ch|di|in)/.test(d)&&!e)x(a,g);else if(/^(un|en|de)/.test(d)&&e)q(a,g);else if(d==_update)for(var f in e)e[f]?x(a,f,!0):q(a,f,!0);else if(!b||"toggle"==d){if(!b)a[_callback]("ifClicked");e?c[_type]!==r&&q(a,g):x(a,g)}}function x(a,b,d){var c=a[0],g=a.parent(),e=b==k,u=b==_indeterminate,
|
||||
v=b==n,s=u?_determinate:e?y:"enabled",F=l(a,s+t(c[_type])),B=l(a,b+t(c[_type]));if(!0!==c[b]){if(!d&&b==k&&c[_type]==r&&c.name){var w=a.closest("form"),p='input[name="'+c.name+'"]',p=w.length?w.find(p):f(p);p.each(function(){this!==c&&f(this).data(m)&&q(f(this),b)})}u?(c[b]=!0,c[k]&&q(a,k,"force")):(d||(c[b]=!0),e&&c[_indeterminate]&&q(a,_indeterminate,!1));D(a,e,b,d)}c[n]&&l(a,_cursor,!0)&&g.find("."+C).css(_cursor,"default");g[_add](B||l(a,b)||"");g.attr("role")&&!u&&g.attr("aria-"+(v?n:k),"true");
|
||||
g[_remove](F||l(a,s)||"")}function q(a,b,d){var c=a[0],g=a.parent(),e=b==k,f=b==_indeterminate,m=b==n,s=f?_determinate:e?y:"enabled",q=l(a,s+t(c[_type])),r=l(a,b+t(c[_type]));if(!1!==c[b]){if(f||!d||"force"==d)c[b]=!1;D(a,e,s,d)}!c[n]&&l(a,_cursor,!0)&&g.find("."+C).css(_cursor,"pointer");g[_remove](r||l(a,b)||"");g.attr("role")&&!f&&g.attr("aria-"+(m?n:k),"false");g[_add](q||l(a,s)||"")}function E(a,b){if(a.data(m)){a.parent().html(a.attr("style",a.data(m).s||""));if(b)a[_callback](b);a.off(".i").unwrap();
|
||||
f(_label+'[for="'+a[0].id+'"]').add(a.closest(_label)).off(".i")}}function l(a,b,f){if(a.data(m))return a.data(m).o[b+(f?"":"Class")]}function t(a){return a.charAt(0).toUpperCase()+a.slice(1)}function D(a,b,f,c){if(!c){if(b)a[_callback]("ifToggled");a[_callback]("ifChanged")[_callback]("if"+t(f))}}var m="iCheck",C=m+"-helper",r="radio",k="checked",y="un"+k,n="disabled";_determinate="determinate";_indeterminate="in"+_determinate;_update="update";_type="type";_click="click";_touch="touchbegin.i touchend.i";
|
||||
_add="addClass";_remove="removeClass";_callback="trigger";_label="label";_cursor="cursor";_mobile=/ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i.test(navigator.userAgent);f.fn[m]=function(a,b){var d='input[type="checkbox"], input[type="'+r+'"]',c=f(),g=function(a){a.each(function(){var a=f(this);c=a.is(d)?c.add(a):c.add(a.find(d))})};if(/^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i.test(a))return a=a.toLowerCase(),g(this),c.each(function(){var c=
|
||||
f(this);"destroy"==a?E(c,"ifDestroyed"):A(c,!0,a);f.isFunction(b)&&b()});if("object"!=typeof a&&a)return this;var e=f.extend({checkedClass:k,disabledClass:n,indeterminateClass:_indeterminate,labelHover:!0},a),l=e.handle,v=e.hoverClass||"hover",s=e.focusClass||"focus",t=e.activeClass||"active",B=!!e.labelHover,w=e.labelHoverClass||"hover",p=(""+e.increaseArea).replace("%","")|0;if("checkbox"==l||l==r)d='input[type="'+l+'"]';-50>p&&(p=-50);g(this);return c.each(function(){var a=f(this);E(a);var c=this,
|
||||
b=c.id,g=-p+"%",d=100+2*p+"%",d={position:"absolute",top:g,left:g,display:"block",width:d,height:d,margin:0,padding:0,background:"#fff",border:0,opacity:0},g=_mobile?{position:"absolute",visibility:"hidden"}:p?d:{position:"absolute",opacity:0},l="checkbox"==c[_type]?e.checkboxClass||"icheckbox":e.radioClass||"i"+r,z=f(_label+'[for="'+b+'"]').add(a.closest(_label)),u=!!e.aria,y=m+"-"+Math.random().toString(36).substr(2,6),h='<div class="'+l+'" '+(u?'role="'+c[_type]+'" ':"");u&&z.each(function(){h+=
|
||||
'aria-labelledby="';this.id?h+=this.id:(this.id=y,h+=y);h+='"'});h=a.wrap(h+"/>")[_callback]("ifCreated").parent().append(e.insert);d=f('<ins class="'+C+'"/>').css(d).appendTo(h);a.data(m,{o:e,s:a.attr("style")}).css(g);e.inheritClass&&h[_add](c.className||"");e.inheritID&&b&&h.attr("id",m+"-"+b);"static"==h.css("position")&&h.css("position","relative");A(a,!0,_update);if(z.length)z.on(_click+".i mouseover.i mouseout.i "+_touch,function(b){var d=b[_type],e=f(this);if(!c[n]){if(d==_click){if(f(b.target).is("a"))return;
|
||||
A(a,!1,!0)}else B&&(/ut|nd/.test(d)?(h[_remove](v),e[_remove](w)):(h[_add](v),e[_add](w)));if(_mobile)b.stopPropagation();else return!1}});a.on(_click+".i focus.i blur.i keyup.i keydown.i keypress.i",function(b){var d=b[_type];b=b.keyCode;if(d==_click)return!1;if("keydown"==d&&32==b)return c[_type]==r&&c[k]||(c[k]?q(a,k):x(a,k)),!1;if("keyup"==d&&c[_type]==r)!c[k]&&x(a,k);else if(/us|ur/.test(d))h["blur"==d?_remove:_add](s)});d.on(_click+" mousedown mouseup mouseover mouseout "+_touch,function(b){var d=
|
||||
b[_type],e=/wn|up/.test(d)?t:v;if(!c[n]){if(d==_click)A(a,!1,!0);else{if(/wn|er|in/.test(d))h[_add](e);else h[_remove](e+" "+t);if(z.length&&B&&e==v)z[/ut|nd/.test(d)?_remove:_add](w)}if(_mobile)b.stopPropagation();else return!1}})})}})(window.jQuery||window.Zepto);
|
185
app/assets/javascripts/js/maps/gdp-data.js
Executable file
185
app/assets/javascripts/js/maps/gdp-data.js
Executable file
@ -0,0 +1,185 @@
|
||||
var gdpData = {
|
||||
"AF": 16.63,
|
||||
"AL": 11.58,
|
||||
"DZ": 158.97,
|
||||
"AO": 85.81,
|
||||
"AG": 1.1,
|
||||
"AR": 351.02,
|
||||
"AM": 8.83,
|
||||
"AU": 1219.72,
|
||||
"AT": 366.26,
|
||||
"AZ": 52.17,
|
||||
"BS": 7.54,
|
||||
"BH": 21.73,
|
||||
"BD": 105.4,
|
||||
"BB": 3.96,
|
||||
"BY": 52.89,
|
||||
"BE": 461.33,
|
||||
"BZ": 1.43,
|
||||
"BJ": 6.49,
|
||||
"BT": 1.4,
|
||||
"BO": 19.18,
|
||||
"BA": 16.2,
|
||||
"BW": 12.5,
|
||||
"BR": 2023.53,
|
||||
"BN": 11.96,
|
||||
"BG": 44.84,
|
||||
"BF": 8.67,
|
||||
"BI": 1.47,
|
||||
"KH": 11.36,
|
||||
"CM": 21.88,
|
||||
"CA": 1563.66,
|
||||
"CV": 1.57,
|
||||
"CF": 2.11,
|
||||
"TD": 7.59,
|
||||
"CL": 199.18,
|
||||
"CN": 5745.13,
|
||||
"CO": 283.11,
|
||||
"KM": 0.56,
|
||||
"CD": 12.6,
|
||||
"CG": 11.88,
|
||||
"CR": 35.02,
|
||||
"CI": 22.38,
|
||||
"HR": 59.92,
|
||||
"CY": 22.75,
|
||||
"CZ": 195.23,
|
||||
"DK": 304.56,
|
||||
"DJ": 1.14,
|
||||
"DM": 0.38,
|
||||
"DO": 50.87,
|
||||
"EC": 61.49,
|
||||
"EG": 216.83,
|
||||
"SV": 21.8,
|
||||
"GQ": 14.55,
|
||||
"ER": 2.25,
|
||||
"EE": 19.22,
|
||||
"ET": 30.94,
|
||||
"FJ": 3.15,
|
||||
"FI": 231.98,
|
||||
"FR": 2555.44,
|
||||
"GA": 12.56,
|
||||
"GM": 1.04,
|
||||
"GE": 11.23,
|
||||
"DE": 3305.9,
|
||||
"GH": 18.06,
|
||||
"GR": 305.01,
|
||||
"GD": 0.65,
|
||||
"GT": 40.77,
|
||||
"GN": 4.34,
|
||||
"GW": 0.83,
|
||||
"GY": 2.2,
|
||||
"HT": 6.5,
|
||||
"HN": 15.34,
|
||||
"HK": 226.49,
|
||||
"HU": 132.28,
|
||||
"IS": 12.77,
|
||||
"IN": 1430.02,
|
||||
"ID": 695.06,
|
||||
"IR": 337.9,
|
||||
"IQ": 84.14,
|
||||
"IE": 204.14,
|
||||
"IL": 201.25,
|
||||
"IT": 2036.69,
|
||||
"JM": 13.74,
|
||||
"JP": 5390.9,
|
||||
"JO": 27.13,
|
||||
"KZ": 129.76,
|
||||
"KE": 32.42,
|
||||
"KI": 0.15,
|
||||
"KR": 986.26,
|
||||
"UNDEFINED": 5.73,
|
||||
"KW": 117.32,
|
||||
"KG": 4.44,
|
||||
"LA": 6.34,
|
||||
"LV": 23.39,
|
||||
"LB": 39.15,
|
||||
"LS": 1.8,
|
||||
"LR": 0.98,
|
||||
"LY": 77.91,
|
||||
"LT": 35.73,
|
||||
"LU": 52.43,
|
||||
"MK": 9.58,
|
||||
"MG": 8.33,
|
||||
"MW": 5.04,
|
||||
"MY": 218.95,
|
||||
"MV": 1.43,
|
||||
"ML": 9.08,
|
||||
"MT": 7.8,
|
||||
"MR": 3.49,
|
||||
"MU": 9.43,
|
||||
"MX": 1004.04,
|
||||
"MD": 5.36,
|
||||
"MN": 5.81,
|
||||
"ME": 3.88,
|
||||
"MA": 91.7,
|
||||
"MZ": 10.21,
|
||||
"MM": 35.65,
|
||||
"NA": 11.45,
|
||||
"NP": 15.11,
|
||||
"NL": 770.31,
|
||||
"NZ": 138,
|
||||
"NI": 6.38,
|
||||
"NE": 5.6,
|
||||
"NG": 206.66,
|
||||
"NO": 413.51,
|
||||
"OM": 53.78,
|
||||
"PK": 174.79,
|
||||
"PA": 27.2,
|
||||
"PG": 8.81,
|
||||
"PY": 17.17,
|
||||
"PE": 153.55,
|
||||
"PH": 189.06,
|
||||
"PL": 438.88,
|
||||
"PT": 223.7,
|
||||
"QA": 126.52,
|
||||
"RO": 158.39,
|
||||
"RU": 1476.91,
|
||||
"RW": 5.69,
|
||||
"WS": 0.55,
|
||||
"ST": 0.19,
|
||||
"SA": 434.44,
|
||||
"SN": 12.66,
|
||||
"RS": 38.92,
|
||||
"SC": 0.92,
|
||||
"SL": 1.9,
|
||||
"SG": 217.38,
|
||||
"SK": 86.26,
|
||||
"SI": 46.44,
|
||||
"SB": 0.67,
|
||||
"ZA": 354.41,
|
||||
"ES": 1374.78,
|
||||
"LK": 48.24,
|
||||
"KN": 0.56,
|
||||
"LC": 1,
|
||||
"VC": 0.58,
|
||||
"SD": 65.93,
|
||||
"SR": 3.3,
|
||||
"SZ": 3.17,
|
||||
"SE": 444.59,
|
||||
"CH": 522.44,
|
||||
"SY": 59.63,
|
||||
"TW": 426.98,
|
||||
"TJ": 5.58,
|
||||
"TZ": 22.43,
|
||||
"TH": 312.61,
|
||||
"TL": 0.62,
|
||||
"TG": 3.07,
|
||||
"TO": 0.3,
|
||||
"TT": 21.2,
|
||||
"TN": 43.86,
|
||||
"TR": 729.05,
|
||||
"TM": 0,
|
||||
"UG": 17.12,
|
||||
"UA": 136.56,
|
||||
"AE": 239.65,
|
||||
"GB": 2258.57,
|
||||
"US": 14624.18,
|
||||
"UY": 40.71,
|
||||
"UZ": 37.72,
|
||||
"VU": 0.72,
|
||||
"VE": 285.21,
|
||||
"VN": 101.99,
|
||||
"YE": 30.02,
|
||||
"ZM": 15.69,
|
||||
"ZW": 5.57
|
||||
};
|
2
app/assets/javascripts/js/maps/jquery-jvectormap-2.0.3.min.js
vendored
Executable file
2
app/assets/javascripts/js/maps/jquery-jvectormap-2.0.3.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
1
app/assets/javascripts/js/maps/jquery-jvectormap-us-aea-en.js
vendored
Executable file
1
app/assets/javascripts/js/maps/jquery-jvectormap-us-aea-en.js
vendored
Executable file
File diff suppressed because one or more lines are too long
1
app/assets/javascripts/js/maps/jquery-jvectormap-world-mill-en.js
vendored
Executable file
1
app/assets/javascripts/js/maps/jquery-jvectormap-world-mill-en.js
vendored
Executable file
File diff suppressed because one or more lines are too long
1
app/assets/javascripts/js/maps/us-unemployment.json
Executable file
1
app/assets/javascripts/js/maps/us-unemployment.json
Executable file
File diff suppressed because one or more lines are too long
7
app/assets/javascripts/js/moment/moment.min.js
vendored
Executable file
7
app/assets/javascripts/js/moment/moment.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
2
app/assets/javascripts/js/pace/pace.min.js
vendored
Normal file
2
app/assets/javascripts/js/pace/pace.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
app/assets/javascripts/js/progressbar/bootstrap-progressbar.min.js
vendored
Executable file
2
app/assets/javascripts/js/progressbar/bootstrap-progressbar.min.js
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
/*! bootstrap-progressbar v0.8.4 | Copyright (c) 2012-2014 Stephan Groß | MIT license | http://www.minddust.com */
|
||||
!function(t){"use strict";var e=function(n,a){this.$element=t(n),this.options=t.extend({},e.defaults,a)};e.defaults={transition_delay:300,refresh_speed:50,display_text:"none",use_percentage:!0,percent_format:function(t){return t+"%"},amount_format:function(t,e){return t+" / "+e},update:t.noop,done:t.noop,fail:t.noop},e.prototype.transition=function(){var n=this.$element,a=n.parent(),s=this.$back_text,r=this.$front_text,i=this.options,o=parseInt(n.attr("data-transitiongoal")),h=parseInt(n.attr("aria-valuemin"))||0,d=parseInt(n.attr("aria-valuemax"))||100,f=a.hasClass("vertical"),p=i.update&&"function"==typeof i.update?i.update:e.defaults.update,u=i.done&&"function"==typeof i.done?i.done:e.defaults.done,c=i.fail&&"function"==typeof i.fail?i.fail:e.defaults.fail;if(isNaN(o))return void c("data-transitiongoal not set");var l=Math.round(100*(o-h)/(d-h));if("center"===i.display_text&&!s&&!r){this.$back_text=s=t("<span>").addClass("progressbar-back-text").prependTo(a),this.$front_text=r=t("<span>").addClass("progressbar-front-text").prependTo(n);var g;f?(g=a.css("height"),s.css({height:g,"line-height":g}),r.css({height:g,"line-height":g}),t(window).resize(function(){g=a.css("height"),s.css({height:g,"line-height":g}),r.css({height:g,"line-height":g})})):(g=a.css("width"),r.css({width:g}),t(window).resize(function(){g=a.css("width"),r.css({width:g})}))}setTimeout(function(){var t,e,c,g,_;f?n.css("height",l+"%"):n.css("width",l+"%");var x=setInterval(function(){f?(c=n.height(),g=a.height()):(c=n.width(),g=a.width()),t=Math.round(100*c/g),e=Math.round(h+c/g*(d-h)),t>=l&&(t=l,e=o,u(n),clearInterval(x)),"none"!==i.display_text&&(_=i.use_percentage?i.percent_format(t):i.amount_format(e,d,h),"fill"===i.display_text?n.text(_):"center"===i.display_text&&(s.text(_),r.text(_))),n.attr("aria-valuenow",e),p(t,n)},i.refresh_speed)},i.transition_delay)};var n=t.fn.progressbar;t.fn.progressbar=function(n){return this.each(function(){var a=t(this),s=a.data("bs.progressbar"),r="object"==typeof n&&n;s||a.data("bs.progressbar",s=new e(this,r)),s.transition()})},t.fn.progressbar.Constructor=e,t.fn.progressbar.noConflict=function(){return t.fn.progressbar=n,this}}(window.jQuery);
|
1
app/assets/javascripts/js/skycons/skycons.min.js
vendored
Executable file
1
app/assets/javascripts/js/skycons/skycons.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -1,13 +1,19 @@
|
||||
class PlainpageController < ApplicationController
|
||||
|
||||
before_action :require_login
|
||||
|
||||
def index
|
||||
unless user_signed_in?
|
||||
redirect_to '/users/sign_in'
|
||||
end
|
||||
flash[:success ] = "Success Flash Message: Welcome to GentellelaOnRails"
|
||||
#other alternatives are
|
||||
# flash[:warn ] = "Israel don't quite like warnings"
|
||||
#flash[:danger ] = "Naomi let the dog out!"
|
||||
end
|
||||
|
||||
|
||||
|
||||
# CHECK SIGNED IN FOR USING THE SERVICE
|
||||
def require_login
|
||||
unless user_signed_in?
|
||||
flash[:danger] = "서비스 이용을 위한 로그인이 필요합니다."
|
||||
redirect_to '/users/sign_in' # halts request cycle
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Users::ConfirmationsController < Devise::ConfirmationsController
|
||||
layout "login_pages"
|
||||
# GET /resource/confirmation/new
|
||||
# def new
|
||||
# super
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
layout "login_pages"
|
||||
# You should configure your model like this:
|
||||
# devise :omniauthable, omniauth_providers: [:twitter]
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Users::PasswordsController < Devise::PasswordsController
|
||||
layout "login_pages"
|
||||
# GET /resource/password/new
|
||||
# def new
|
||||
# super
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Users::RegistrationsController < Devise::RegistrationsController
|
||||
layout "login_pages"
|
||||
# before_action :configure_sign_up_params, only: [:create]
|
||||
# before_action :configure_account_update_params, only: [:update]
|
||||
|
||||
@ -8,9 +9,9 @@ class Users::RegistrationsController < Devise::RegistrationsController
|
||||
# end
|
||||
|
||||
# POST /resource
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
def create
|
||||
super
|
||||
end
|
||||
|
||||
# GET /resource/edit
|
||||
# def edit
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Users::UnlocksController < Devise::UnlocksController
|
||||
layout "login_pages"
|
||||
# GET /resource/unlock/new
|
||||
# def new
|
||||
# super
|
||||
|
@ -1,29 +0,0 @@
|
||||
<h2>Sign up</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password %>
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em>
|
||||
<% end %><br />
|
||||
<%= f.password_field :password, autocomplete: "off" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Sign up" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
@ -14,7 +14,9 @@
|
||||
<body class="nav-md">
|
||||
<div class="container body">
|
||||
<% flash.each do |key, value| %>
|
||||
<div align="center" id="flash" class="alert alert-<%= key %>"><%= value %></div>
|
||||
<div align="center" id="flash" class="alert alert-<%= key %>"><%= value %>
|
||||
<a href="#" data-dismiss="alert" class="close">×</a>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "partials/sidenav" %>
|
||||
|
@ -32,7 +32,7 @@
|
||||
<ul class="nav side-menu">
|
||||
<li><a><i class="fa fa-home"></i> Home <span class="fa fa-chevron-down"></span></a>
|
||||
<ul class="nav child_menu" style="display: none">
|
||||
<li><a href="index.html">Dashboard</a>
|
||||
<li><a href="/dashboard">Dashboard</a>
|
||||
</li>
|
||||
<li><a href="index2.html">Dashboard2</a>
|
||||
</li>
|
||||
|
1041
app/views/plainpage/dashboard.html
Executable file
1041
app/views/plainpage/dashboard.html
Executable file
File diff suppressed because it is too large
Load Diff
@ -42,6 +42,16 @@
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
ttt
|
||||
<div class="col-md-6">
|
||||
<div id="reportrange" class="pull-right" style="background: #fff; cursor: pointer; padding: 5px 10px; border: 1px solid #ccc">
|
||||
<i class="glyphicon glyphicon-calendar fa fa-calendar"></i>
|
||||
<span>December 30, 2014 - January 28, 2015</span> <b class="caret"></b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -50,4 +60,81 @@
|
||||
<!-- /page content -->
|
||||
|
||||
<!--Test Page specific JS -->
|
||||
<script> alert ('Test Page specific JS')</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
//alert ('Test Page specific JS')
|
||||
</script>
|
||||
|
||||
<!-- datepicker -->
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
var cb = function(start, end, label) {
|
||||
console.log(start.toISOString(), end.toISOString(), label);
|
||||
$('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
|
||||
//alert("Callback has fired: [" + start.format('MMMM D, YYYY') + " to " + end.format('MMMM D, YYYY') + ", label = " + label + "]");
|
||||
}
|
||||
|
||||
var optionSet1 = {
|
||||
startDate: moment().subtract(29, 'days'),
|
||||
endDate: moment(),
|
||||
minDate: '01/01/2012',
|
||||
maxDate: '12/31/2015',
|
||||
dateLimit: {
|
||||
days: 60
|
||||
},
|
||||
showDropdowns: true,
|
||||
showWeekNumbers: true,
|
||||
timePicker: false,
|
||||
timePickerIncrement: 1,
|
||||
timePicker12Hour: true,
|
||||
ranges: {
|
||||
'Today': [moment(), moment()],
|
||||
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
|
||||
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
|
||||
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
|
||||
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
||||
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
|
||||
},
|
||||
opens: 'left',
|
||||
buttonClasses: ['btn btn-default'],
|
||||
applyClass: 'btn-small btn-primary',
|
||||
cancelClass: 'btn-small',
|
||||
format: 'MM/DD/YYYY',
|
||||
separator: ' to ',
|
||||
locale: {
|
||||
applyLabel: 'Submit',
|
||||
cancelLabel: 'Clear',
|
||||
fromLabel: 'From',
|
||||
toLabel: 'To',
|
||||
customRangeLabel: 'Custom',
|
||||
daysOfWeek: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
|
||||
monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||||
firstDay: 1
|
||||
}
|
||||
};
|
||||
$('#reportrange span').html(moment().subtract(29, 'days').format('MMMM D, YYYY') + ' - ' + moment().format('MMMM D, YYYY'));
|
||||
$('#reportrange').daterangepicker(optionSet1, cb);
|
||||
$('#reportrange').on('show.daterangepicker', function() {
|
||||
console.log("show event fired");
|
||||
});
|
||||
$('#reportrange').on('hide.daterangepicker', function() {
|
||||
console.log("hide event fired");
|
||||
});
|
||||
$('#reportrange').on('apply.daterangepicker', function(ev, picker) {
|
||||
console.log("apply event fired, start/end dates are " + picker.startDate.format('MMMM D, YYYY') + " to " + picker.endDate.format('MMMM D, YYYY'));
|
||||
});
|
||||
$('#reportrange').on('cancel.daterangepicker', function(ev, picker) {
|
||||
console.log("cancel event fired");
|
||||
});
|
||||
$('#options1').click(function() {
|
||||
$('#reportrange').data('daterangepicker').setOptions(optionSet1, cb);
|
||||
});
|
||||
$('#options2').click(function() {
|
||||
$('#reportrange').data('daterangepicker').setOptions(optionSet2, cb);
|
||||
});
|
||||
$('#destroy').click(function() {
|
||||
$('#reportrange').data('daterangepicker').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
@ -13,4 +13,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
<%= render "users/shared/links" %>
|
@ -22,4 +22,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
<%= render "users/shared/links" %>
|
@ -13,4 +13,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
<%= render "users/shared/links" %>
|
145
app/views/users/registrations/new.html.erb
Normal file
145
app/views/users/registrations/new.html.erb
Normal file
@ -0,0 +1,145 @@
|
||||
<%#/devise/sessions/new.html.erb %>
|
||||
|
||||
<div class="">
|
||||
<a class="hiddenanchor" id="tologin"></a>
|
||||
<a class="hiddenanchor" id="toregister"></a>
|
||||
<div id="wrapper">
|
||||
<div id="login" class="animate form">
|
||||
<section class="login_content">
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
||||
|
||||
<h1>Create Account</h1>
|
||||
|
||||
<div align="center" id="flash" class="alert alert-alert">
|
||||
<a href="#" data-dismiss="alert" class="close">×</a>
|
||||
<ul style="text-align: center">
|
||||
<l>
|
||||
<%= devise_error_messages! %>
|
||||
</l>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="text" class="form-control" placeholder="Username" required="" />
|
||||
</div>
|
||||
<div>
|
||||
<%= f.email_field :email, autofocus: true , class: "form-control", placeholder: "Email", required: ""%>
|
||||
</div>
|
||||
<div>
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em>
|
||||
<% end %>
|
||||
<%= f.password_field :password, autocomplete: "off", class: "form-control", placeholder: "Password", required: "" %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control", placeholder: "Password confirmation", required: "" %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.submit "Sign up", :class => "btn btn-default submit" %>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="separator">
|
||||
|
||||
<p class="change_link">Already a member ?
|
||||
<a href="#toregister" class="to_register"> Log in </a>
|
||||
</p>
|
||||
<div class="clearfix"></div>
|
||||
<br />
|
||||
<div>
|
||||
<h1><i class="fa fa-paw" style="font-size: 26px;"></i> Gentelella Alela!</h1>
|
||||
|
||||
<p>©2015 All Rights Reserved. Gentelella Alela! is a Bootstrap 3 template. Privacy and Terms</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
<!-- form -->
|
||||
</section>
|
||||
<!-- content -->
|
||||
</div>
|
||||
|
||||
<div id="register" class="animate form">
|
||||
<section class="login_content">
|
||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
||||
<h1>Login Formzz</h1>
|
||||
<div>
|
||||
<%= f.email_field :email, autofocus: true, :class => "form-control", :placeholder =>"Email", :required => "" %>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<%= f.password_field :password, autofocus: true, :class => "form-control", :placeholder =>"Password", :required => "" %>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<div class="checkbox-inline">
|
||||
<%= f.check_box :remember_me %>
|
||||
<%= f.label :remember_me %>
|
||||
</div>
|
||||
<% end -%>
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<%= f.submit "Log in", :class => "btn btn-default submit"%>
|
||||
|
||||
<a class="reset_pass" href="#">Lost your password?</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="separator">
|
||||
|
||||
<p class="change_link">New to site?
|
||||
<a href="#tologin" class="to_register"> Create Account </a>
|
||||
</p>
|
||||
<div class="clearfix"></div>
|
||||
<br />
|
||||
<div>
|
||||
<h1><i class="fa fa-paw" style="font-size: 26px;"></i> Gentelella Alela!</h1>
|
||||
|
||||
<p>©2015 All Rights Reserved. Gentelella Alela! is a Bootstrap 3 template. Privacy and Terms</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<!-- form -->
|
||||
</section>
|
||||
<!-- content -->
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!--
|
||||
<h2>Sign up</h2>
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password %>
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em>
|
||||
<% end %><br />
|
||||
<%= f.password_field :password, autocomplete: "off" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Sign up" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
-->
|
@ -10,7 +10,7 @@
|
||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
||||
<h1>Login Form</h1>
|
||||
<div>
|
||||
<%= f.email_field :email, autofocus: true, :class => "form-control", :placeholder =>"Username", :required => "" %>
|
||||
<%= f.email_field :email, autofocus: true, :class => "form-control", :placeholder =>"Email", :required => "" %>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
<%= f.submit "Log in", :class => "btn btn-default submit"%>
|
||||
|
||||
<a class="reset_pass" href="#">Lost your password?</a>
|
||||
<a class="reset_pass" href="/users/password/new">Lost your password?</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="separator">
|
||||
@ -44,7 +44,6 @@
|
||||
<br />
|
||||
<div>
|
||||
<h1><i class="fa fa-paw" style="font-size: 26px;"></i> Gentelella Alela!</h1>
|
||||
|
||||
<p>©2015 All Rights Reserved. Gentelella Alela! is a Bootstrap 3 template. Privacy and Terms</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -53,11 +52,12 @@
|
||||
</section>
|
||||
<!-- content -->
|
||||
</div>
|
||||
|
||||
|
||||
<div id="register" class="animate form">
|
||||
<section class="login_content">
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<%= devise_error_messages! %>
|
||||
<h1>Create Account</h1>
|
||||
<div>
|
||||
<input type="text" class="form-control" placeholder="Username" required="" />
|
||||
@ -71,6 +71,10 @@
|
||||
<% end %>
|
||||
<%= f.password_field :password, autocomplete: "off", class: "form-control", placeholder: "Password", required: "" %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control", placeholder: "Password confirmation", required: "" %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.submit "Sign up", :class => "btn btn-default submit" %>
|
||||
</div>
|
||||
@ -84,7 +88,6 @@
|
||||
<br />
|
||||
<div>
|
||||
<h1><i class="fa fa-paw" style="font-size: 26px;"></i> Gentelella Alela!</h1>
|
||||
|
||||
<p>©2015 All Rights Reserved. Gentelella Alela! is a Bootstrap 3 template. Privacy and Terms</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -94,10 +97,13 @@
|
||||
</section>
|
||||
<!-- content -->
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<h2>Log in</h2>
|
||||
|
@ -13,4 +13,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
<%= render "users/shared/links" %>
|
@ -15,7 +15,7 @@ Rails.application.configure do
|
||||
|
||||
# Don't care if the mailer can't send.
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
|
||||
# Print deprecation notices to the Rails logger.
|
||||
config.active_support.deprecation = :log
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
Rails.application.routes.draw do
|
||||
devise_for :users, controllers: { sessions: 'users/sessions' }
|
||||
devise_for :users, controllers: { sessions: 'users/sessions' , registrations: 'users/registrations', confirmations: 'users/confirmations', passwords: 'users/passwords', unlocks: 'users/unlocks'}
|
||||
# The priority is based upon order of creation: first created -> highest priority.
|
||||
# See how all your routes lay out with "rake routes".
|
||||
|
||||
# You can have the root of your site routed with "root"
|
||||
root 'plainpage#index'
|
||||
|
||||
get 'index' => 'plainpage#index'
|
||||
get 'dashboard' => 'plainpage#dashboard'
|
||||
# Example of regular route:
|
||||
# get 'products/:id' => 'catalog#view'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user