first commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
// ?ajax=routes&id=
|
||||
if (isset($_GET['ajax']) && $_GET['ajax']=='routes') {
|
||||
$id = (int)$_GET['id'];
|
||||
if ($id>0) {
|
||||
$url = API_BASE_URL . "?ajax=routes&id=${id}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${oauth2ServiceToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
echo $body;
|
||||
} else {
|
||||
echo "Invalid ID!";
|
||||
}
|
||||
exit();
|
||||
}
|
||||
// ?ajax=taxiquote&id=
|
||||
if (isset($_GET['ajax']) && $_GET['ajax']=='taxiquote') {
|
||||
$id = (int)$_GET['id'];
|
||||
if ($id>0) {
|
||||
$url = API_BASE_URL . "?ajax=taxiquote&id=${id}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${oauth2ServiceToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
echo $body;
|
||||
} else {
|
||||
echo "Invalid ID!";
|
||||
}
|
||||
exit();
|
||||
}
|
||||
// ?ajax=taxi&id=
|
||||
if (isset($_GET['ajax']) && $_GET['ajax']=='taxi') {
|
||||
$id = (int)$_GET['id'];
|
||||
if ($id>0) {
|
||||
$url = API_BASE_URL . "?ajax=taxi&id=${id}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${oauth2ServiceToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
echo $body;
|
||||
} else {
|
||||
echo "Invalid ID!";
|
||||
}
|
||||
exit();
|
||||
}
|
||||
// ?ajax=quote&id=&sid=
|
||||
if (isset($_GET['ajax']) && $_GET['ajax']=='quote') {
|
||||
$id = (int)$_GET['id'];
|
||||
$sid = (int)$_GET['sid'];
|
||||
if ($id>0 && $sid>0) {
|
||||
$url = API_BASE_URL . "?ajax=quote&id=${id}&sid=${sid}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${oauth2ServiceToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
echo $body;
|
||||
} else {
|
||||
echo "Invalid ID/SID!";
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
// vi:ts=2
|
||||
|
||||
+7
File diff suppressed because one or more lines are too long
@@ -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()}})});
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
}));
|
||||
@@ -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
File diff suppressed because one or more lines are too long
@@ -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));
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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');
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
header('Content-Encoding: UTF-8');
|
||||
header('Content-Type: text/csv; charset=UTF-8');
|
||||
header('Content-Disposition: attachment; filename="mytransport-'.date("Ymd-Hi").'.csv"');
|
||||
//echo "\xEF\xBB\xBF"; // UTF-8 BOM
|
||||
|
||||
require('../backend.php');
|
||||
require('config.php');
|
||||
require('functions.php');
|
||||
|
||||
$member_id = 3;
|
||||
$members_id = "3,22";
|
||||
|
||||
$q = "SELECT parsedemail_item.*,parsedemail_item_advice_google.id AS gid,parsedemail_item_advice_google.routes,trackedemail_item.id as tid,trackedemail_item.member_id, ";
|
||||
$q.= " b.address AS location_start,b.latitude AS location_start_lat,b.longitude AS location_start_lng, b.timezone AS location_start_tz,
|
||||
b.geocoding_date AS location_geocoding_date, c.address AS location_end, c.latitude AS location_end_lat,c.longitude AS location_end_lng ";
|
||||
$q.= " FROM trackedemail_item, parsedemail_item ";
|
||||
$q.= " LEFT JOIN parsedemail_item_advice_google ON parsedemail_item.id=parsedemail_item_advice_google.parsedemail_item_id ";
|
||||
$q.= " LEFT JOIN address b ON (b.id=a.location_start_id) LEFT JOIN address c ON (c.id=a.location_end_id) ";
|
||||
$q.= " WHERE trackedemail_item.id=parsedemail_item.trackedemail_item_id AND trackedemail_item.member_id IN (${members_id})";
|
||||
//$q.= " AND parsedemail_item.location_start_tz='Asia/Singapore';";
|
||||
$q.= " AND parsedemail_item.dup_id IS NULL";
|
||||
$q.= " ORDER BY parsedemail_item.travel_date DESC, parsedemail_item.travel_date_end DESC";
|
||||
//echo $q;
|
||||
$r = pg_query($q);
|
||||
echo '"Travel Date (Start)";"End Time";"Duration";"Distance";"Travel From";"Travel To";"Cost";"Provider";"Routes";"Member ID"' . "\n";
|
||||
|
||||
$arrayToCsvLine = function(array $values) {
|
||||
$line = '';
|
||||
$values = array_map(function ($v) {
|
||||
return '"' . str_replace('"', '""', $v) . '"';
|
||||
}, $values);
|
||||
$line .= implode(';', $values);
|
||||
return $line;
|
||||
};
|
||||
|
||||
while ($f=pg_fetch_assoc($r)) {
|
||||
$duration = getDuration($f["duration"],$f["travel_date"],$f["travel_date_end"]);
|
||||
$line = array(
|
||||
$f["travel_date"],
|
||||
getEndDateTime($f["travel_date"],$f["travel_date_end"],$f["duration"]),
|
||||
$duration==""?"0":(int)$duration,
|
||||
$f["distance"]==""?"0.00":sprintf("%0.02f",1.0*$f["distance"]),
|
||||
$f["location_start"],
|
||||
$f["location_end"],
|
||||
$f["cost"]==""?"0.00":sprintf("%0.02f",1.0*$f["cost"]),
|
||||
getTransportProvider($f["transport_provider_id"]),
|
||||
$f["routes"]==""?"0":(int)$f["routes"],
|
||||
$f["member_id"]
|
||||
);
|
||||
echo $arrayToCsvLine($line)."\n"; // ."\r\n"
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
function getDuration($duration,$startTime,$endTime) {
|
||||
$ret = $duration;
|
||||
if ($startTime!="" && $endTime!="") {
|
||||
$end_t = strtotime($endTime);
|
||||
$start_t = strtotime($startTime);
|
||||
$ret = (int)round(($end_t-$start_t)/60,2);
|
||||
if ($ret<0) $ret = -$ret;
|
||||
return $ret > 240 ? ($ret-240) : $ret;
|
||||
}
|
||||
if ($ret>$duration) $ret = $duration;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function getEndDateTime($startTime,$endTime,$duration) {
|
||||
if ($endTime!="") return $endTime;
|
||||
if ($duration>0) return $duration;
|
||||
}
|
||||
|
||||
function showDirections($f,$noRecurse=true, $htmlHeader="") {
|
||||
if ($f["routes"]>0 && $f["gid"]>0) {
|
||||
$q0 = "SELECT * FROM google_directions_legs WHERE parsedemail_item_advice_google_id=".$f["gid"];
|
||||
$r0 = pg_query($q0);
|
||||
if ($htmlHeader!="") {
|
||||
echo "<table width='100%' style='color:#cc5555;font-weight:bold;'>${htmlHeader}</table>\n";
|
||||
}
|
||||
echo "<table width='100%' bgcolor='#ccc'><tr><th>Departure</th><th>Arrival</th><th>Distance</th><th>Duration</th><th>Steps</th><th>Cost</th></tr>\n";
|
||||
while ($f0=pg_fetch_assoc($r0)) {
|
||||
echo "<tr align=center bgcolor='#ffc'>";
|
||||
echo "<td>".($f0["departure_time"]==0?'N/A':date("Y-m-d H:i:s",$f0["departure_time"]))."</td>" ;
|
||||
echo "<td>".($f0["arrival_time"]==0?'N/A':date("Y-m-d H:i:s",$f0["arrival_time"]))."</td>";
|
||||
echo "<td>".sprintf("%0.01f",$f0["distance"]/1000.0)."km</td>";
|
||||
echo "<td>".gmdate("H:i:s", $f0["duration"])."</td>";
|
||||
echo "<td>".$f0["steps"]."</td>";
|
||||
echo "<td>$".sprintf("%0.02f",0.01*$f0["fare_raw"])."</td>";
|
||||
echo "</tr>\n";
|
||||
echo "<tr><td colspan=8>";
|
||||
$q1 = "SELECT a.id AS sid,a.*,b.* FROM google_directions_leg_steps a LEFT JOIN google_directions_leg_step_details b ON a.id=b.google_directions_leg_step_id ";
|
||||
$q1.= " WHERE a.google_directions_leg_id=".$f0["id"];
|
||||
$r1 = pg_query($q1); $i=1;
|
||||
echo "<table width='100%'><tr><th>N</th><th>Travel Mode</th><th>Distance</th><th>Duration</th><th>Instructions</th>";
|
||||
echo "<th>Stops</th><th>Line</th><th>Vehicle</th><th>Departure Stop</th><th>Arrival Stop</th><th>Quote</th><th align=right>Departure / Arrival</th>";
|
||||
echo "</tr>";
|
||||
$fare = 0;
|
||||
while ($f1=pg_fetch_assoc($r1)) {
|
||||
echo "<tr bgcolor='#".($i%2==0?"fff'":"eee")."'><td>".$i."</td>";
|
||||
echo "<td>".$f1["travel_mode"]."</td>";
|
||||
echo "<td align=right>".($f1["distance"]<1000 ? $f1["distance"] : sprintf("%0.01fk",$f1["distance"]/1000.0))."m</td>";
|
||||
echo "<td align=center>".gmdate("H:i:s", $f1["duration"])."</td>";
|
||||
echo "<td>".$f1["html_instructions"]."</td>";
|
||||
echo "<td>".$f1["num_stops"]."</td>";
|
||||
echo "<td>".$f1["line"]."</td>";
|
||||
echo "<td>".$f1["vehicle"]."</td>";
|
||||
echo "<td>".$f1["departure_stop"]."</td>";
|
||||
echo "<td>".$f1["arrival_stop"]."</td>";
|
||||
$q2 = "SELECT * FROM leg_step_quote WHERE google_directions_leg_step_id=".$f1["sid"];
|
||||
$r2 = pg_query($q2);
|
||||
$f2 = pg_fetch_assoc($r2);
|
||||
if (is_array($f2) && isset($f2["fare"]) && $f2["fare"]!="") {
|
||||
echo "<td align=right><div id=\"quote_".$f["id"]."_".$f1["sid"]."\"><a href='#' title=\"Get quote\" onclick=\"return getQuote(".$f["id"].",".$f1["sid"].")\">".$f2["fare"]."</a></div></td>";
|
||||
echo "<td align=right>".sprintf("%0.03f",$f1["location_start_lat"]).",".sprintf("%0.03f",$f1["location_start_lng"]);
|
||||
echo "<br/>".sprintf("%0.03f",$f1["location_end_lat"]).",".sprintf("%0.03f",$f1["location_end_lng"])."</td>";
|
||||
$fare += $f2["fare_raw"];
|
||||
} else if (strtolower($f1["vehicle"])=='bus' || strtolower($f1["vehicle"])=='subway' || strtolower($f1["vehicle"])=='scooter') {
|
||||
echo "<td align=right><div id=\"quote_".$f["id"]."_".$f1["sid"]."\"><a href='#' onclick=\"return getQuote(".$f["id"].",".$f1["sid"].")\">Get quote</a></div></td>";
|
||||
echo "<td align=right>".sprintf("%0.03f",$f1["location_start_lat"]).",".sprintf("%0.03f",$f1["location_start_lng"]);
|
||||
echo "<br/>".sprintf("%0.03f",$f1["location_end_lat"]).",".sprintf("%0.03f",$f1["location_end_lng"])."</td>";
|
||||
} else {
|
||||
echo "<td align=center>N/A</td><td align=center>N/A</th>";
|
||||
}
|
||||
echo "</tr>\n";
|
||||
$i++;
|
||||
}
|
||||
if ($fare==0) $fare = $f0["fare_raw"];
|
||||
echo "<tr align=right><td colspan=10><b>Total:</b></td><td>$".sprintf("%0.02f",$fare/100.0)."</td></tr>\n";
|
||||
echo "</table>\n";
|
||||
echo "</td></tr>\n";
|
||||
}
|
||||
echo "</table>";
|
||||
} else {
|
||||
echo " <a href='#' onclick=\"return loadRoutes(".$f["id"].");\">Get google directions routes</a>";
|
||||
}
|
||||
echo "<div id=\"taxi_".$f["id"]."\">";
|
||||
showTaxi($f,$noRecurse);
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
function showMenu($id) {
|
||||
echo "<a href=\"#\" onclick=\"return loadTaxi(${id});\">Get taxi advice</a>";
|
||||
echo " | <a href=\"#\" onclick=\"return quoteTaxi(${id});\">Regular taxi quote</a>";
|
||||
}
|
||||
|
||||
function showTaxi($f, $noRecurse=true, $force=false) {
|
||||
$q0 = "SELECT * FROM parsedemail_item_advice WHERE parsedemail_item_id=".$f["id"];
|
||||
$r0 = pg_query($q0);
|
||||
//echo $q0;
|
||||
if ($noRecurse) {
|
||||
showMenu($f["id"]);
|
||||
}
|
||||
if ($r0 && pg_num_rows($r0) && !$force) {
|
||||
ob_start();
|
||||
echo "<table width=100%><tr align=right><th align=center>Time</th><th>Provider</th><th align=left>Product</th><th>High</th><th>Low</th><th>Distance</th><th align=center>Duration</th></tr>\n";
|
||||
while ($f0=pg_fetch_assoc($r0)) {
|
||||
echo "<tr align=right>";
|
||||
echo "<td align=center>".strtok($f0["advice_time"],".")."</td>";
|
||||
echo "<td>".getTransportProvider($f0["transport_provider_id"])."</td>";
|
||||
echo "<td align=left>".$f0["display_name"]."<!-- ".$f0["transport_product"]." --></td>";
|
||||
echo "<td>$".sprintf("%0.02f",$f0["high_estimate"]/100.0)."</td>";
|
||||
echo "<td>$".sprintf("%0.02f",$f0["low_estimate"]/100.0)."</td>";
|
||||
echo "<td>".$f0["distance_estimate"]."</td>";
|
||||
echo "<td align=center>".gmdate("H:i:s", $f0["duration_estimate"])."</td>";
|
||||
echo "</tr>";
|
||||
}
|
||||
echo "</table>\n";
|
||||
if ($force) {
|
||||
showTaxi($f,true,false);
|
||||
} else {
|
||||
ob_end_flush();
|
||||
}
|
||||
} if ($noRecurse) {
|
||||
//echo "No recurse!";
|
||||
} else {
|
||||
// Get Advice
|
||||
ob_start();
|
||||
$result = local_v1_service_call('GET','advice',$f["id"]);
|
||||
ob_end_clean();
|
||||
//ob_end_flush();
|
||||
if ($result["code"]==0) {
|
||||
$data = $result["data"];
|
||||
if (isset($data["error_uber"])) echo $data["error_uber"]."\n";
|
||||
if (isset($data["error_lyft"])) echo $data["error_lyft"]."\n";
|
||||
showTaxi($f, true);
|
||||
} else {
|
||||
echo "Invalid service response code!\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTransportProvider($id) {
|
||||
global $providers;
|
||||
if (!is_array($providers) || !isset($providers[$id])) {
|
||||
$q = "SELECT id,name FROM transport_providers";
|
||||
$r = pg_query($q);
|
||||
while ($f=pg_fetch_row($r)) $providers[$f[0]] = $f[1];
|
||||
}
|
||||
return $providers[$id]."(".$id.")";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
require('../backend.php');
|
||||
require('config.php');
|
||||
$q = "SELECT min(latitude),max(latitude),min(longitude),max(longitude) FROM address WHERE timezone=1"; //'Asia/Singapore'";
|
||||
$r = pg_query($q);
|
||||
$f = pg_fetch_row($r);
|
||||
$lats = array($f[0],$f[1]);
|
||||
$lngs = array($f[2],$f[3]);
|
||||
$center_lat = (min($lats)+max($lats))/2;
|
||||
$center_lng = (min($lngs)+max($lngs))/2;
|
||||
// top locations
|
||||
$q = "SELECT SUM(num) AS total, lat, lng FROM ( SELECT COUNT(*) AS num, ROUND(b.latitude,2) AS lat, ROUND(b.longitude,2) AS lng FROM parsedemail_item a LEFT JOIN address b ON b.id=a.location_start_id WHERE b.timezone=1 GROUP BY b.latitude, b.longitude UNION SELECT COUNT(*) AS num, ROUND(c.latitude,2) AS lat, ROUND(c.longitude,2) AS lng FROM parsedemail_item a LEFT JOIN address c ON c.id=a.location_end_id WHERE c.timezone=1 GROUP BY c.latitude, c.longitude ) AS foo GROUP BY foo.lat,foo.lng ORDER BY total DESC";
|
||||
$r = pg_query($q);
|
||||
$top_locations = array();
|
||||
while ($f=pg_fetch_row($r)) {
|
||||
$top_locations[] = $f;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Heatmaps</title>
|
||||
<style>
|
||||
/* Always set the map height explicitly to define the size of the div
|
||||
* element that contains the map. */
|
||||
#map {
|
||||
height: 625px;
|
||||
}
|
||||
/* Optional: Makes the sample page fill the window. */
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#floating-panel {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 25%;
|
||||
z-index: 5;
|
||||
background-color: #fff;
|
||||
padding: 5px;
|
||||
border: 1px solid #999;
|
||||
text-align: center;
|
||||
font-family: 'Roboto','sans-serif';
|
||||
line-height: 30px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
#floating-panel {
|
||||
background-color: #fff;
|
||||
border: 1px solid #999;
|
||||
left: 25%;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
z-index: 5;
|
||||
}
|
||||
</style>
|
||||
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="floating-panel">
|
||||
<button onclick="toggleHeatmap()">Toggle Heatmap</button>
|
||||
<button onclick="changeGradient()">Change gradient</button>
|
||||
<button onclick="changeRadius()">Change radius</button>
|
||||
<button onclick="changeOpacity()">Change opacity</button>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
<script>
|
||||
|
||||
// This example requires the Visualization library. Include the libraries=visualization
|
||||
// parameter when you first load the API. For example:
|
||||
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=visualization">
|
||||
|
||||
var map, heatmap;
|
||||
|
||||
function initMap() {
|
||||
map = new google.maps.Map(document.getElementById('map'), {
|
||||
zoom: 13,
|
||||
center: {lat: <?=$center_lat?>, lng: <?=$center_lng?>},
|
||||
mapTypeId: 'roadmap'
|
||||
});
|
||||
|
||||
heatmap = new google.maps.visualization.HeatmapLayer({
|
||||
data: getPoints(),
|
||||
map: map
|
||||
});
|
||||
|
||||
var iconBase =
|
||||
'https://developers.google.com/maps/documentation/javascript/examples/full/images/';
|
||||
var icons = {
|
||||
parking: {
|
||||
icon: iconBase + 'parking_lot_maps.png'
|
||||
},
|
||||
library: {
|
||||
icon: iconBase + 'library_maps.png'
|
||||
},
|
||||
info: {
|
||||
icon: iconBase + 'info-i_maps.png'
|
||||
}
|
||||
};
|
||||
var icon = {
|
||||
url: 'pin-673-443159.png',
|
||||
size: new google.maps.Size(30, 40),
|
||||
scaledSize: new google.maps.Size(30, 40)
|
||||
};
|
||||
var features = getParkings();
|
||||
// Create markers.
|
||||
for (var i = 0; i < features.length; i++) {
|
||||
var marker = new google.maps.Marker({
|
||||
position: features[i].position,
|
||||
icon: icon, /*icons['parking'].icon,*/ /*features[i].type].icon,*/
|
||||
title: features[i].provider + '\r\n' + features[i].name + '\r\n' + features[i].description,
|
||||
map: map
|
||||
});
|
||||
};
|
||||
var toplocations = getTopLocations();
|
||||
for (var i = 0; i <toplocations.length; i++) {
|
||||
var marker = new google.maps.Marker({
|
||||
position: toplocations[i].position,
|
||||
icon: icons['library'].icon, /*features[i].type].icon,*/
|
||||
title: 'Total ' + toplocations[i].count,
|
||||
map: map
|
||||
});
|
||||
}
|
||||
customSettings();
|
||||
}
|
||||
|
||||
function toggleHeatmap() {
|
||||
heatmap.setMap(heatmap.getMap() ? null : map);
|
||||
}
|
||||
|
||||
function changeGradient() {
|
||||
var gradient = [
|
||||
'rgba(0, 255, 255, 0)',
|
||||
'rgba(0, 255, 255, 1)',
|
||||
'rgba(0, 191, 255, 1)',
|
||||
'rgba(0, 127, 255, 1)',
|
||||
'rgba(0, 63, 255, 1)',
|
||||
'rgba(0, 0, 255, 1)',
|
||||
'rgba(0, 0, 223, 1)',
|
||||
'rgba(0, 0, 191, 1)',
|
||||
'rgba(0, 0, 159, 1)',
|
||||
'rgba(0, 0, 127, 1)',
|
||||
'rgba(63, 0, 91, 1)',
|
||||
'rgba(127, 0, 63, 1)',
|
||||
'rgba(191, 0, 31, 1)',
|
||||
'rgba(255, 0, 0, 1)'
|
||||
]
|
||||
heatmap.set('gradient', heatmap.get('gradient') ? null : gradient);
|
||||
}
|
||||
|
||||
function changeRadius() {
|
||||
heatmap.set('radius', heatmap.get('radius') ? null : 30);
|
||||
}
|
||||
|
||||
function changeOpacity() {
|
||||
heatmap.set('opacity', heatmap.get('opacity') ? null : 0.2);
|
||||
}
|
||||
|
||||
// Heatmap data: 500 Points
|
||||
function getPoints() {
|
||||
return [
|
||||
<?
|
||||
$q = "SELECT location_start_lat,location_start_lng,location_end_lat,location_end_lng FROM parsedemail_item WHERE location_start_tz='Asia/Singapore'";
|
||||
$r = pg_query($q);
|
||||
while ($f=pg_fetch_row($r)) {
|
||||
if ($f[0]!==NULL && $f[1]!==NULL) {
|
||||
echo "new google.maps.LatLng(".$f[0].",".$f[1]."),\n";
|
||||
}
|
||||
if ($f[2]!==NULL && $f[3]!==NULL) {
|
||||
echo "new google.maps.LatLng(".$f[2].",".$f[3]."),\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
];
|
||||
}
|
||||
|
||||
function getParkings() {
|
||||
return [<?
|
||||
$handle = fopen("parking.txt", "r");
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
echo "{position: new google.maps.LatLng(".trim(str_replace('position: {lat:','',str_replace('lng:','',str_replace('},','',$line))))."),";
|
||||
echo " provider: \"\", name: \"\", description: \"\"},\n";
|
||||
}
|
||||
fclose($handle);?>];
|
||||
}
|
||||
<? /* ?>
|
||||
// Markers
|
||||
function getParkings2() {
|
||||
return [
|
||||
<?
|
||||
$radius = 200000;
|
||||
$url = $savvyext->cfgReadChar('microservices.catalog') . "/api/v1/parkings/?latitude=${center_lat}&longitude=${center_lng}&radius=${radius}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${catalogToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
$data = json_decode($body,true);
|
||||
if (is_array($data) && $data["count"]>0 && is_array($data["results"]) && count($data["results"])>0) {
|
||||
foreach ($data["results"] as $f) {
|
||||
// {"id":869,"provider":"Public","name":"Yellow Box","description":"Bukit Panjang Ring Road Block 542_YB","longitude":103.76393987440395,"latitude":1.3829555377103968,"radius":"1.000","image":null,"extra":{"RackCount":10,"ShelterIndicator":"Y"},"aproximate_scooter_availability":null}
|
||||
echo "{position: new google.maps.LatLng(".$f["latitude"].",".$f["longitude"]."), ";
|
||||
echo " provider: \"".$f["provider"]."\", name: \"".$f["name"]."\", description: \"".$f["description"]."\"},\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
];
|
||||
}
|
||||
<? */ ?>
|
||||
function getTopLocations() {
|
||||
return [
|
||||
<? $i=0; foreach ($top_locations as $f) { ?>
|
||||
{position: new google.maps.LatLng(<?=$f[1].",".$f[2]?>), count: <?=$f[0]?>},
|
||||
<? $i++; if ($i>10) break; } ?>
|
||||
];
|
||||
}
|
||||
</script>
|
||||
Showing <?php echo pg_num_rows($r); ?> result(s)
|
||||
<script async defer
|
||||
src="https://maps.googleapis.com/maps/api/js?key=<?=$googleKey?>&libraries=visualization&callback=initMap">
|
||||
</script>
|
||||
<script>
|
||||
// $(function() {
|
||||
// Handler for .ready() called.
|
||||
function customSettings() {
|
||||
heatmap.set('radius', 30);
|
||||
var gradient = [
|
||||
'rgba(0, 255, 255, 0)',
|
||||
'rgba(0, 255, 255, 1)',
|
||||
'rgba(0, 191, 255, 1)',
|
||||
'rgba(0, 127, 255, 1)',
|
||||
'rgba(0, 63, 255, 1)',
|
||||
'rgba(0, 0, 255, 1)',
|
||||
'rgba(0, 0, 223, 1)',
|
||||
'rgba(0, 0, 191, 1)',
|
||||
'rgba(0, 0, 159, 1)',
|
||||
'rgba(0, 0, 127, 1)',
|
||||
'rgba(63, 0, 91, 1)',
|
||||
'rgba(127, 0, 63, 1)',
|
||||
'rgba(191, 0, 31, 1)',
|
||||
'rgba(255, 0, 0, 1)'
|
||||
]
|
||||
heatmap.set('gradient', gradient);
|
||||
}
|
||||
//});
|
||||
/*
|
||||
<button onclick="toggleHeatmap()">Toggle Heatmap</button>
|
||||
<button onclick="changeGradient()">Change gradient</button>
|
||||
<button onclick="changeRadius()">Change radius</button>
|
||||
<button onclick="changeOpacity()">Change opacity</button>
|
||||
*/
|
||||
</script>
|
||||
<h1>Top locations</h1>
|
||||
<table>
|
||||
<tr><th>Total</th><th>Latitude</th><th>Longitude</th></tr>
|
||||
<? foreach ($top_locations as $f) { ?>
|
||||
<tr align=right>
|
||||
<td><?=$f[0]?></td>
|
||||
<td><?=$f[1]?></td>
|
||||
<td><?=$f[2]?></td>
|
||||
</tr>
|
||||
<? } ?>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
// vi:ts=2
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
require('../backend.php');
|
||||
require('config.php');
|
||||
|
||||
$member_id = 3;
|
||||
$members_id = "3,22";
|
||||
|
||||
$date1 = isset($_GET['date1'])?date("Y-m-d",strtotime($_GET['date1'])):date("Y-m-1");
|
||||
$date2 = isset($_GET['date2'])?date("Y-m-d",strtotime($_GET['date2'])):date("Y-m-d");
|
||||
|
||||
require('functions.php');
|
||||
require('ajax.php');
|
||||
require('templates/header.html.php');
|
||||
|
||||
$url = API_BASE_URL . "?date1=${date1}&date2=${date2}";
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'header' => "Accept: application/json\r\n" .
|
||||
"Authorization: Server-Token ${catalogToken}\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$body = file_get_contents($url, false, $context);
|
||||
$result = json_decode($body,true);
|
||||
|
||||
$data = array();
|
||||
if (is_array($result)) {
|
||||
if (isset($result["data"])) {
|
||||
$data = $result["data"];
|
||||
}
|
||||
if (isset($result["pub1"])) {
|
||||
$pub1 = $result["pub1"];
|
||||
}
|
||||
if (isset($result["pub2"])) {
|
||||
$pub2 = $result["pub2"];
|
||||
}
|
||||
if (isset($result["taxi"])) {
|
||||
$taxi = $result["taxi"];
|
||||
}
|
||||
if (isset($result["taxi0"])) {
|
||||
$taxi0 = $result["taxi0"];
|
||||
}
|
||||
if (isset($result["public_vs_rideshare"])) {
|
||||
$public_vs_rideshare = $result["public_vs_rideshare"];
|
||||
}
|
||||
/*
|
||||
if (isset($result[""])) {
|
||||
$ = $result[""];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
require_once('templates/header.js.php');
|
||||
?>
|
||||
<a href="csv.php">Download CSV</a><br/>
|
||||
<table width="100%">
|
||||
<col><col><col><col><col><col><col><col><col><col>
|
||||
<tr><th>Travel Date (Start)</th><th>End Time</th><th>Duration</th><th>Distance</th><th>Travel From</th><th>Travel To</th><th>Cost</th><th>Provider</th><th>Routes</th><th>Member ID</th></tr>
|
||||
<?
|
||||
$i = 0;
|
||||
foreach ($data as $f) {
|
||||
//echo "<tr onclick=\"document.getElementById('item".$f["id"]."').style.display='block';\" align=\"center\">";
|
||||
$str = "<tr onclick=\"$('#item".$f["id"]."').popup('show');\" align=\"center\">";
|
||||
$str.= "<td nowrap>".$f["travel_date"]."</td>";
|
||||
$f_end_date = getEndDateTime($f["travel_date"],$f["travel_date_end"],$f["duration"]);
|
||||
$str.= "<td nowrap>".$f_end_date."</td>";
|
||||
$f_duration = getDuration($f["duration"],$f["travel_date"],$f["travel_date_end"]);
|
||||
$str.= "<td>".$f_duration."</td>";
|
||||
$str.= "<td>".$f["distance"]."</td>";
|
||||
$str.= "<td align=\"left\">".$f["location_start"]."</td>";
|
||||
$str.= "<td align=\"left\">".$f["location_end"]."</td>";
|
||||
$str.= "<td align=\"right\" nowrap>".$f["cost_raw"]."</td>";
|
||||
$f_transport_provider = getTransportProvider($f["transport_provider_id"]);
|
||||
$str.= "<td>".$f_transport_provider."</td>";
|
||||
$str.= "<td>".$f["routes"]."</td>";
|
||||
$str.= "<td>".$f["member_id"]."</td>";
|
||||
$str.= "</tr>\n";
|
||||
echo $str;
|
||||
echo "<tr><td colspan=10></a><div id=\"item".$f["id"]."\" class=\"well\">";
|
||||
echo "<a href='#' onclick=\"$('#item".$f["id"]."').popup('hide');return false;\">click to hide (#".$f["tid"].")...</a>";
|
||||
$str = "<tr><td width='150'>".$f["travel_date"]."</td><td width='100' align=right>Duration: </td><td width='70'>".$f_duration."</td>";
|
||||
$str.= "<td width='70' align=right>Cost: </td><td width='50' nowrap>".$f["cost_raw"]."</td>";
|
||||
$str.= "<td width='50' align=right>Routes: </td><td width='50'>".$f["routes"]."</td><td>".$f["location_start"]."</td></tr>\n";
|
||||
$str.= "<tr><td width='150'>".$f_end_date."</td><td width='100' align=right>Distance: </td><td width='70'>".$f["distance"]."</td>";
|
||||
$str.= "<td width='70' align=right>Vendor:</td><td width='50' nowrap>".$f_transport_provider."</td>";
|
||||
$str.= "<td width='50' align=right>Member: </td><td width='50'>".$f["member_id"]."</td><td>".$f["location_end"]."</td></tr>\n";
|
||||
showDirections($f, true, $str);
|
||||
echo "</div>\n";
|
||||
echo "<script>$(document).ready(function () { $('#item".$f["id"]."').popup();});</script>\n";
|
||||
if ($i%10==0) {
|
||||
echo '<script>$("#progress").attr("data-progresspercent",'.(int)(50+50*$i/$total).');</script>' . "\n";
|
||||
}
|
||||
echo "</td></tr>\n";
|
||||
$i++;
|
||||
}
|
||||
echo "</table></div>";
|
||||
echo '<script>$("#loader").hide();$("#tabs").show();$("#dfilter").show();</script>' . "\n";
|
||||
echo "<script>$(document).ready(function() { $.fn.popup.defaults.pagecontainer = '#page'; }); </script>\n";
|
||||
|
||||
require('javascript.php');
|
||||
|
||||
echo "</div>\n</body>\n</html>";
|
||||
|
||||
// vi:ts=2
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
function loadRoutes(id) {
|
||||
var xmlhttp = ajaxFunction();
|
||||
if (xmlhttp!=null) {
|
||||
var url = '?ajax=routes&id='+id;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if(this.readyState==4 && this.status == 200) {
|
||||
document.getElementById('item'+id).innerHTML = this.responseText;
|
||||
} else if (this.readyState == 4 && this.status != 200) {
|
||||
alert('Error!');
|
||||
//alert(this.responseXML+'/'+this.responseText+'/'+this.statusText);
|
||||
//alert(this.getAllResponseHeaders());
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET",url,true);
|
||||
xmlhttp.send(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getQuote(id,sid) {
|
||||
var xmlhttp = ajaxFunction();
|
||||
if (xmlhttp!=null) {
|
||||
var url = '?ajax=quote&id='+id+'&sid='+sid;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if(this.readyState==4 && this.status == 200) {
|
||||
document.getElementById('quote_'+id+'_'+sid).innerHTML = this.responseText;
|
||||
} else if (this.readyState == 4 && this.status != 200) {
|
||||
alert('Error!');
|
||||
//alert(this.responseXML+'/'+this.responseText+'/'+this.statusText);
|
||||
//alert(this.getAllResponseHeaders());
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET",url,true);
|
||||
xmlhttp.send(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function loadTaxi(id) {
|
||||
var xmlhttp = ajaxFunction();
|
||||
if (xmlhttp!=null) {
|
||||
var url = '?ajax=taxi&id='+id;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if(this.readyState==4 && this.status == 200) {
|
||||
document.getElementById('taxi_'+id).innerHTML = this.responseText;
|
||||
} else if (this.readyState == 4 && this.status != 200) {
|
||||
alert('Error!');
|
||||
//alert(this.responseXML+'/'+this.responseText+'/'+this.statusText);
|
||||
//alert(this.getAllResponseHeaders());
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET",url,true);
|
||||
xmlhttp.send(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function quoteTaxi(id) {
|
||||
var xmlhttp = ajaxFunction();
|
||||
if (xmlhttp!=null) {
|
||||
var url = '?ajax=taxiquote&id='+id;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if(this.readyState==4 && this.status == 200) {
|
||||
document.getElementById('taxi_'+id).innerHTML = this.responseText;
|
||||
} else if (this.readyState == 4 && this.status != 200) {
|
||||
alert('Error!');
|
||||
//alert(this.responseXML+'/'+this.responseText+'/'+this.statusText);
|
||||
//alert(this.getAllResponseHeaders());
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET",url,true);
|
||||
xmlhttp.send(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function ajaxFunction()
|
||||
{
|
||||
if (window.XMLHttpRequest)
|
||||
{
|
||||
// code for IE7+, Firefox, Chrome, Opera, Safari
|
||||
return new XMLHttpRequest();
|
||||
}
|
||||
else if (window.ActiveXObject)
|
||||
{
|
||||
// code for IE6, IE5
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
else
|
||||
{
|
||||
alert("Your browser does not support XMLHTTP!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function showScooters(tid,id) {
|
||||
$('#item'+id).width('90%');
|
||||
$('#item'+id).height('90%');
|
||||
$('#overlay'+tid).html('<iframe src="scooters.php?id='+tid+'" width="95%" style="position: absolute; height: 85%; border: none"></iframe>');
|
||||
}
|
||||
function showScooters1(tid,id) {
|
||||
$('#item'+id+"_content_1").show();
|
||||
$('#item'+id+"_content_2").hide();
|
||||
$('#item'+id).width('90%');
|
||||
$('#item'+id).height('90%');
|
||||
$('#item'+id+"_content_1").width('100%');
|
||||
$('#item'+id+"_content_1").height('100%');
|
||||
$('#item'+id+"_content_1").html('<iframe src="scooters.php?id='+tid+'" width="95%" style="position: absolute; height: 85%; border: none"></iframe>');
|
||||
}
|
||||
function showScooters2(tid,id) {
|
||||
$('#item'+id+"_content_1").hide();
|
||||
$('#item'+id+"_content_2").show();
|
||||
$('#item'+id).width('90%');
|
||||
$('#item'+id).height('90%');
|
||||
$('#item'+id+"_content_2").width('100%');
|
||||
$('#item'+id+"_content_2").width('100%');
|
||||
//$('#overlay'+tid).html('<iframe src="scooters.php?id='+tid+'" width="95%" style="position: absolute; height: 85%; border: none"></iframe>');
|
||||
}
|
||||
// -->
|
||||
</script>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,223 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Trips Dashboard</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>
|
||||
<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;
|
||||
}
|
||||
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="?">
|
||||
<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">Distance vs. Money Spent</label>
|
||||
<label class="tv-tab" for="tv-tab-2">Duration vs. Money Spent</label>
|
||||
<label class="tv-tab" for="tv-tab-3">Rideshare vs. Public</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-3" name="tv-group" type="radio"/>
|
||||
<div class="tv-content">
|
||||
<div style="width:75%">
|
||||
<canvas id="canvas3"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<input class="tv-radio" id="tv-tab-4" name="tv-group" type="radio"/>
|
||||
<div class="tv-content">
|
||||
<script>
|
||||
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>
|
||||
@@ -0,0 +1,284 @@
|
||||
<script>
|
||||
var color = Chart.helpers.color;
|
||||
var dataSets1 = [];
|
||||
var dataSetTrends1 = [];
|
||||
var dataSets2 = [];
|
||||
var dataSetTrends2 = [];
|
||||
// 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]; ?>,
|
||||
y: <?php echo $f[1]; ?>});
|
||||
dataSetTrends1[1].push({
|
||||
x: <?php echo $f[0]; ?>,
|
||||
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]; ?>,
|
||||
y: <?php echo $f[1]; ?>});
|
||||
dataSetTrends2[1].push({
|
||||
x: <?php echo $f[0]; ?>,
|
||||
y: <?php echo $f[2]; ?>});
|
||||
<?php } ?>
|
||||
$("#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 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 } ?>
|
||||
$("#progress").attr("data-progresspercent",43);
|
||||
dataSets2[4] = []; dataSetTrends2[4] = [];
|
||||
<?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 } ?>
|
||||
$("#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: 'Public transit and walking',
|
||||
borderColor: window.chartColors.green,
|
||||
backgroundColor: color(window.chartColors.green).alpha(0.2).rgbString(),
|
||||
data: dataSets1[1]
|
||||
}, {
|
||||
label: 'Public transit and walking 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: 'Public transit and walking',
|
||||
borderColor: window.chartColors.green,
|
||||
backgroundColor: color(window.chartColors.green).alpha(0.2).rgbString(),
|
||||
data: dataSets2[1]
|
||||
}, {
|
||||
label: 'Public transit and walking 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]
|
||||
}]
|
||||
};
|
||||
|
||||
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: 'Distance vs. Money Spent'
|
||||
},
|
||||
}
|
||||
});
|
||||
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: 'Duration vs. Money Spent'
|
||||
},
|
||||
}
|
||||
});
|
||||
$('#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();
|
||||
});
|
||||
*/
|
||||
var dataSets3 = [];
|
||||
dataSets3[0] = [];
|
||||
dataSets3[1] = [];
|
||||
<?
|
||||
//var date = luxon.DateTime.fromRFC2822(initialDateStr);
|
||||
// 1491004800000
|
||||
// 0-2 - public (cost, dist, dur)
|
||||
// 3 - date
|
||||
// 4-6 - rideshare (cost, dist, dur)
|
||||
foreach ($public_vs_rideshare as $id=>$val) {
|
||||
if (count($val)!=7) continue;
|
||||
if ($val[6]<$val[2] && $val[6]>0.9*$val[2]) {
|
||||
?>/* <?= "($val[6]<$val[2] && $val[6]>".(0.1*$val[2]).")" ?> */
|
||||
dataSets3[1].push({
|
||||
p: '<?= "You could have saved ".($val[4]-$val[0])." dollars!\\r\\nwith a 10% longer trip\\r\\n" ?>',
|
||||
t: <?=strtotime($val[3]) ?>000, /* <?= $val[3] ?> */
|
||||
o: <?= $val[6] ?>, /* Open: rideshare duration */
|
||||
h: <?= max($val[6],$val[2]) ?>,
|
||||
l: <?= min($val[6],$val[2]) ?>,
|
||||
c: <?= $val[2] ?> /* Close: public duration */
|
||||
});
|
||||
<? } else { ?>
|
||||
dataSets3[0].push({
|
||||
p: '<?= $val[6]>$val[2]?"You could have saved ".($val[6]-$val[2])." minutes!\\r\\nand ".($val[4]-$val[0])." dollars!\\r\\n":""?>',
|
||||
t: <?=strtotime($val[3]) ?>000, /* <?= $val[3] ?> */
|
||||
o: <?= $val[6] ?>, /* Open: rideshare duration */
|
||||
h: <?= max($val[6],$val[2]) ?>,
|
||||
l: <?= min($val[6],$val[2]) ?>,
|
||||
c: <?= $val[2] ?> /* Close: public duration */
|
||||
});
|
||||
<? } } ?>
|
||||
|
||||
var ctx = document.getElementById('canvas3').getContext('2d');
|
||||
//ctx.canvas.width = 1000;
|
||||
//ctx.canvas.height = 850;
|
||||
var chart = new Chart(ctx, {
|
||||
type: 'candlestick',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: 'Rideshare vs. Public (trip time)',
|
||||
data: dataSets3[0],
|
||||
color: {
|
||||
up: '#01ff01',
|
||||
down: '#fe0000',
|
||||
unchanged: '#999',
|
||||
}
|
||||
},{
|
||||
label: 'Rideshare vs. Public (10% longer)',
|
||||
data: dataSets3[1],
|
||||
color: {
|
||||
up: '#ffdd01',
|
||||
down: '#fe0000',
|
||||
unchanged: '#999',
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- vi:ts=2
|
||||
-->
|
||||
Reference in New Issue
Block a user