first commit

This commit is contained in:
dev-chiefworks
2022-05-31 16:21:53 -04:00
commit f76abffdcd
5978 changed files with 1078901 additions and 0 deletions
+7
View File
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
/*!
* chartjs-adapter-luxon v0.1.1
* https://www.chartjs.org
* (c) 2019 Chart.js Contributors
* Released under the MIT license
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e=e||self).Chart,e.luxon)}(this,function(e,t){"use strict";var n={datetime:"MMM d, yyyy, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"ha",day:"MMM d",week:"DD",month:"MMM yyyy",quarter:"'Q'q - yyyy",year:"yyyy"};function r(e){return t.DateTime.fromMillis(e)}e._adapters._date.override({_id:"luxon",formats:function(){return n},parse:function(n,f){if(e.helpers.isNullOrUndef(n))return null;var a=typeof n;return"number"===a?n=r(n):"string"===a?n="string"==typeof f?t.DateTime.fromFormat(n,f):t.DateTime.fromISO(n):"object"===a?n=t.DateTime.fromObject(n):n instanceof Date&&(n=t.DateTime.fromJSDate(n)),n.isValid?n.valueOf():null},format:function(e,t){return r(e).toFormat(t)},add:function(e,t,n){var f={};return f[n]=t,r(e).plus(f).valueOf()},diff:function(e,t,n){return r(e).diff(r(t)).as(n).valueOf()},startOf:function(e,t,n){return"isoWeek"===t?r(e).isoWeekday(n).valueOf():t?r(e).startOf(t).valueOf():e},endOf:function(e,t){return r(e).endOf(t).valueOf()}})});
+462
View File
@@ -0,0 +1,462 @@
/*!
* @license
* chartjs-chart-financial
* http://chartjs.org/
* Version: 0.1.0
*
* Copyright 2019 Chart.js Contributors
* Released under the MIT license
* https://github.com/chartjs/chartjs-chart-financial/blob/master/LICENSE.md
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chart.js')) :
typeof define === 'function' && define.amd ? define(['chart.js'], factory) :
(global = global || self, factory(global.Chart));
}(this, function (Chart) { 'use strict';
Chart = Chart && Chart.hasOwnProperty('default') ? Chart['default'] : Chart;
var helpers = Chart.helpers;
var defaultConfig = {
position: 'left',
ticks: {
callback: Chart.Ticks.formatters.linear
}
};
var FinancialLinearScale = Chart.scaleService.getScaleConstructor('linear').extend({
determineDataLimits: function() {
var me = this;
var chart = me.chart;
var data = chart.data;
var datasets = data.datasets;
var isHorizontal = me.isHorizontal();
function IDMatches(meta) {
return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
}
// First Calculate the range
me.min = null;
me.max = null;
// Regular charts use x, y values
// For the financial chart we have rawValue.h (hi) and rawValue.l (low) for each point
helpers.each(datasets, function(dataset, datasetIndex) {
var meta = chart.getDatasetMeta(datasetIndex);
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
helpers.each(dataset.data, function(rawValue) {
var high = rawValue.h;
var low = rawValue.l;
if (me.min === null) {
me.min = low;
} else if (low < me.min) {
me.min = low;
}
if (me.max === null) {
me.max = high;
} else if (high > me.max) {
me.max = high;
}
});
}
});
// Add whitespace around bars. Axis shouldn't go exactly from min to max
var space = (me.max - me.min) * 0.05;
me.min -= space;
me.max += space;
// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
this.handleTickRangeOptions();
}
});
Chart.scaleService.registerScaleType('financialLinear', FinancialLinearScale, defaultConfig);
var helpers$1 = Chart.helpers;
Chart.defaults.financial = {
label: '',
hover: {
mode: 'label'
},
scales: {
xAxes: [{
type: 'time',
distribution: 'series',
categoryPercentage: 0.8,
barPercentage: 0.9,
ticks: {
source: 'data'
}
}],
yAxes: [{
type: 'financialLinear'
}]
},
tooltips: {
intersect: false,
mode: 'index',
callbacks: {
label: function(tooltipItem, data) {
var p = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].p;
var o = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].o;
var h = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].h;
var l = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].l;
var c = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].c;
var dataset = data.datasets[tooltipItem.datasetIndex];
var precision = helpers$1.valueOrDefault(dataset.precision, 2);
precision = Math.max(0, Math.min(100, precision));
o = o.toFixed(precision);
h = h.toFixed(precision);
l = l.toFixed(precision);
c = c.toFixed(precision);
return (p!=''?(p+'\r'):'') + ' O: ' + o + ' H: ' + h + ' L: ' + l + ' C: ' + c;
}
}
}
};
/**
* This class is based off controller.bar.js from the upstream Chart.js library
*/
var FinancialController = Chart.controllers.bar.extend({
dataElementType: Chart.elements.Financial,
/**
* @private
*/
_updateElementGeometry: function(element, index, reset) {
var me = this;
var model = element._model;
var vscale = me._getValueScale();
var base = vscale.getBasePixel();
var horizontal = vscale.isHorizontal();
var ruler = me._ruler || me.getRuler();
var vpixels = me.calculateBarValuePixels(me.index, index);
var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
var chart = me.chart;
var datasets = chart.data.datasets;
var indexData = datasets[me.index].data[index];
model.horizontal = horizontal;
model.base = reset ? base : vpixels.base;
model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
model.height = horizontal ? ipixels.size : undefined;
model.width = horizontal ? undefined : ipixels.size;
model.candleOpen = vscale.getPixelForValue(Number(indexData.o));
model.candleHigh = vscale.getPixelForValue(Number(indexData.h));
model.candleLow = vscale.getPixelForValue(Number(indexData.l));
model.candleClose = vscale.getPixelForValue(Number(indexData.c));
},
draw: function() {
var ctx = this.chart.chart.ctx;
var elements = this.getMeta().data;
var dataset = this.getDataset();
var ilen = elements.length;
var i = 0;
var d;
Chart.canvasHelpers.clipArea(ctx, this.chart.chartArea);
for (; i < ilen; ++i) {
d = dataset.data[i].o;
if (d !== null && d !== undefined && !isNaN(d)) {
elements[i].draw();
}
}
Chart.canvasHelpers.unclipArea(ctx);
},
});
var helpers$2 = Chart.helpers;
var globalOpts = Chart.defaults.global;
globalOpts.elements.financial = {
color: {
up: 'rgba(80, 160, 115, 1)',
down: 'rgba(215, 85, 65, 1)',
unchanged: 'rgba(90, 90, 90, 1)',
}
};
function isVertical(bar) {
return bar._view.width !== undefined;
}
/**
* Helper function to get the bounds of the candle
* @private
* @param bar {Chart.Element.financial} the bar
* @return {Bounds} bounds of the bar
*/
function getBarBounds(candle) {
var vm = candle._view;
var x1, x2, y1, y2;
var halfWidth = vm.width / 2;
x1 = vm.x - halfWidth;
x2 = vm.x + halfWidth;
y1 = vm.candleHigh;
y2 = vm.candleLow;
return {
left: x1,
top: y1,
right: x2,
bottom: y2
};
}
var FinancialElement = Chart.Element.extend({
height: function() {
var vm = this._view;
return vm.base - vm.y;
},
inRange: function(mouseX, mouseY) {
var inRange = false;
if (this._view) {
var bounds = getBarBounds(this);
inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
}
return inRange;
},
inLabelRange: function(mouseX, mouseY) {
var me = this;
if (!me._view) {
return false;
}
var inRange = false;
var bounds = getBarBounds(me);
if (isVertical(me)) {
inRange = mouseX >= bounds.left && mouseX <= bounds.right;
} else {
inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
}
return inRange;
},
inXRange: function(mouseX) {
var bounds = getBarBounds(this);
return mouseX >= bounds.left && mouseX <= bounds.right;
},
inYRange: function(mouseY) {
var bounds = getBarBounds(this);
return mouseY >= bounds.top && mouseY <= bounds.bottom;
},
getCenterPoint: function() {
var vm = this._view;
return {
x: vm.x,
y: (vm.candleHigh + vm.candleLow) / 2
};
},
getArea: function() {
var vm = this._view;
return vm.width * Math.abs(vm.y - vm.base);
},
tooltipPosition: function() {
var vm = this._view;
return {
x: vm.x,
y: (vm.candleOpen + vm.candleClose) / 2
};
},
hasValue: function() {
var model = this._model;
return helpers$2.isNumber(model.x) &&
helpers$2.isNumber(model.candleOpen) &&
helpers$2.isNumber(model.candleHigh) &&
helpers$2.isNumber(model.candleLow) &&
helpers$2.isNumber(model.candleClose);
}
});
var helpers$3 = Chart.helpers;
var globalOpts$1 = Chart.defaults.global;
globalOpts$1.elements.candlestick = helpers$3.merge({}, [globalOpts$1.elements.financial, {
borderColor: globalOpts$1.elements.financial.color.unchanged,
borderWidth: 1,
}]);
var CandlestickElement = FinancialElement.extend({
draw: function() {
var ctx = this._chart.ctx;
var vm = this._view;
var x = vm.x;
var o = vm.candleOpen;
var h = vm.candleHigh;
var l = vm.candleLow;
var c = vm.candleClose;
var borderColors = vm.borderColor;
if (typeof borderColors === 'string') {
borderColors = {
up: borderColors,
down: borderColors,
unchanged: borderColors
};
}
var borderColor;
if (c < o) {
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.up : undefined, globalOpts$1.elements.candlestick.borderColor);
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.up : undefined, globalOpts$1.elements.candlestick.color.up);
} else if (c > o) {
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.down : undefined, globalOpts$1.elements.candlestick.borderColor);
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.down : undefined, globalOpts$1.elements.candlestick.color.down);
} else {
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.unchanged : undefined, globalOpts$1.elements.candlestick.borderColor);
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.unchanged : undefined, globalOpts$1.elements.candlestick.color.unchanged);
}
ctx.lineWidth = helpers$3.getValueOrDefault(vm.borderWidth, globalOpts$1.elements.candlestick.borderWidth);
ctx.strokeStyle = helpers$3.getValueOrDefault(borderColor, globalOpts$1.elements.candlestick.borderColor);
ctx.beginPath();
ctx.moveTo(x, h);
ctx.lineTo(x, Math.min(o, c));
ctx.moveTo(x, l);
ctx.lineTo(x, Math.max(o, c));
ctx.stroke();
ctx.fillRect(x - vm.width / 2, c, vm.width, o - c);
ctx.strokeRect(x - vm.width / 2, c, vm.width, o - c);
ctx.closePath();
},
});
Chart.defaults.candlestick = Chart.helpers.merge({}, Chart.defaults.financial);
var CandlestickController = Chart.controllers.candlestick = FinancialController.extend({
dataElementType: CandlestickElement,
updateElement: function(element, index, reset) {
var me = this;
var meta = me.getMeta();
var dataset = me.getDataset();
element._xScale = me.getScaleForId(meta.xAxisID);
element._yScale = me.getScaleForId(meta.yAxisID);
element._datasetIndex = me.index;
element._index = index;
element._model = {
datasetLabel: dataset.label || '',
// label: '', // to get label value please use dataset.data[index].label
// Appearance
color: dataset.color,
borderColor: dataset.borderColor,
borderWidth: dataset.borderWidth,
};
me._updateElementGeometry(element, index, reset);
element.pivot();
},
});
var helpers$4 = Chart.helpers;
var globalOpts$2 = Chart.defaults.global;
globalOpts$2.elements.ohlc = helpers$4.merge({}, [globalOpts$2.elements.financial, {
lineWidth: 2,
armLength: null,
armLengthRatio: 0.8,
}]);
var OhlcElement = FinancialElement.extend({
draw: function() {
var ctx = this._chart.ctx;
var vm = this._view;
var x = vm.x;
var o = vm.candleOpen;
var h = vm.candleHigh;
var l = vm.candleLow;
var c = vm.candleClose;
var armLength = helpers$4.getValueOrDefault(vm.armLength, globalOpts$2.elements.ohlc.armLength);
var armLengthRatio = helpers$4.getValueOrDefault(vm.armLengthRatio, globalOpts$2.elements.ohlc.armLengthRatio);
if (armLength === null) {
// The width of an ohlc is affected by barPercentage and categoryPercentage
// This behavior is caused by extending controller.financial, which extends controller.bar
// barPercentage and categoryPercentage are now set to 1.0 (see controller.ohlc)
// and armLengthRatio is multipled by 0.5,
// so that when armLengthRatio=1.0, the arms from neighbour ohcl touch,
// and when armLengthRatio=0.0, ohcl are just vertical lines.
armLength = vm.width * armLengthRatio * 0.5;
}
if (c < o) {
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.up : undefined, globalOpts$2.elements.ohlc.color.up);
} else if (c > o) {
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.down : undefined, globalOpts$2.elements.ohlc.color.down);
} else {
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.unchanged : undefined, globalOpts$2.elements.ohlc.color.unchanged);
}
ctx.lineWidth = helpers$4.getValueOrDefault(vm.lineWidth, globalOpts$2.elements.ohlc.lineWidth);
ctx.beginPath();
ctx.moveTo(x, h);
ctx.lineTo(x, l);
ctx.moveTo(x - armLength, o);
ctx.lineTo(x, o);
ctx.moveTo(x + armLength, c);
ctx.lineTo(x, c);
ctx.stroke();
},
});
Chart.defaults.ohlc = Chart.helpers.merge({}, Chart.defaults.financial);
Chart.defaults.ohlc.scales.xAxes[0].barPercentage = 1.0;
Chart.defaults.ohlc.scales.xAxes[0].categoryPercentage = 1.0;
var OhlcController = Chart.controllers.ohlc = FinancialController.extend({
dataElementType: OhlcElement,
updateElement: function(element, index, reset) {
var me = this;
var meta = me.getMeta();
var dataset = me.getDataset();
element._xScale = me.getScaleForId(meta.xAxisID);
element._yScale = me.getScaleForId(meta.yAxisID);
element._datasetIndex = me.index;
element._index = index;
element._model = {
datasetLabel: dataset.label || '',
lineWidth: dataset.lineWidth,
armLength: dataset.armLength,
armLengthRatio: dataset.armLengthRatio,
color: dataset.color,
};
me._updateElementGeometry(element, index, reset);
element.pivot();
},
});
}));
+889
View File
@@ -0,0 +1,889 @@
/*!
* jQuery Popup Overlay
*
* @requires jQuery v1.7.1+
* @link https://vast-engineering.github.com/jquery-popup-overlay/
*/
;(function ($) { /* eslint-disable-line */
var $window = $(window);
var options = {};
var zindexvalues = [];
var lastclicked = [];
var scrollbarwidth;
var bodymarginright = null;
var opensuffix = '_open';
var closesuffix = '_close';
var visiblePopupsArray = [];
var transitionsupport = null;
var opentimer;
var iOS = /(iPad|iPhone|iPod)/.test(navigator.userAgent);
var focusableElementsString = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
var methods = {
_init: function (el) {
var $el = $(el);
var options = $el.data('popupoptions');
lastclicked[el.id] = false;
zindexvalues[el.id] = 0;
if (!$el.data('popup-initialized')) {
$el.attr('data-popup-initialized', 'true');
methods._initonce(el);
}
if (options.autoopen) {
setTimeout(function() {
methods.show(el, 0);
}, 0);
}
},
_initonce: function (el) {
var $el = $(el);
var $body = $('body');
var $wrapper;
var options = $el.data('popupoptions');
bodymarginright = parseInt($body.css('margin-right'), 10);
transitionsupport = document.body.style.webkitTransition !== undefined ||
document.body.style.MozTransition !== undefined ||
document.body.style.msTransition !== undefined ||
document.body.style.OTransition !== undefined ||
document.body.style.transition !== undefined;
if (options.scrolllock) {
// Calculate the browser's scrollbar width dynamically
var parent;
var child;
if (typeof scrollbarwidth === 'undefined') {
parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');
child = parent.children();
scrollbarwidth = child.innerWidth() - child.height(99).innerWidth();
parent.remove();
}
}
if (!$el.attr('id')) {
$el.attr('id', 'j-popup-' + parseInt((Math.random() * 100000000), 10));
}
$el.addClass('popup_content');
if ((options.background) && (!$('#' + el.id + '_background').length)) {
$body.append('<div id="' + el.id + '_background" class="popup_background"></div>');
var $background = $('#' + el.id + '_background');
$background.css({
opacity: 0,
visibility: 'hidden',
backgroundColor: options.color,
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0
});
if (options.setzindex && !options.autozindex) {
$background.css('z-index', '100000');
}
if (options.transition) {
$background.css('transition', options.transition);
}
}
$body.append(el);
$el.wrap('<div id="' + el.id + '_wrapper" class="popup_wrapper" />');
$wrapper = $('#' + el.id + '_wrapper');
$wrapper.css({
opacity: 0,
visibility: 'hidden',
position: 'absolute'
});
// Make div clickable in iOS
if (iOS) {
$background = $('#' + el.id + '_background');
$background.css('cursor', 'pointer');
$(options.pagecontainer).css('cursor', 'pointer');
}
if (options.type == 'overlay' && !options.absolute && options.background) {
$wrapper.css('overflow','auto');
$wrapper[0].style.WebkitOverflowScrolling = 'touch'; // for smooth scrolling in overflow:auto divs in iOS
}
$el.css({
opacity: 0,
visibility: 'hidden',
'pointer-events': 'auto', // reset pointer events back to default for a child element
display: 'inline-block'
});
if (options.setzindex && !options.autozindex) {
$wrapper.css('z-index', '100001');
}
if (!options.outline) {
$el.css('outline', 'none');
}
if (options.transition) {
$el.css('transition', options.transition);
$wrapper.css('transition', options.transition);
}
// Hide popup content from screen readers initially
$el.attr('aria-hidden', true);
if (options.type == 'overlay') {
$el.css({
textAlign: 'left',
position: 'relative',
verticalAlign: 'middle'
});
$wrapper.css({
position: 'fixed',
width: '100%',
height: '100%',
top: 0,
left: 0,
textAlign: 'center'
});
// CSS vertical align helper
$wrapper.append('<div class="popup_align" />');
$('.popup_align').css({
display: 'inline-block',
verticalAlign: 'middle',
height: '100%'
});
}
// Add WAI ARIA role to announce dialog to screen readers
$el.attr('role', 'dialog');
var openelement = (options.openelement) ? options.openelement : ('.' + el.id + opensuffix);
$(openelement).each(function (i, item) {
$(item).attr('data-popup-ordinal', i);
if (!item.id) {
$(item).attr('id', 'open_' + parseInt((Math.random() * 100000000), 10));
}
});
// Set aria-labelledby (if aria-label or aria-labelledby is not set in html)
if (!($el.attr('aria-labelledby') || $el.attr('aria-label'))) {
$el.attr('aria-labelledby', $(openelement).attr('id'));
}
// Show and hide tooltips on hover
if(options.action == 'hover'){
options.keepfocus = false;
// Handler: mouseenter, focusin
$(openelement).on('mouseenter', function () {
methods.show(el, $(this).data('popup-ordinal'));
});
// Handler: mouseleave, focusout
$(openelement).on('mouseleave', function () {
methods.hide(el);
});
} else {
// Handler: Show popup when clicked on `open` element
$(document).on('click.jqp', openelement, function (event) {
event.preventDefault();
var ord = $(this).data('popup-ordinal');
setTimeout(function() { // setTimeout is to allow `close` method to finish (for issues with multiple tooltips)
methods.show(el, ord);
}, 0);
});
}
if (options.closebutton) {
methods.addclosebutton(el);
}
if (options.detach) {
$el.detach();
} else {
$el.hide();
}
},
/**
* Show method
*
* @param {object} el - popup instance DOM node
* @param {number} ordinal - order number of an `open` element
*/
show: function (el, ordinal) {
var $el = $(el);
if ($el.data('popup-visible')) return;
// Initialize if not initialized. Required for: $('#popup').popup('show')
if (!$el.data('popup-initialized')) {
methods._init(el);
}
$el.attr('data-popup-initialized', 'true');
var $body = $('body');
var options = $el.data('popupoptions');
var $wrapper = $('#' + el.id + '_wrapper');
var $background = $('#' + el.id + '_background');
// `beforeopen` callback event
callback(el, ordinal, options.beforeopen);
// Remember last clicked place
lastclicked[el.id] = ordinal;
// Add popup id to visiblePopupsArray
setTimeout(function() {
visiblePopupsArray.push(el.id);
}, 0);
// Calculating maximum z-index
if (options.autozindex) {
var elements = document.getElementsByTagName('*');
var len = elements.length;
var maxzindex = 0;
for(var i=0; i<len; i++){
var elementzindex = $(elements[i]).css('z-index');
if(elementzindex !== 'auto'){
elementzindex = parseInt(elementzindex, 10);
if(maxzindex < elementzindex){
maxzindex = elementzindex;
}
}
}
zindexvalues[el.id] = maxzindex;
// Add z-index to the background
if (options.background) {
if (zindexvalues[el.id] >= 0) {
$('#' + el.id + '_background').css({
zIndex: (zindexvalues[el.id] + 1)
});
}
}
// Add z-index to the wrapper
if (zindexvalues[el.id] >= 0) {
$wrapper.css({
zIndex: (zindexvalues[el.id] + 2)
});
}
}
if (options.detach) {
$wrapper.prepend(el);
$el.show();
} else {
$el.show();
}
opentimer = setTimeout(function() {
$wrapper.css({
visibility: 'visible',
opacity: 1
});
$('html').addClass('popup_visible').addClass('popup_visible_' + el.id);
$wrapper.addClass('popup_wrapper_visible');
}, 20); // 20ms required for opening animation to occur in FF
// Disable background layer scrolling when popup is opened
if (options.scrolllock) {
$body.css('overflow', 'hidden');
if ($body.height() > $window.height()) {
$body.css('margin-right', bodymarginright + scrollbarwidth);
}
}
$el.css({
'visibility': 'visible',
'opacity': 1
});
// Show background
if (options.background) {
$background.css({
'visibility': 'visible',
'opacity': options.opacity
});
// Fix IE8 issue with background not appearing
setTimeout(function() {
$background.css({
'opacity': options.opacity
});
}, 0);
}
$el.data('popup-visible', true);
// Position popup
methods.reposition(el, ordinal);
// Remember which element had focus before opening a popup
$el.data('focusedelementbeforepopup', document.activeElement);
// Make holder div programatically focusable with tabindex:-1 (tabindex:0 is keyboard focusable)
$el.attr('tabindex', -1);
// Focus the popup or user specified element.
// Initial timeout of 50ms is set to give some time to popup to show after clicking on
// `open` element, and after animation is complete to prevent background scrolling.
setTimeout(function() {
if (options.focuselement === 'closebutton') { // e.g. focuselement:'closebutton'
$('#' + el.id + ' .' + el.id + closesuffix + ':first').focus();
} else if (options.focuselement) { // e.g. focuselement:'#my-close-button'
$(options.focuselement).focus();
} else if (options.focuselement === true || options.keepfocus) { // e.g. focuselement:true OR keepfocus:true
$el.focus();
}
}, options.focusdelay);
// Hide main content from screen readers
if (options.keepfocus) {
$(options.pagecontainer).attr('aria-hidden', true);
}
// Reveal popup content to screen readers
$el.attr('aria-hidden', false);
callback(el, ordinal, options.onopen);
if (transitionsupport) {
$wrapper.one('transitionend', function() {
callback(el, ordinal, options.opentransitionend);
});
} else {
callback(el, ordinal, options.opentransitionend);
}
// Handler: Reposition tooltip when window is resized
if (options.type == 'tooltip') {
$(window).on('resize.' + el.id, function () {
methods.reposition(el, ordinal);
});
}
},
/**
* Hide method
*
* @param object el - popup instance DOM node
* @param boolean outerClick - click on the outer content below popup
*/
hide: function (el, outerClick) {
// Get index of popup ID inside of visiblePopupsArray
var popupIdIndex = $.inArray(el.id, visiblePopupsArray);
// If popup is not opened, ignore the rest of the function
if (popupIdIndex === -1) {
return;
}
if(opentimer) clearTimeout(opentimer);
var $body = $('body');
var $el = $(el);
var options = $el.data('popupoptions');
var $wrapper = $('#' + el.id + '_wrapper');
var $background = $('#' + el.id + '_background');
$el.data('popup-visible', false);
if (visiblePopupsArray.length === 1) {
$('html').removeClass('popup_visible').removeClass('popup_visible_' + el.id);
} else {
if($('html').hasClass('popup_visible_' + el.id)) {
$('html').removeClass('popup_visible_' + el.id);
}
}
// Remove popup from the visiblePopupsArray
visiblePopupsArray.splice(popupIdIndex, 1);
if($wrapper.hasClass('popup_wrapper_visible')) {
$wrapper.removeClass('popup_wrapper_visible');
}
// Focus back on saved element
if (options.keepfocus && !outerClick) {
setTimeout(function() {
if ($($el.data('focusedelementbeforepopup')).is(':visible')) {
$el.data('focusedelementbeforepopup').focus();
}
}, 0);
}
// Hide popup
$wrapper.css({
'visibility': 'hidden',
'opacity': 0
});
$el.css({
'visibility': 'hidden',
'opacity': 0
});
// Hide background
if (options.background) {
$background.css({
'visibility': 'hidden',
'opacity': 0
});
}
// Reveal main content to screen readers
$(options.pagecontainer).attr('aria-hidden', false);
// Hide popup content from screen readers
$el.attr('aria-hidden', true);
// `onclose` callback event
callback(el, lastclicked[el.id], options.onclose);
if (transitionsupport && $el.css('transition-duration') !== '0s') {
$el.one('transitionend', function() {
if (!($el.data('popup-visible'))) {
if (options.detach) {
$el.detach();
} else {
$el.hide();
}
}
// Re-enable scrolling of background layer, if needed
if (options.scrolllock) {
setTimeout(function() {
if ($.grep(visiblePopupsArray, function(eid) { return $("#"+eid).data('popupoptions').scrolllock }).length) {
// Some "scolllock=true" popup is currently visible, leave scrolling disabled
return;
}
$body.css({
overflow: 'visible',
'margin-right': bodymarginright
});
}, 10); // 10ms added for CSS transition in Firefox which doesn't like overflow:auto
}
callback(el, lastclicked[el.id], options.closetransitionend);
});
} else {
if (options.detach) {
$el.detach();
} else {
$el.hide();
}
// Re-enable scrolling of background layer, if needed
if (options.scrolllock) {
setTimeout(function() {
if ($.grep(visiblePopupsArray, function(eid) { return $("#"+eid).data('popupoptions').scrolllock }).length) {
// Some "scrolllock=true" popup is currently visible, leave scrolling disabled
return;
}
$body.css({
overflow: 'visible',
'margin-right': bodymarginright
});
}, 10); // 10ms added for CSS transition in Firefox which doesn't like overflow:auto
}
callback(el, lastclicked[el.id], options.closetransitionend);
}
if (options.type == 'tooltip') {
$(window).off('resize.' + el.id);
}
},
/**
* Toggle method
*
* @param {object} el - popup instance DOM node
* @param {number} ordinal - order number of an `open` element
*/
toggle: function (el, ordinal) {
if ($(el).data('popup-visible')) {
methods.hide(el);
} else {
setTimeout(function() {
methods.show(el, ordinal);
}, 0);
}
},
/**
* Reposition method
*
* @param {object} el - popup instance DOM node
* @param {number} ordinal - order number of an `open` element
*/
reposition: function (el, ordinal) {
var $el = $(el);
var options = $el.data('popupoptions');
var $wrapper = $('#' + el.id + '_wrapper');
ordinal = ordinal || 0;
// Tooltip type
if (options.type == 'tooltip') {
// TODO: this static assignments should probably be moved to init method
$wrapper.css({
'position': 'absolute'
});
var $tooltipanchor;
if (options.tooltipanchor) {
$tooltipanchor = $(options.tooltipanchor);
} else if (options.openelement) {
$tooltipanchor = $(options.openelement).filter('[data-popup-ordinal="' + ordinal + '"]');
} else {
$tooltipanchor = $('.' + el.id + opensuffix + '[data-popup-ordinal="' + ordinal + '"]');
}
var linkOffset = $tooltipanchor.offset() || { left: 0, top: 0 };
// Horizontal position for tooltip
if (options.horizontal == 'right') {
$wrapper.css('left', linkOffset.left + $tooltipanchor.outerWidth() + options.offsetleft);
} else if (options.horizontal == 'leftedge') {
$wrapper.css('left', linkOffset.left + options.offsetleft);
} else if (options.horizontal == 'left') {
$wrapper.css('right', $window.width() - linkOffset.left - options.offsetleft);
} else if (options.horizontal == 'rightedge') {
$wrapper.css('right', $window.width() - linkOffset.left - $tooltipanchor.outerWidth() - options.offsetleft);
} else {
$wrapper.css('left', linkOffset.left + ($tooltipanchor.outerWidth() / 2) - ($el.outerWidth() / 2) - parseFloat($el.css('marginLeft')) + options.offsetleft);
}
// Vertical position for tooltip
if (options.vertical == 'bottom') {
$wrapper.css('top', linkOffset.top + $tooltipanchor.outerHeight() + options.offsettop);
} else if (options.vertical == 'bottomedge') {
$wrapper.css('top', linkOffset.top + $tooltipanchor.outerHeight() - $el.outerHeight() + options.offsettop);
} else if (options.vertical == 'top') {
$wrapper.css('bottom', $window.height() - linkOffset.top - options.offsettop);
} else if (options.vertical == 'topedge') {
$wrapper.css('bottom', $window.height() - linkOffset.top - $el.outerHeight() - options.offsettop);
} else {
$wrapper.css('top', linkOffset.top + ($tooltipanchor.outerHeight() / 2) - ($el.outerHeight() / 2) - parseFloat($el.css('marginTop')) + options.offsettop);
}
// Overlay type
} else if (options.type == 'overlay') {
// TODO all static assignments in this block should probably be moved to init method
// Horizontal position for overlay
if (options.horizontal) {
$wrapper.css('text-align', options.horizontal);
} else {
$wrapper.css('text-align', 'center');
}
// Vertical position for overlay
if (options.vertical) {
$el.css('vertical-align', options.vertical);
} else {
$el.css('vertical-align', 'middle');
}
if (options.absolute) {
$wrapper.css({
position: 'absolute',
top: window.scrollY
});
}
if (!options.background) {
$wrapper.css({ 'pointer-events': 'none' });
// If popup doesnt fit the viewport, and if background doesn't exist, add scrollbar to popup div instead of wrapper
if (!options.absolute && !isInViewport(el)) {
$el.css('overflow', 'auto');
$el[0].style.WebkitOverflowScrolling = 'touch'; // for smooth scrolling in overflow:auto divs in iOS
$el.css('max-height', 'calc(100% - ' + $el.css('margin-top') + ' - ' + $el.css('margin-bottom') + ')');
}
}
}
},
/**
* Add-close-button method
*
* @param {object} el - popup instance DOM node
*/
addclosebutton: function (el) {
var genericCloseButton;
if ($(el).data('popupoptions').closebuttonmarkup) {
genericCloseButton = $(options.closebuttonmarkup).addClass(el.id + '_close');
} else {
genericCloseButton = '<button class="popup_close ' + el.id + '_close" title="Close" aria-label="Close"><span aria-hidden="true">×</span></button>';
}
if ($(el).data('popup-initialized')){
$(el).append(genericCloseButton);
}
}
};
/**
* Callback event calls
*
* @param {object} el - popup instance DOM node
* @param {number} ordinal - order number of an `open` element
* @param {function} func - callback function
*/
var callback = function (el, ordinal, func) {
var options = $(el).data('popupoptions');
var openelement;
var elementclicked;
if (typeof options === 'undefined') return;
openelement = options.openelement ? options.openelement : ('.' + el.id + opensuffix);
elementclicked = $(openelement + '[data-popup-ordinal="' + ordinal + '"]');
if (typeof func == 'function') {
func.call($(el), el, elementclicked);
}
};
/**
* Check if element is fully in viewport
*
* @param {object} el - popup instance DOM node
*/
var isInViewport = function (el) {
var bounding = el.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
// Hide popup if ESC key is pressed
$(document).on('keydown', function (event) {
if(visiblePopupsArray.length) {
var elementId = visiblePopupsArray[visiblePopupsArray.length - 1];
var el = document.getElementById(elementId);
if ($(el).data('popupoptions').escape && event.keyCode == 27) {
methods.hide(el);
}
}
});
// Hide popup on click
$(document).on('click', function (event) {
if(visiblePopupsArray.length) {
var elementId = visiblePopupsArray[visiblePopupsArray.length - 1];
var el = document.getElementById(elementId);
var closeButton = ($(el).data('popupoptions').closeelement) ? $(el).data('popupoptions').closeelement : ('.' + el.id + closesuffix);
// If Close button clicked
if ($(event.target).closest(closeButton).length) {
event.preventDefault();
methods.hide(el);
}
// If clicked outside of popup
if ($(el).data('popupoptions')
&& $(el).data('popupoptions').blur
&& !$(event.target).closest($(el).data('popupoptions').blurignore).length
&& !$(event.target).closest('#' + elementId).length
&& event.which !== 2
&& $(event.target).is(':visible')) {
if ($(el).data('popupoptions').background) {
// If clicked on popup cover
methods.hide(el);
// Older iOS/Safari will trigger a click on the elements below the cover,
// when tapping on the cover, so the default action needs to be prevented.
event.preventDefault();
} else {
// If clicked on outer content
methods.hide(el, true);
}
}
}
});
// Keep keyboard focus inside of popup
$(document).on('keydown', function(event) {
if(visiblePopupsArray.length && event.which == 9) {
// If tab or shift-tab pressed
var elementId = visiblePopupsArray[visiblePopupsArray.length - 1];
var el = document.getElementById(elementId);
var options = $(el).data('popupoptions');
// If the last opened popup doesn't have `keepfocus` option, ignore the rest and don't lock the focus inside of popup.
if (!options.keepfocus) {
return;
}
// Get list of all children elements in given object
var popupItems = $(el).find('*');
// Get list of focusable items
var focusableItems = popupItems.filter(focusableElementsString).filter(':visible');
// Get currently focused item
var focusedItem = $(':focus');
// Get the number of focusable items
var numberOfFocusableItems = focusableItems.length;
// Get the index of the currently focused item
var focusedItemIndex = focusableItems.index(focusedItem);
// If popup doesn't contain focusable elements, focus popup itself
if (numberOfFocusableItems === 0) {
$(el).focus();
event.preventDefault();
} else {
if (event.shiftKey) {
// Back tab
// If focused on first item and user preses back-tab, go to the last focusable item
if (focusedItemIndex === 0) {
focusableItems.get(numberOfFocusableItems - 1).focus();
event.preventDefault();
}
} else {
// Forward tab
// If focused on the last item and user preses tab, go to the first focusable item
if (focusedItemIndex == numberOfFocusableItems - 1) {
focusableItems.get(0).focus();
event.preventDefault();
}
}
}
}
});
/**
* Plugin API
*/
$.fn.popup = function (customoptions) {
return this.each(function () {
var $el = $(this);
var newDefaults = $.extend(true, {}, $.fn.popup.defaults);
// Set defaults for tooltips dynamically instead of implicitly, so they can be overriden with custom options.
if (customoptions && customoptions.type === 'tooltip') {
newDefaults.background = false;
}
if (typeof customoptions === 'object') { // e.g. $('#popup').popup({'color':'blue'})
var opt = $.extend({}, newDefaults, $el.data('popupoptions'), customoptions);
$el.data('popupoptions', opt);
options = $el.data('popupoptions');
methods._init(this);
} else if (typeof customoptions === 'string') { // e.g. $('#popup').popup('hide')
if (!($el.data('popupoptions'))) {
$el.data('popupoptions', newDefaults);
options = $el.data('popupoptions');
}
methods[customoptions].call(this, this);
} else { // e.g. $('#popup').popup()
if (!($el.data('popupoptions'))) {
$el.data('popupoptions', newDefaults);
options = $el.data('popupoptions');
}
methods._init(this);
}
});
};
// destroy all popups
$.fn.popup.destroyall = function () {
// TODO: create tests to check if we can use `hide` method (perhaps we'll need to remove transitions)
// or we need another way of removing the data when destroying.
for(var i=0; i < visiblePopupsArray.length; i++) {
$('#' + visiblePopupsArray[i]).popup('hide');
}
$('.popup_wrapper').remove();
$('.popup_background').remove();
// visiblePopupsArray = []; // TODO: check if we need this for SPA and popups with fadeOut animation and scrolllock
$(document).off('click.jqp');
};
$.fn.popup.defaults = {
type: 'overlay',
absolute: false,
autoopen: false,
background: true,
color: 'black',
opacity: '0.5',
horizontal: 'center',
vertical: 'middle',
offsettop: 0,
offsetleft: 0,
escape: true,
blur: true,
blurignore: null,
setzindex: true,
autozindex: false,
scrolllock: false,
closebutton: false,
closebuttonmarkup: null,
keepfocus: true,
focuselement: null,
focusdelay: 50,
outline: false,
pagecontainer: null,
detach: false,
openelement: null,
closeelement: null,
transition: null,
tooltipanchor: null,
beforeopen: null,
onclose: null,
onopen: null,
opentransitionend: null,
closetransitionend: null
};
})(jQuery); /* eslint-disable-line */
+1
View File
File diff suppressed because one or more lines are too long
+147
View File
@@ -0,0 +1,147 @@
'use strict';
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
(function(global) {
var MONTHS = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
var COLORS = [
'#4dc9f6',
'#f67019',
'#f53794',
'#537bc4',
'#acc236',
'#166a8f',
'#00a950',
'#58595b',
'#8549ba'
];
var Samples = global.Samples || (global.Samples = {});
var Color = global.Color;
Samples.utils = {
// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
srand: function(seed) {
this._seed = seed;
},
rand: function(min, max) {
var seed = this._seed;
min = min === undefined ? 0 : min;
max = max === undefined ? 1 : max;
this._seed = (seed * 9301 + 49297) % 233280;
return min + (this._seed / 233280) * (max - min);
},
numbers: function(config) {
var cfg = config || {};
var min = cfg.min || 0;
var max = cfg.max || 1;
var from = cfg.from || [];
var count = cfg.count || 8;
var decimals = cfg.decimals || 8;
var continuity = cfg.continuity || 1;
var dfactor = Math.pow(10, decimals) || 0;
var data = [];
var i, value;
for (i = 0; i < count; ++i) {
value = (from[i] || 0) + this.rand(min, max);
if (this.rand() <= continuity) {
data.push(Math.round(dfactor * value) / dfactor);
} else {
data.push(null);
}
}
return data;
},
labels: function(config) {
var cfg = config || {};
var min = cfg.min || 0;
var max = cfg.max || 100;
var count = cfg.count || 8;
var step = (max - min) / count;
var decimals = cfg.decimals || 8;
var dfactor = Math.pow(10, decimals) || 0;
var prefix = cfg.prefix || '';
var values = [];
var i;
for (i = min; i < max; i += step) {
values.push(prefix + Math.round(dfactor * i) / dfactor);
}
return values;
},
months: function(config) {
var cfg = config || {};
var count = cfg.count || 12;
var section = cfg.section;
var values = [];
var i, value;
for (i = 0; i < count; ++i) {
value = MONTHS[Math.ceil(i) % 12];
values.push(value.substring(0, section));
}
return values;
},
color: function(index) {
return COLORS[index % COLORS.length];
},
transparentize: function(color, opacity) {
var alpha = opacity === undefined ? 0.5 : 1 - opacity;
return Color(color).alpha(alpha).rgbString();
}
};
// DEPRECATED
window.randomScalingFactor = function() {
return Math.round(Samples.utils.rand(-100, 100));
};
// INITIALIZATION
Samples.utils.srand(Date.now());
// Google Analytics
/* eslint-disable */
if (document.location.hostname.match(/^(www\.)?chartjs\.org$/)) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-28909194-3', 'auto');
ga('send', 'pageview');
}
/* eslint-enable */
}(this));
+20
View File
@@ -0,0 +1,20 @@
<?php
define ('API_BASE_URL','https://oauth2.float.sg/mytransport.sg/api.php');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$google_api_key = $savvyext->cfgReadChar('google.api_key');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_pconnect($conn_string);
if ($pgconn) {
// echo "Okay";
} else {
//echo pg_last_error($pgconn);
}
+94
View File
@@ -0,0 +1,94 @@
<?php
function area_to_area($area1, $area2, $date1, $date2, $t, $c='#FF0000') {
global $pgconn;
$data = [];
$q = "SELECT * FROM geofence_area WHERE id=${area1}";
$r = pg_query($pgconn, $q);
$area1i = pg_fetch_assoc($r);
$boundaries = json_decode($area1i["boundaries"], true);
$polygonCoords = [];
foreach ($boundaries["polygon"] as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString1 = implode(",", $polygonCoords);
$q = "SELECT * FROM geofence_area WHERE id=${area2}";
$r = pg_query($pgconn, $q);
$area2i = pg_fetch_assoc($r);
$boundaries = json_decode($area2i["boundaries"], true);
$polygonCoords = [];
foreach ($boundaries["polygon"] as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString2 = implode(",", $polygonCoords);
$q = "SELECT a.travel_date,a.cost";
$q.= ",b.latitude AS location_start_lat,b.longitude AS location_start_lng";
$q.= ",c.latitude AS location_end_lat,c.longitude AS location_end_lng";
$q.= " FROM quotes a, address b, address c";
$q.= " WHERE a.cost>0 AND a.transport_provider_id=${t}";
$q.= " AND b.id=a.location_start_id AND c.id=a.location_end_id";
$q.= " AND a.travel_date>'${date1} 00:00' AND a.travel_date<'${date2} 23:59'";
$q.= " AND ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString1}))', 4326), b.geometry::geometry)";
$q.= " AND ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString2}))', 4326), c.geometry::geometry)";
$q.= " ORDER BY a.travel_date";
$r = pg_query($pgconn, $q);
while ($f=pg_fetch_assoc($r)) {
$f['origin'] = $area1i['name'];
$f['destination'] = $area2i['name'];
$f['c'] = $c;
$f['time'] = strtotime($f['travel_date']);
$data[] = $f;
}
return [$data,$area1i["name"]." to ".$area2i["name"],$boundaries["polygon"]];
}
function trend_line($regression1, $data) {
$i = 0;
$pub1 = array();
$xs1 = [];
$ys1 = [];
$ys2 = [];
foreach ($data as $f) {
$t = $f['time'];
$pub1[$t] = array($t,$f['cost']);
$xs1[] = [$t];
$ys1[] = $f['cost'];
$i++;
}
if ($i>0) {
$regression1->train($xs1,$ys1);
}
foreach ($pub1 as $key=>$f) {
$y = $regression1->predict( [$f[0]] );
$f[2] = $y;
$pub1[$key] = $f;
}
return [$pub1,$xs1,$ys2];
}
function variation($data, $i, $f, $t) {
global $dMin, $dMax, $tVar, $tVar0;
$tVar[] = $f['cost'];
$trend = $t[$f['time']][2];
$delta = $f['cost'] - $trend;
$variation = stats_variance($tVar);
if ($delta>$dMax) $dMax = $delta;
if ($delta<$dMin) $dMin = $delta;
$tVar0[$f['time']] = $variation;
/* {
"travel_date":"2020-05-10 14:54:04+00",
"cost":"12",
"location_start_lat":"1.319292",
"location_start_lng":"103.9126091",
"location_end_lat":"1.316269",
"location_end_lng":"103.977615",
"origin":"Central East - Eunos",
"destination":"Far East - Changi",
"c":"#5555ff"} */
//if ($i<5) error_log(json_encode($t));
return [$trend, $delta, $variation];
}
+84
View File
@@ -0,0 +1,84 @@
<?php
use Phpml\Regression\LeastSquares;
require('../vendor/autoload.php');
require('../backend.php');
require('config.php');
$regression1 = new LeastSquares();
$t = 3;
$date1 = "2020-01-01";
$date2 = "2020-05-10";
$area1 = 14;
$area2 = 11;
$areas = [
10 => 'Central - Tanglin',
11 => 'Central - Newton',
17 => 'Far East - Changi',
14 => 'Central East - Eunos'
];
$t = isset($_GET['t'])?((int)$_GET['t']):$t;
$date1 = isset($_GET['date1'])?date("Y-m-d",strtotime($_GET['date1'])):$date1;
$date2 = isset($_GET['date2'])?date("Y-m-d",strtotime($_GET['date2'])):$date2;
$area1 = isset($_GET['area1'])?((int)$_GET['area1']):$area1;
$area2 = isset($_GET['area2'])?((int)$_GET['area2']):$area2;
if (3 > $t || $t > 5) $t = 3;
if (!array_key_exists($area1,$areas)) $area1 = 14;
if (!array_key_exists($area2,$areas)) $area2 = 11;
$providers = [3 => "Grab", 5 => "Gojek", 4 => "ComfortDelGro"];
require('functions.php');
//require('ajax.php');
$c = '#ff5555';
list($data1,$label1,$poly1) = area_to_area($area1, $area2, $date1, $date2, $t, $c);
$res1 = trend_line($regression1, $data1);
$pub1 = $res1[0];
$c = '#5555ff';
list($data2,$label2,$poly2) = area_to_area($area2, $area1, $date1, $date2, $t, $c);
$res2 = trend_line($regression1, $data2);
$pub2 = $res2[0];
$data = array_merge($data1, $data2);
require('templates/header.html.php');
require_once('templates/header.js.php');
?>
<table>
<col><col><col><col><col><col><col>
<tr><th>NN</th><th>Travel Date</th><th>Cost</th><th>GPS</th><th>Origin</th><th>GPS</th><th>Destination</th></tr>
<?
$i = 1;
foreach ($data as $f) { ?>
<tr>
<td><?= $i ?></td>
<td><?= strtok($f['travel_date'],'+') ?></td>
<td><?= sprintf("%0.02f", $f['cost']) ?></td>
<td><?= $f['location_start_lat'].','.$f['location_end_lng']?></td>
<td><?= $f['origin'] ?></td>
<td><?= $f['location_end_lat'].','.$f['location_end_lng']?></td>
<td><?= $f['destination'] ?></td>
</tr>
<?
$i++;
}
?>
<script>$("#loader").hide();$("#tabs").show();$("#dfilter").show();</script>
<script>
$(document).ready(function() {
$.fn.popup.defaults.pagecontainer = '#page';
});
</script>
</div>
<?
include('javascript.php');
?>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
<script type="text/javascript">
<!--
// -->
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=<?=$google_api_key?>&callback=initMap">
</script>
+291
View File
@@ -0,0 +1,291 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Surge pricing varaition in downtown core</title>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="assets/js/jquery.popupoverlay.js"></script>
<link rel="stylesheet" type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<style>
[class*="fa-"]:before {
font-family: 'FontAwesome', sans-serif;
}
</style>
<style id="compiled-css" type="text/css">
#ui-datepicker-div { font-size: 12px; }
</style>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 80vh;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script src="assets/js/luxon.min.js"></script>
<script src="assets/js/Chart.min.js"></script>
<script src="assets/js/chartjs-adapter-luxon.js"></script>
<script src="assets/js/chartjs-chart-financial.js" type="text/javascript"></script>
<script src="assets/js/utils.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
td:hover{
cursor: pointer;
}
col:first-child {background: #FFD}
col:nth-child(2n+3) {background: #FFD}
tr:first-child {background: #DDF}
tr:nth-child(2n+3) {background: #DDD}
th {
text-align: center;
}
.well {
/* drop-shadow is better than box-shadow as it add a shadow to tooltip arrows arrow as well,
however drop-shadow dramatically affects the performance of transition animation on Android. */
/* filter: drop-shadow(0 0 10px rgba(0,0,0,0.3)); */
display:none;
margin:1em;
max-width: 90%;
}
.well .popup_close {
position: absolute;
top: 0;
right: 0px;
border-radius: 2px;
background: none;
border: 0;
font-size: 25px;
padding: 0 10px;
}
.tv-content {
display: none;
}
.tv-radio {
display: none;
}
.tv-radio:checked + .tv-content {
display: block;
}
.tv-tab {
display: inline-block;
cursor: pointer;
padding: 8px;
}
.tv-tab:hover {
opacity: 0.9;
}
body {
margin: 40px;
font-family: 'Georgia';
background-color: #ffffee;
}
.tv-tabs {
color: #ecf0f1;
}
.tv-tabs :nth-child(odd) {
background-color: #2c3e50;
}
.tv-tabs :nth-child(even) {
background-color: #34495e;
}
.tv-content {
padding: 10px;
min-width: 600px;
min-height: 600px;
}
#tv-tab-1 + .tv-content {
background-color: #ffffff;
color: #ecf0f1;
}
#tv-tab-2 + .tv-content {
background-color: #ffffff;
color: #ecf0f1;
}
#tv-tab-3 + .tv-content {
background-color: #ffffff;
color: #ecf0f1;
}
#tv-tab-4 + .tv-content {
background-color: #ffffff;
color: #000000;
}
#tv-tab-5 + .tv-content {
background-color: #ffffff;
color: #000000;
}
a,
.tv-link {
display: inline-block;
padding: 2px;
color: #f1c40f;
background-color: rgba(255,255,255,0.2);
box-shadow: 1px 1px 5px rgba(255,255,255,0.2);
transition: all 0.4s ease-in-out;
}
a:hover,
.tv-link:hover {
background-color: transparent;
box-shadow: none;
}
ul {
list-style-type: binary;
}
pre {
display: block;
overflow: hidden;
padding: 8px;
background-color: rgba(0,0,0,0.2);
}
code {
display: block;
margin-top: -10px;
margin-left: -40px;
}
.progress {
width:100px;
height: 100%;
}
.progress-wrap {
background: #dcdcdc;
margin: 20px 0;
overflow: hidden;
position: relative;
}
.progress-bar {
background:#249c23;
left: 0;
position: absolute;
top: 0;
width:0%;
}
</style>
</head>
<body>
<!-- Wrap all page content in a page container (optional, but recommended for screen readers and iOS*) -->
<div id="page">
<div id="loader">Loading data
<div id="progress" class="progress-wrap progress"
data-progresspercent="0"
data-height="10px"
data-width="150px"
data-speed="1500"
data-color="3a9c23">
<div class="progress-bar progress"></div>
</div>
</div>
<div id="dfilter" style="display:none">
<form method="get" action="?">
<select name="t"><? foreach ($providers as $key=>$val) { ?><option value="<?=$key?>"<?= $key==$t ? ' selected' : '' ?>><?=$val?></option><? } ?></select>
<select name="area1"><? foreach ($areas as $key=>$val) { ?><option value="<?=$key?>"<?= $key == $area1 ? ' selected' : '' ?>><?=$val?></option><? } ?></select>
<select name="area2"><? foreach ($areas as $key=>$val) { ?><option value="<?=$key?>"<?= $key == $area2 ? ' selected' : '' ?>><?=$val?></option><? } ?></select>
<input type="text" id="date1" name="date1" value="<?= $date1 ?>" />
<input type="text" id="date2" name="date2" value="<?= $date2 ?>" />
<input type="submit" value="filter"/>
</form>
<br/>
</div>
<div id="tabs" class="tv-tabs" style="display:none">
<label class="tv-tab" for="tv-tab-1"><?= $providers[$t] ?>: <?= $label1 ?></label>
<label class="tv-tab" for="tv-tab-2"><?= $providers[$t] ?>: <?= $label2 ?></label>
<label class="tv-tab" for="tv-tab-5">Map</label>
<label class="tv-tab" for="tv-tab-3">Comparison</label>
<label class="tv-tab" for="tv-tab-4">Data</label>
</div>
<input class="tv-radio" id="tv-tab-1" name="tv-group" type="radio" checked="checked"/>
<div class="tv-content">
<div style="width:75%">
<canvas id="canvas1"></canvas>
</div>
</div>
</div>
<input class="tv-radio" id="tv-tab-2" name="tv-group" type="radio"/>
<div class="tv-content">
<div style="width:75%">
<canvas id="canvas2"></canvas>
</div>
</div>
<input class="tv-radio" id="tv-tab-5" name="tv-group" type="radio"/>
<div class="tv-content">
<div id="map"></div>
</div>
<input class="tv-radio" id="tv-tab-3" name="tv-group" type="radio"/>
<div class="tv-content">
<div style="width:75%;color:#000000!important;">
<div id="dataRes1"></div><br/>
<div id="dataRes2"></div><br/>
<div style="width:75%">
<canvas id="canvas3"></canvas>
</div>
<table>
<col><col><col><col><col><col>
<tr><th>NN</th><th>Travel Date</th><th>Time</th><th>Cost</th><th>Trend</th><th>Delta</th><th>Variation</th></tr>
<? $j=1; $dMax = 0; $dMin = 0; $tVar = []; $tVar0 = []; foreach ($data1 as $i=>$f) { $d = variation($data1,$i,$f,$pub1); ?>
<tr>
<td><?= $j++ ?></td>
<td><?= strtok($f['travel_date'],'+') ?></td>
<td><?= $f['time'] ?></td>
<td><?= sprintf("%0.02f", $f['cost']) ?></td>
<td><?= sprintf("%0.02f", $d[0]) ?></td>
<td><?= sprintf("%0.02f", $d[1]) ?></td>
<td><?= sprintf("%0.02f", $d[2]) ?></td>
</tr>
<? } ?>
<tr>
<td colspan="7"><div id="dataSrc1"><?= $label1.": ".sprintf("%0.02f",$dMin).' / '.sprintf("%0.02f",$dMax).' ~ '.stats_variance($tVar) ?></div></td>
</tr>
<? $tVar1 = $tVar0; $dMax = 0; $dMin = 0; $tVar = []; $tVar0 = []; foreach ($data2 as $i=>$f) { $d = variation($data1,$i,$f,$pub2); ?>
<tr>
<td><?= $j++ ?></td>
<td><?= strtok($f['travel_date'],'+') ?></td>
<td><?= $f['time'] ?></td>
<td><?= sprintf("%0.02f", $f['cost']) ?></td>
<td><?= sprintf("%0.02f", $d[0]) ?></td>
<td><?= sprintf("%0.02f", $d[1]) ?></td>
<td><?= sprintf("%0.02f", $d[2]) ?></td>
</tr>
<? } ?>
<? $tVar2 = $tVar0; ?>
<tr>
<td colspan="7"><div id="dataSrc2"><?= $label2.": ".sprintf("%0.02f",$dMin).' / '.sprintf("%0.02f",$dMax).' ~ '.stats_variance($tVar) ?></div></td>
</tr>
</table>
</div>
</div>
<input class="tv-radio" id="tv-tab-4" name="tv-group" type="radio"/>
<div class="tv-content">
<script>
document.getElementById('dataRes1').innerHTML = document.getElementById('dataSrc1').innerHTML;
document.getElementById('dataRes2').innerHTML = document.getElementById('dataSrc2').innerHTML;
function updateProgress() {
var progress = $("#progress");
var getPercent = progress.attr("data-progresspercent");
var getSpeed = parseInt(progress.attr("data-speed"));
var getColor = progress.attr("data-color");
var getHeight = progress.attr("data-height");
var getWidth = progress.attr("data-width");
progress.css({"height":getHeight,"width":getWidth});
progress.find(".progress-bar").css({"background-color":"#"+getColor}).animate({ width:getPercent+'%' },getSpeed);
if (getPercent<100) setTimeout(updateProgress,500);
}
updateProgress();
</script>
+353
View File
@@ -0,0 +1,353 @@
<script>
var color = Chart.helpers.color;
var dataSets1 = [];
var dataSetTrends1 = [];
var dataSets2 = [];
var dataSetTrends2 = [];
var dataSets3 = [];
var dataSetTrends3 = [];
// Rideshare only
dataSets1[0] = []; dataSetTrends1[0] = [];
dataSets2[0] = []; dataSetTrends2[0] = [];
$("#progress").attr("data-progresspercent",25);
// Public transit and walking
dataSets1[1] = []; dataSetTrends1[1] = [];
<?php foreach ($pub2 as $f) { ?> dataSets1[1].push({x: <?php echo $f[0]; ?>000, y: <?php echo $f[1]; ?>});
dataSetTrends1[1].push({x: <?php echo $f[0]; ?>000, y: <?php echo $f[2]; ?>});
<?php } ?>
$("#progress").attr("data-progresspercent",27);
dataSets2[1] = []; dataSetTrends2[1] = [];
<?php foreach ($pub1 as $f) { ?> dataSets2[1].push({x: <?php echo $f[0]; ?>000, y: <?php echo $f[1]; ?>});
dataSetTrends2[1].push({x: <?php echo $f[0]; ?>000, y: <?php echo $f[2]; ?>});
<?php } ?>
dataSets3[0] = []; dataSetTrends3[0] = [];
<?php $tVar1a = []; foreach ($tVar1 as $k=>$v) { ?> dataSets3[0].push({x: <?php echo $k; ?>000, y: <?php echo $v; ?>});
<?php /* $tVar1a[] = $v;*/ } ?>
//dataSetTrends3[0] = [<?php echo implode(',',$tVar1a); ?>];
dataSets3[1] = []; dataSetTrends3[1] = [];
<?php $tVar2a = []; foreach ($tVar2 as $k=>$v) { ?> dataSets3[1].push({x: <?php echo $k; ?>000, y: <?php echo $v; ?>});
<?php /* $tVar2a[] = $v;*/ } ?>
//dataSetTrends3[1] = [<?php echo implode(',',$tVar2a); ?>];
$("#progress").attr("data-progresspercent",30);
// Public transit, walking and scooter
dataSets1[2] = []; dataSetTrends1[2] = [];
dataSets2[2] = []; dataSetTrends2[2] = [];
$("#progress").attr("data-progresspercent",35);
// Public transit, walking and bicycle
dataSets1[3] = []; dataSetTrends1[3] = [];
dataSets2[3] = []; dataSetTrends2[3] = [];
$("#progress").attr("data-progresspercent",40);
// Driving your own car
dataSets1[4] = []; dataSetTrends1[4] = [];
<?php if (isset($taxi)): ?>
<?php foreach ($taxi as $f) { if (!isset($f[2])) continue; ?> dataSets1[4].push({
x: <?php echo $f[0]; ?>,
y: <?php echo $f[1]; ?>});
dataSetTrends1[4].push({
x: <?php echo $f[0]; ?>,
y: <?php echo $f[2]; ?>});
<?php } ?>
<?php endif; ?>
$("#progress").attr("data-progresspercent",43);
dataSets2[4] = []; dataSetTrends2[4] = [];
<?php if (isset($taxi0)): ?>
<?php foreach ($taxi0 as $f) { if (!isset($f[2])) continue; ?> dataSets2[4].push({
x: <?php echo $f[0]; ?>,
y: <?php echo $f[1]; ?>});
dataSetTrends2[4].push({
x: <?php echo $f[0]; ?>,
y: <?php echo $f[2]; ?>});
<?php } ?>
<?php endif; ?>
$("#progress").attr("data-progresspercent",45);
// Car share (like Zipcar or BlueSG) and public transit, walking
dataSets1[5] = []; dataSetTrends1[5] = [];
dataSets2[5] = []; dataSetTrends2[5] = [];
$("#progress").attr("data-progresspercent",50);
var scatterChartData1 = {
datasets: [/*{
label: 'Rideshare only',
borderColor: window.chartColors.blue,
backgroundColor: color(window.chartColors.blue).alpha(0.2).rgbString(),
data: dataSets1[0]
},*/{
label: '<?= $providers[$t] ?>',
borderColor: window.chartColors.green,
backgroundColor: color(window.chartColors.green).alpha(0.2).rgbString(),
data: dataSets1[1]
}, {
label: '<?= $providers[$t] ?> trend line',
pointBorderColor: window.chartColors.black,
pointBackgroundColor: color(window.chartColors.black).alpha(0.2).rgbString(),
data: dataSetTrends1[1],
showLine: true,
borderWidth: 1,
fill: false,
tension: 0,
pointRadius: 3,
pointHoverRadius: 3
}/*,{
label: 'Public transit, walking and scooter',
borderColor: window.chartColors.red,
backgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
data: dataSets1[2]
}, {
label: 'Public transit, walking and bicycle',
borderColor: window.chartColors.purple,
backgroundColor: color(window.chartColors.purple).alpha(0.2).rgbString(),
data: dataSets1[3]
}, {
label: 'Driving your own car',
borderColor: window.chartColors.orange,
backgroundColor: color(window.chartColors.orange).alpha(0.2).rgbString(),
data: dataSets1[4]
}, {
label: 'Driving your own car trend line',
pointBorderColor: window.chartColors.black,
pointBackgroundColor: color(window.chartColors.black).alpha(0.2).rgbString(),
data: dataSetTrends1[4],
showLine: true,
borderWidth: 1,
fill: false,
tension: 0,
pointRadius: 3,
pointHoverRadius: 3
}, {
label: 'Car share (like Zipcar or BlueSG) and public transit, walking',
borderColor: window.chartColors.yellow,
backgroundColor: color(window.chartColors.yellow).alpha(0.2).rgbString(),
Color: color(window.chartColors.yellow).alpha(0.2).rgbString(),
data: dataSets1[5]
}*/]
};
var scatterChartData2 = {
datasets: [/*{
label: 'Rideshare only',
borderColor: window.chartColors.blue,
backgroundColor: color(window.chartColors.blue).alpha(0.2).rgbString(),
data: dataSets2[0]
},*/ {
label: '<?=$providers[$t]?>',
borderColor: window.chartColors.green,
backgroundColor: color(window.chartColors.green).alpha(0.2).rgbString(),
data: dataSets2[1]
}, {
label: '<?=$providers[$t]?> trend line',
pointBorderColor: window.chartColors.black,
pointBackgroundColor: color(window.chartColors.black).alpha(0.2).rgbString(),
data: dataSetTrends2[1],
showLine: true,
borderWidth: 1,
fill: false,
tension: 0,
pointRadius: 3,
pointHoverRadius: 3
}/*,{
label: 'Public transit, walking and scooter',
borderColor: window.chartColors.red,
backgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
data: dataSets2[2]
}, {
label: 'Public transit, walking and bicycle',
borderColor: window.chartColors.purple,
backgroundColor: color(window.chartColors.purple).alpha(0.2).rgbString(),
data: dataSets2[3]
}, {
label: 'Driving your own car',
borderColor: window.chartColors.orange,
backgroundColor: color(window.chartColors.orange).alpha(0.2).rgbString(),
data: dataSets2[4]
}, {
label: 'Driving your own car trend line',
pointBorderColor: window.chartColors.black,
pointBackgroundColor: color(window.chartColors.black).alpha(0.2).rgbString(),
data: dataSetTrends2[4],
showLine: true,
borderWidth: 1,
fill: false,
tension: 0,
pointRadius: 3,
pointHoverRadius: 3
}, {
label: 'Car share (like Zipcar or BlueSG) and public transit, walking',
borderColor: window.chartColors.yellow,
backgroundColor: color(window.chartColors.yellow).alpha(0.2).rgbString(),
Color: color(window.chartColors.yellow).alpha(0.2).rgbString(),
data: dataSets2[5]
}*/]
};
var scatterChartData3 = {
datasets: [{
label: '<?= $label1 ?>',
borderColor: window.chartColors.red,
backgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
pointBorderColor: window.chartColors.red,
pointBackgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
data: dataSets3[0],
pointHoverRadius: 5,
fill: false,
tension: 0,
showLine: true
}, {
label: '<?= $label2 ?>',
borderColor: window.chartColors.blue,
backgroundColor: color(window.chartColors.blue).alpha(0.2).rgbString(),
pointBorderColor: window.chartColors.blue,
pointBackgroundColor: color(window.chartColors.blue).alpha(0.2).rgbString(),
data: dataSets3[1],
pointHoverRadius: 5,
fill: false,
tension: 0,
showLine: true
}/*, {
label: '<?= $label1 ?> line',
data: dataSets3[0],
type: 'line'
}, {
label: '<?= $label2 ?> line',
data: dataSets3[1],
type: 'line'
}*/]
};
window.onload = function() {
var ctx1 = document.getElementById('canvas1').getContext('2d');
//window.myScatter = Chart.Scatter(ctx1, {
window.myScatter1 = new Chart(ctx1, {
type: 'scatter',
data: scatterChartData1,
options: {
title: {
display: true,
text: '<?= $providers[$t] ?>: <?= $label1 ?>'
},
scales: {
xAxes: [{
ticks: {
callback: function(value, index, values) {
return new Date(value).toLocaleDateString("en-US");
}
}
}]
}
}
});
var ctx2 = document.getElementById('canvas2').getContext('2d');
//window.myScatter = Chart.Scatter(ctx2, {
window.myScatter2 = new Chart(ctx2, {
type: 'scatter',
data: scatterChartData2,
options: {
title: {
display: true,
text: '<?= $providers[$t] ?>: <?= $label2 ?>'
},
scales: {
xAxes: [{
ticks: {
callback: function(value, index, values) {
return new Date(value).toLocaleDateString("en-US");
}
}
}]
}
}
});
var ctx3 = document.getElementById('canvas3').getContext('2d');
//window.myScatter = Chart.Scatter(ctx3, {
window.myScatter3 = new Chart(ctx3, {
type: 'scatter',
data: scatterChartData3,
options: {
title: {
display: true,
text: 'Statistical variance'
},
scales: {
xAxes: [{
ticks: {
callback: function(value, index, values) {
return new Date(value).toLocaleDateString("en-US");
}
}
}]
}
}
});
$('#date1').datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
dateFormat: "yy-m-d"
});
$('#date2').datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
dateFormat: "yy-m-d"
});
};
/*
document.getElementById('reloadData').addEventListener('click', function() {
var i = 0;
scatterChartData.datasets.forEach(function(dataset) {
dataset.data = dataSets[i];
i++;
});
window.myScatter.update();
});
*/
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: {lat: 1.313333, lng: 103.833333},
mapTypeId: 'roadmap'
});
<? foreach ($data as $i=>$f) { ?>
var flightPlanCoordinates<?= $i ?> = [
{lat: <?= $f["location_start_lat"] ?>, lng: <?= $f["location_start_lng"] ?>},
{lat: <?= $f["location_end_lat"] ?>, lng: <?= $f["location_end_lng"] ?>}
];
var flightPath<?= $i ?> = new google.maps.Polyline({
path: flightPlanCoordinates<?= $i ?>,
geodesic: true,
strokeColor: '<?= $f['c'] ?>',
strokeOpacity: 0.06125,
strokeWeight: 2
});
flightPath<?= $i ?>.setMap(map);
<? } ?>
var areaCoordinates1 = [
<? foreach ($poly1 as $i=>$coord) { ?>{lat: <?= $coord[1] ?>, lng: <?= $coord[0] ?>},<? } ?>
{lat:<?=$poly1[$i][1]?> ,lng:<?=$poly1[$i][0]?>}
];
var areaPath1 = new google.maps.Polyline({
path: areaCoordinates1,
geodesic: true,
strokeColor: '#009900',
strokeOpacity: 1.0,
strokeWeight: 2
});
areaPath1.setMap(map);
var areaCoordinates2 = [
<? foreach ($poly2 as $i=>$coord) { ?>{lat: <?= $coord[1] ?>, lng: <?= $coord[0] ?>},<? } ?>
{lat:<?=$poly2[$i][1]?> ,lng:<?=$poly2[$i][0]?>}
];
var areaPath2 = new google.maps.Polyline({
path: areaCoordinates2,
geodesic: true,
strokeColor: '#009900',
strokeOpacity: 1.0,
strokeWeight: 2
});
areaPath2.setMap(map);
}
</script>
<!-- vi:ts=2
-->