New db import method
--- /dev/null
+++ b/.box
@@ -1,1 +1,5 @@
+shared_writable_dirs:
+ - /labs/tiles
+ - /lib/staticmaplite/cache
+php_extensions: [pgsql, pdo, pdo_pgsql, curl]
--- a/about.php
+++ b/about.php
@@ -17,6 +17,10 @@
Feedback encouraged; contact maxious@lambdacomplex.org<br />
<br />
Some icons by Joseph Wain / glyphish.com<br />
+Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
+, <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>)
+and Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>)
+<br />
<br />
<small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip.
Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty,
--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -26,6 +26,9 @@
#createuser transitdata -SDRP
#password transitdata
#psql -d transitdata -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"
+#psql -d transitdata -c "GRANT SELECT,INSERT ON TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
+#psql -d transitdata -c "GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
+##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
php /var/www/updatedb.php
wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
--- /dev/null
+++ b/css/local.css.php
@@ -1,1 +1,216 @@
-
+<?php
+ header('Content-type: text/css');
+ ob_start("compress");
+ function compress($buffer) {
+ /* remove comments */
+ $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
+ /* remove tabs, spaces, newlines, etc. */
+ $buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
+ return $buffer;
+ }
+
+echo '
+.ui-li-thumb, .ui-li-icon { position: relative; }
+
+ .ui-navbar {
+ width: 100%;
+ }
+ .ui-btn-inner {
+ white-space: normal !important;
+ }
+ .ui-li-heading {
+ white-space: normal !important;
+ }
+ .ui-listview-filter {
+ margin: 0 !important;
+ }
+ .ui-icon-navigation {
+ background-image: url(images/113-navigation.png);
+ background-position: 1px 0;
+ }
+ .ui-icon-beaker {
+ background-image: url(images/91-beaker-2.png);
+ background-position: 1px 0;
+ }
+ #footer {
+ text-size: 0.75em;
+ text-align: center;
+ }
+ body {
+ background-color: #F0F0F0;
+ }
+ #jqm-homeheader {
+ text-align: center;
+ }
+ .viaPoints {
+ display: none;
+ text-size: 0.2em;
+ }
+ .min-width-480px .viaPoints {
+ display: inline;
+ }
+ #extrainfo {
+ visibility: hidden;
+ display: none;
+ }
+ #servicewarning {
+ padding: 1em;
+ margin-bottom: 0.5em;
+ text-size: 0.2em;
+ background-color: #FF9;
+ -moz-border-radius: 15px;
+border-radius: 15px;
+ }
+
+
+#footer {
+clear:both;
+text-align:center;
+}
+ // source http://webaim.org/techniques/skipnav/
+ #skip a, #skip a:hover, #skip a:visited
+{
+position:absolute;
+left:0px;
+top:-500px;
+width:1px;
+height:1px;
+overflow:hidden;
+}
+
+#skip a:active, #skip a:focus
+{
+position:static;
+width:auto;
+height:auto;
+}';
+
+//if (false)
+ echo '
+// adaptive layout from jQuery Mobile docs site
+.type-interior .content-secondary {
+ border-right: 0;
+ border-left: 0;
+ margin: 10px -15px 0;
+ background: #fff;
+ border-top: 1px solid #ccc;
+}
+.type-home .ui-content {
+ margin-top: 5px;
+}
+.type-interior .ui-content {
+ padding-bottom: 0;
+}
+.content-secondary .ui-collapsible-contain {
+ padding: 10px 15px;
+
+}
+.content-secondary .ui-collapsible-heading {
+ margin: 0 0 30px;
+}
+.content-secondary .ui-collapsible-heading-collapsed,
+.content-secondary .ui-collapsible-content {
+ padding:0;
+ margin: 0;
+}
+@media all and (min-width: 650px){
+.content-secondary {
+ text-align: left;
+ float: left;
+ width: 45%;
+ background: none;
+ border-top: 0;
+ }
+ .content-secondary,
+ .type-interior .content-secondary {
+ margin: 30px 0 20px 2%;
+ padding: 20px 4% 0 0;
+ background: none;
+ }
+ .type-index .content-secondary {
+ padding: 0;
+ }
+ .type-index .content-secondary .ui-listview {
+ margin: 0;
+ }
+ .content-primary {
+ width: 45%;
+ float: right;
+ margin-top: 30px;
+ margin-right: 1%;
+ padding-right: 1%;
+ }
+ .content-primary ul:first-child {
+ margin-top: 0;
+ }
+
+ .type-interior .content-primary {
+ padding: 1.5em 6% 3em 0;
+ margin: 0;
+ }
+ /* fix up the collapsibles - expanded on desktop */
+ .content-secondary .ui-collapsible-heading {
+ display: none;
+ }
+ .content-secondary .ui-collapsible-contain {
+ margin:0;
+ }
+ .content-secondary .ui-collapsible-content {
+ display: block;
+ margin: 0;
+ padding: 0;
+ }
+ .type-interior .content-secondary .ui-li-divider {
+ padding-top: 1em;
+ padding-bottom: 1em;
+ }
+ .type-interior .content-secondary {
+ margin: 0;
+ padding: 0;
+ }
+}
+@media all and (min-width: 750px){
+ .type-home .ui-content,
+ .type-interior .ui-content {
+ background-position: 39%;
+ }
+ .content-secondary {
+ width: 34%;
+ }
+ .content-primary {
+ width: 56%;
+ padding-right: 1%;
+ }
+ .type-interior .ui-content {
+ background-position: 34%;
+ }
+}
+
+@media all and (min-width: 1200px){
+ .type-home .ui-content{
+ background-position: 38.5%;
+ }
+ .type-interior .ui-content {
+ background-position: 30%;
+ }
+ .content-secondary {
+ width: 30%;
+ padding-right:6%;
+ margin: 30px 0 20px 5%;
+ }
+ .type-interior .content-secondary {
+ margin: 0;
+ padding: 0;
+ }
+ .content-primary {
+ width: 50%;
+ margin-right: 5%;
+ padding-right: 3%;
+ }
+ .type-interior .content-primary {
+ width: 60%;
+ }
+}';
+ ob_end_flush();
+?>
+
--- a/dotcloud/postinstall
+++ b/dotcloud/postinstall
@@ -3,8 +3,8 @@
curl http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
-o /home/dotcloud/current/cbrfeed.zip
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
--O /tmp/Graph.obj
+curl http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
+-o /tmp/Graph.obj
#db setup
#curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz
--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -23,43 +23,42 @@
$url.= "&guid=ON";
return str_replace("&", "&", $url);
}
-
function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
{
-global $labsPath;
+ global $labsPath;
echo '
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
- <title>' . $pageTitle . '</title>
- <meta name="google-site-verification"
-content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />
- <link rel="stylesheet" href="'.$labsPath.'css/jquery-ui-1.8.12.custom.css" />';
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>' . $pageTitle . '</title>
+ <meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />
+<link rel="dns-prefetch" href="//code.jquery.com">
+<link rel="dns-prefetch" href="//ajax.googleapis.com">
+ <link rel="stylesheet" href="' . $labsPath . 'css/jquery-ui-1.8.12.custom.css" />';
if (isDebugServer()) {
- echo '<link rel="stylesheet" href="'.$labsPath.'css/jquery.mobile-1.0b1.css" />
-
- <script type="text/javascript" src="'.$labsPath.'js/jquery-1.6.1.min.js"></script>
- <script>$(document).bind("mobileinit", function(){
+ $jqmcss = $labsPath . 'css/jquery.mobile-1.0b1.css';
+ $jqjs = $labsPath . 'js/jquery-1.6.1.min.js';
+ $jqmjs = $labsPath . 'js/jquery.mobile-1.0b1.js';
+ }
+ else {
+ $jqmcss = "//code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css";
+ $jqjs = "//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js";
+ $jqmjs = "//code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js";
+ }
+ echo '<link rel="stylesheet" href="' . $jqmcss . '" />
+ <script src="'.$jqjs.'"></script>
+ <script>$(document).bind("mobileinit", function(){
$.mobile.ajaxEnabled = false;
});
-</script>
- <script type="text/javascript" src="'.$labsPath.'js/jquery.mobile-1.0b1.js"></script>';
- }
- else {
- echo '<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
- <script>$(document).bind("mobileinit", function(){
- $.mobile.ajaxEnabled = false;
-});
-</script>
- <script type="text/javascript" src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>';
- }
- echo '
- <script src="'.$labsPath.'js/jquery.ui.autocomplete.min.js"></script>
-<script src="'.$labsPath.'js/jquery.ui.core.min.js"></script>
-<script src="'.$labsPath.'js/jquery.ui.position.min.js"></script>
-<script src="'.$labsPath.'js/jquery.ui.widget.min.js"></script>
+</script>
+ <script src="'.$jqmjs.'"></script>
+
+<script src="' . $labsPath . 'js/jquery.ui.core.min.js"></script>
+<script src="' . $labsPath . 'js/jquery.ui.position.min.js"></script>
+<script src="' . $labsPath . 'js/jquery.ui.widget.min.js"></script>
+ <script src="' . $labsPath . 'js/jquery.ui.autocomplete.min.js"></script>
<script>
$(function() {
$( "#geolocate" ).autocomplete({
@@ -75,12 +74,9 @@
minLength: 2
});
});
- </script>
- ';
- echo '<style type="text/css">
-.ui-li-thumb, .ui-li-icon { position: relative; }';
-
-if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android')) echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,
+ </script>';
+ echo '<style type="text/css">';
+ if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android')) echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,
.ui-btn-down-b,.ui-bar-c,.ui-body-c,.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c,.ui-bar-c,.ui-body-d,
.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d,.ui-bar-d,.ui-body-e,.ui-btn-up-e,.ui-btn-hover-e,
.ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a {
@@ -88,208 +84,8 @@
box-shadow: none;
-webkit-box-shadow: none;
}';
-echo '
- .ui-navbar {
- width: 100%;
- }
- .ui-btn-inner {
- white-space: normal !important;
- }
- .ui-li-heading {
- white-space: normal !important;
- }
- .ui-listview-filter {
- margin: 0 !important;
- }
- .ui-icon-navigation {
- background-image: url('.$labsPath.'css/images/113-navigation.png);
- background-position: 1px 0;
- }
- .ui-icon-beaker {
- background-image: url('.$labsPath.'css/images/91-beaker-2.png);
- background-position: 1px 0;
- }
- #footer {
- text-size: 0.75em;
- text-align: center;
- }
- body {
- background-color: #F0F0F0;
- }
- #jqm-homeheader {
- text-align: center;
- }
- .viaPoints {
- display: none;
- text-size: 0.2em;
- }
- .min-width-480px .viaPoints {
- display: inline;
- }
- #extrainfo {
- visibility: hidden;
- display: none;
- }
- #servicewarning {
- padding: 1em;
- margin-bottom: 0.5em;
- text-size: 0.2em;
- background-color: #FF9;
- -moz-border-radius: 15px;
-border-radius: 15px;
- }
-
-
-#footer {
-clear:both;
-text-align:center;
-}
- // source http://webaim.org/techniques/skipnav/
- #skip a, #skip a:hover, #skip a:visited
-{
-position:absolute;
-left:0px;
-top:-500px;
-width:1px;
-height:1px;
-overflow:hidden;
-}
-
-#skip a:active, #skip a:focus
-{
-position:static;
-width:auto;
-height:auto;
-}
-
-
-// adaptive layout from jQuery Mobile docs site
-.type-interior .content-secondary {
- border-right: 0;
- border-left: 0;
- margin: 10px -15px 0;
- background: #fff;
- border-top: 1px solid #ccc;
-}
-.type-home .ui-content {
- margin-top: 5px;
-}
-.type-interior .ui-content {
- padding-bottom: 0;
-}
-.content-secondary .ui-collapsible-contain {
- padding: 10px 15px;
-
-}
-.content-secondary .ui-collapsible-heading {
- margin: 0 0 30px;
-}
-.content-secondary .ui-collapsible-heading-collapsed,
-.content-secondary .ui-collapsible-content {
- padding:0;
- margin: 0;
-}
-@media all and (min-width: 650px){
-.content-secondary {
- text-align: left;
- float: left;
- width: 45%;
- background: none;
- border-top: 0;
- }
- .content-secondary,
- .type-interior .content-secondary {
- margin: 30px 0 20px 2%;
- padding: 20px 4% 0 0;
- background: none;
- }
- .type-index .content-secondary {
- padding: 0;
- }
- .type-index .content-secondary .ui-listview {
- margin: 0;
- }
- .content-primary {
- width: 45%;
- float: right;
- margin-top: 30px;
- margin-right: 1%;
- padding-right: 1%;
- }
- .content-primary ul:first-child {
- margin-top: 0;
- }
-
- .type-interior .content-primary {
- padding: 1.5em 6% 3em 0;
- margin: 0;
- }
- /* fix up the collapsibles - expanded on desktop */
- .content-secondary .ui-collapsible-heading {
- display: none;
- }
- .content-secondary .ui-collapsible-contain {
- margin:0;
- }
- .content-secondary .ui-collapsible-content {
- display: block;
- margin: 0;
- padding: 0;
- }
- .type-interior .content-secondary .ui-li-divider {
- padding-top: 1em;
- padding-bottom: 1em;
- }
- .type-interior .content-secondary {
- margin: 0;
- padding: 0;
- }
-
-}
-@media all and (min-width: 750px){
- .type-home .ui-content,
- .type-interior .ui-content {
- background-position: 39%;
- }
- .content-secondary {
- width: 34%;
- }
- .content-primary {
- width: 56%;
- padding-right: 1%;
- }
- .type-interior .ui-content {
- background-position: 34%;
- }
-}
-
-@media all and (min-width: 1200px){
- .type-home .ui-content{
- background-position: 38.5%;
- }
- .type-interior .ui-content {
- background-position: 30%;
- }
- .content-secondary {
- width: 30%;
- padding-right:6%;
- margin: 30px 0 20px 5%;
- }
- .type-interior .content-secondary {
- margin: 0;
- padding: 0;
- }
- .content-primary {
- width: 50%;
- margin-right: 5%;
- padding-right: 3%;
- }
- .type-interior .content-primary {
- width: 60%;
- }
-}
-
-</style>';
+ echo '</style>';
+ echo '<link rel="stylesheet" href="' . $labsPath . 'css/local.css.php" />';
if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
echo '<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
@@ -346,28 +142,26 @@
<div data-role="header" data-position="inline">
<a href="' . (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "javascript:history.go(-1)") . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a>
<h1>' . $pageTitle . '</h1>
- <a href="'.$labsPath.'/index.php" data-icon="home" class="ui-btn-right">Home</a>
+ <a href="' . $labsPath . '/index.php" data-icon="home" class="ui-btn-right">Home</a>
</div><!-- /header -->
<a name="maincontent" id="maincontent"></a>
<div data-role="content"> ';
$overrides = getServiceOverride();
if ($overrides['service_id']) {
- if ($overrides['service_id'] == "noservice") {
- echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a
+ if ($overrides['service_id'] == "noservice") {
+ echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a
href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
- }
- else {
- echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
- }
+ }
+ else {
+ echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
}
}
-
+ }
}
function include_footer()
{
-
-global $labsPath;
- echo '<div id="footer"><a href="'.$labsPath.'about.php">About/Contact Us</a> <a href="'.$labsPath.'feedback.php">Feedback/Bug Report</a> <a href="'.$labsPath.'privacy.php">Privacy Policy</a>';
+ global $labsPath;
+ echo '<div id="footer"><a href="' . $labsPath . 'about.php">About/Contact Us</a> <a href="' . $labsPath . 'feedback.php">Feedback/Bug Report</a> <a href="' . $labsPath . 'privacy.php">Privacy Policy</a>';
echo '</div>';
if (isAnalyticsOn()) {
echo "<script> (function() {
@@ -380,17 +174,15 @@
})();</script>";
$googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>';
-
- }
- echo "\n</div></div></body></html>";
-}
-function timePlaceSettings($geolocate = false)
+ }
+ echo "\n</div></div></body></html>";
+}
+function placeSettings()
{
global $service_periods;
$geoerror = false;
- if ($geolocate == true) {
$geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
- }
+
echo '<div id="error">';
if ($geoerror) {
echo 'Sorry, but your location could not currently be detected.
@@ -399,27 +191,13 @@
}
echo '</div>';
echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '">
- <h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
+ <h3>Change Location...</h3>
<form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post">
<div class="ui-body">
<div data-role="fieldcontain">
<label for="geolocate"> Current Location: </label>
<input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a>
</div>
- <div data-role="fieldcontain">
- <label for="time"> Time: </label>
- <input type="time" name="time" id="time" value="' . (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:i")) . '"/>
- <a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getMinutes()));" . '">Current Time?</a>
- </div>
- <div data-role="fieldcontain">
- <label for="service_period"> Service Period: </label>
- <select name="service_period" id="service_period">';
- foreach ($service_periods as $service_period) {
- echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';
- }
- echo '</select>
- <a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>
- </div>
<input type="submit" value="Update"/>
</div></form>
--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -31,7 +31,8 @@
function isDebugServer()
{
- return !isset($_SERVER['SERVER_NAME']) || $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" ;
+ return php_sapi_name() == "cli" || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] ==
+"localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1") ;
}
include_once ("common-geo.inc.php");
--- a/include/db/servicealert-dao.inc.php
+++ b/include/db/servicealert-dao.inc.php
@@ -2,7 +2,7 @@
function getServiceOverride($date="") {
global $conn;
$query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
- debug($query,"database");
+ // debug($query,"database");
$query = $conn->prepare($query); // Create a prepared statement
$query->bindParam(":date", date("Ymd",($date != "" ? $date : time())));
$query->execute();
@@ -16,7 +16,7 @@
function getCurrentAlerts() {
global $conn;
$query = "SELECT * from servicealerts_alerts";
- debug($query, "database");
+ //debug($query, "database");
$query = $conn->prepare($query);
//if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence);
$query->execute();
@@ -29,10 +29,19 @@
function getInformedAlerts($id,$filter_class,$filter_id) {
global $conn;
- $query = "SELECT * from servicealerts_informed where servicealert_id = :id";
- debug($query, "database");
+ $query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id";
+
+ if ($filter_class != "" && $filter_id != "") {
+ $query .= " AND (informed_class = :informed_class OR informed_class = 'network') AND informed_id = :informed_id";
+
+ }
+ //debug($query, "database");
$query = $conn->prepare($query);
- $query->bindParam(":id", $id);
+ if ($filter_class != "" && $filter_id != "") {
+ $query->bindParam(":informed_class", $filter_class);
+ $query->bindParam(":informed_id", $filter_id);
+ }
+ $query->bindParam(":servicealert_id", $id);
$query->execute();
if (!$query) {
databaseError($conn->errorInfo());
--- a/include/db/trip-dao.inc.php
+++ b/include/db/trip-dao.inc.php
@@ -173,6 +173,22 @@
$r = $query->fetch(PDO::FETCH_ASSOC);
return $r['arrival_time'];
}
+function getTripEndTime($tripID)
+{
+ global $conn;
+ $query = "SELECT trip_id,max(arrival_time) as arrival_time from stop_times
+ WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ $r = $query->fetch(PDO::FETCH_ASSOC);
+ return $r['arrival_time'];
+}
function getActiveTrips($time)
{
global $conn;
--- a/index.php
+++ b/index.php
@@ -24,7 +24,6 @@
<li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
</ul>
<?php
-echo timePlaceSettings();
echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>';
include_footer(true)
?>
--- /dev/null
+++ b/js/LAB.min.js
@@ -1,1 +1,5 @@
-
+/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
+ v2.0.1 (c) Kyle Simpson
+ MIT License
+*/
+(function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a.charAt(0)!="/"){a=(c||"")+a}return b.test(a)?a:((a.charAt(0)=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){I(b);d=null}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){setTimeout(j,0)}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j]()}catch(err){}}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
--- a/js/flotr/flotr-0.2.0-alpha.js
+++ /dev/null
@@ -1,2 +1,1 @@
-//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.
-var Flotr={version:"0.2.0-alpha",author:"Bas Wenneker",website:"http://www.solutoire.com",_registeredTypes:{lines:"drawSeriesLines",points:"drawSeriesPoints",bars:"drawSeriesBars",candles:"drawSeriesCandles",pie:"drawSeriesPie"},register:function(A,B){Flotr._registeredTypes[A]=B+""},draw:function(B,D,A,C){C=C||Flotr.Graph;return new C(B,D,A)},getSeries:function(A){return A.collect(function(C){var B,C=(C.data)?Object.clone(C):{data:C};for(B=C.data.length-1;B>-1;--B){C.data[B][1]=(C.data[B][1]===null?null:parseFloat(C.data[B][1]))}return C})},merge:function(D,B){var A=B||{};for(var C in D){A[C]=(D[C]!=null&&typeof (D[C])=="object"&&!(D[C].constructor==Array||D[C].constructor==RegExp)&&!Object.isElement(D[C]))?Flotr.merge(D[C],B[C]):A[C]=D[C]}return A},getTickSize:function(E,D,A,B){var H=(A-D)/E;var G=Flotr.getMagnitude(H);var C=H/G;var F=10;if(C<1.5){F=1}else{if(C<2.25){F=2}else{if(C<3){F=((B==0)?2:2.5)}else{if(C<7.5){F=5}}}}return F*G},defaultTickFormatter:function(A){return A+""},defaultTrackFormatter:function(A){return"("+A.x+", "+A.y+")"},defaultPieLabelFormatter:function(A){return(A.fraction*100).toFixed(2)+"%"},getMagnitude:function(A){return Math.pow(10,Math.floor(Math.log(A)/Math.LN10))},toPixel:function(A){return Math.floor(A)+0.5},toRad:function(A){return -A*(Math.PI/180)},parseColor:function(D){if(D instanceof Flotr.Color){return D}var A,C=Flotr.Color;if((A=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]))}if((A=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]),parseFloat(A[4]))}if((A=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55)}if((A=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55,parseFloat(A[4]))}if((A=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(D))){return new C(parseInt(A[1],16),parseInt(A[2],16),parseInt(A[3],16))}if((A=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(D))){return new C(parseInt(A[1]+A[1],16),parseInt(A[2]+A[2],16),parseInt(A[3]+A[3],16))}var B=D.strip().toLowerCase();if(B=="transparent"){return new C(255,255,255,0)}return((A=C.lookupColors[B]))?new C(A[0],A[1],A[2]):false},extractColor:function(B){var A;do{A=B.getStyle("background-color").toLowerCase();if(!(A==""||A=="transparent")){break}B=B.up(0)}while(!B.nodeName.match(/^body$/i));return(A=="rgba(0, 0, 0, 0)")?"transparent":A}};Flotr.Graph=Class.create({initialize:function(B,C,A){this.el=$(B);if(!this.el){throw"The target container doesn't exist"}this.data=C;this.series=Flotr.getSeries(C);this.setOptions(A);this.lastMousePos={pageX:null,pageY:null};this.selection={first:{x:-1,y:-1},second:{x:-1,y:-1}};this.prevSelection=null;this.selectionInterval=null;this.ignoreClick=false;this.prevHit=null;this.constructCanvas();this.initEvents();this.findDataRanges();this.calculateTicks(this.axes.x);this.calculateTicks(this.axes.x2);this.calculateTicks(this.axes.y);this.calculateTicks(this.axes.y2);this.calculateSpacing();this.draw();this.insertLegend();if(this.options.spreadsheet.show){this.constructTabs()}},setOptions:function(B){var P={colors:["#00A8F0","#C0D800","#CB4B4B","#4DA74D","#9440ED"],title:null,subtitle:null,legend:{show:true,noColumns:1,labelFormatter:Prototype.K,labelBoxBorderColor:"#CCCCCC",labelBoxWidth:14,labelBoxHeight:10,labelBoxMargin:5,container:null,position:"nw",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:0,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},x2axis:{},yaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:90,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},y2axis:{titleAngle:270},points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#FFFFFF",fillOpacity:0.4},lines:{show:false,lineWidth:2,fill:false,fillColor:null,fillOpacity:0.4},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,horizontal:false,stacked:false},candles:{show:false,lineWidth:1,wickLineWidth:1,candleWidth:0.6,fill:true,upFillColor:"#00A8F0",downFillColor:"#CB4B4B",fillOpacity:0.5,barcharts:false},pie:{show:false,lineWidth:1,fill:true,fillColor:null,fillOpacity:0.6,explode:6,sizeRatio:0.6,startAngle:Math.PI/4,labelFormatter:Flotr.defaultPieLabelFormatter,pie3D:false,pie3DviewAngle:(Math.PI/2*0.8),pie3DspliceThickness:20},grid:{color:"#545454",backgroundColor:null,tickColor:"#DDDDDD",labelMargin:3,verticalLines:true,horizontalLines:true,outlineWidth:2},selection:{mode:null,color:"#B6D9FF",fps:20},mouse:{track:false,position:"se",relative:false,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:"#FF3F19",trackDecimals:1,sensibility:2,radius:3},shadowSize:4,defaultType:"lines",HtmlText:true,fontSize:7.5,spreadsheet:{show:false,tabGraphLabel:"Graph",tabDataLabel:"Data",toolbarDownload:"Download CSV",toolbarSelectAll:"Select all"}};P.x2axis=Object.extend(Object.clone(P.xaxis),P.x2axis);P.y2axis=Object.extend(Object.clone(P.yaxis),P.y2axis);this.options=Flotr.merge((B||{}),P);this.axes={x:{options:this.options.xaxis,n:1},x2:{options:this.options.x2axis,n:2},y:{options:this.options.yaxis,n:1},y2:{options:this.options.y2axis,n:2}};var H=[],C=[],K=this.series.length,N=this.series.length,D=this.options.colors,A=[],G=0,M,J,I,O,E;for(J=N-1;J>-1;--J){M=this.series[J].color;if(M!=null){--N;if(Object.isNumber(M)){H.push(M)}else{A.push(Flotr.parseColor(M))}}}for(J=H.length-1;J>-1;--J){N=Math.max(N,H[J]+1)}for(J=0;C.length<N;){M=(D.length==J)?new Flotr.Color(100,100,100):Flotr.parseColor(D[J]);var F=G%2==1?-1:1;var L=1+F*Math.ceil(G/2)*0.2;M.scale(L,L,L);C.push(M);if(++J>=D.length){J=0;++G}}for(J=0,I=0;J<K;++J){O=this.series[J];if(O.color==null){O.color=C[I++].toString()}else{if(Object.isNumber(O.color)){O.color=C[O.color].toString()}}if(!O.xaxis){O.xaxis=this.axes.x}if(O.xaxis==1){O.xaxis=this.axes.x}else{if(O.xaxis==2){O.xaxis=this.axes.x2}}if(!O.yaxis){O.yaxis=this.axes.y}if(O.yaxis==1){O.yaxis=this.axes.y}else{if(O.yaxis==2){O.yaxis=this.axes.y2}}O.lines=Object.extend(Object.clone(this.options.lines),O.lines);O.points=Object.extend(Object.clone(this.options.points),O.points);O.bars=Object.extend(Object.clone(this.options.bars),O.bars);O.candles=Object.extend(Object.clone(this.options.candles),O.candles);O.pie=Object.extend(Object.clone(this.options.pie),O.pie);O.mouse=Object.extend(Object.clone(this.options.mouse),O.mouse);if(O.shadowSize==null){O.shadowSize=this.options.shadowSize}}},constructCanvas:function(){var C=this.el,B,D,A;this.canvas=C.select(".flotr-canvas")[0];this.overlay=C.select(".flotr-overlay")[0];C.childElements().invoke("remove");C.setStyle({position:"relative",cursor:"default"});this.canvasWidth=C.getWidth();this.canvasHeight=C.getHeight();B={width:this.canvasWidth,height:this.canvasHeight};if(this.canvasWidth<=0||this.canvasHeight<=0){throw"Invalid dimensions for plot, width = "+this.canvasWidth+", height = "+this.canvasHeight}if(!this.canvas){D=this.canvas=new Element("canvas",B);D.className="flotr-canvas";D=D.writeAttribute("style","position:absolute;left:0px;top:0px;")}else{D=this.canvas.writeAttribute(B)}C.insert(D);if(Prototype.Browser.IE){D=window.G_vmlCanvasManager.initElement(D)}this.ctx=D.getContext("2d");if(!this.overlay){A=this.overlay=new Element("canvas",B);A.className="flotr-overlay";A=A.writeAttribute("style","position:absolute;left:0px;top:0px;")}else{A=this.overlay.writeAttribute(B)}C.insert(A);if(Prototype.Browser.IE){A=window.G_vmlCanvasManager.initElement(A)}this.octx=A.getContext("2d");if(window.CanvasText){CanvasText.enable(this.ctx);CanvasText.enable(this.octx);this.textEnabled=true}},getTextDimensions:function(F,C,B,D){if(!F){return{width:0,height:0}}if(!this.options.HtmlText&&this.textEnabled){var E=this.ctx.getTextBounds(F,C);return{width:E.width+2,height:E.height+6}}else{var A=this.el.insert('<div style="position:absolute;top:-10000px;'+B+'" class="'+D+' flotr-dummy-div">'+F+"</div>").select(".flotr-dummy-div")[0];dim=A.getDimensions();A.remove();return dim}},loadDataGrid:function(){if(this.seriesData){return this.seriesData}var A=this.series;var B=[];for(i=0;i<A.length;++i){A[i].data.each(function(D){var C=D[0],F=D[1];if(r=B.find(function(G){return G[0]==C})){r[i+1]=F}else{var E=[];E[0]=C;E[i+1]=F;B.push(E)}})}B=B.sortBy(function(C){return C[0]});return this.seriesData=B},showTab:function(B,C){var A="canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle";switch(B){case"graph":this.datagrid.up().hide();this.el.select(A).invoke("show");this.tabs.data.removeClassName("selected");this.tabs.graph.addClassName("selected");break;case"data":this.constructDataGrid();this.datagrid.up().show();this.el.select(A).invoke("hide");this.tabs.data.addClassName("selected");this.tabs.graph.removeClassName("selected");break}},constructTabs:function(){var A=new Element("div",{className:"flotr-tabs-group",style:"position:absolute;left:0px;top:"+this.canvasHeight+"px;width:"+this.canvasWidth+"px;"});this.el.insert({bottom:A});this.tabs={graph:new Element("div",{className:"flotr-tab selected",style:"float:left;"}).update(this.options.spreadsheet.tabGraphLabel),data:new Element("div",{className:"flotr-tab",style:"float:left;"}).update(this.options.spreadsheet.tabDataLabel)};A.insert(this.tabs.graph).insert(this.tabs.data);this.el.setStyle({height:this.canvasHeight+this.tabs.data.getHeight()+2+"px"});this.tabs.graph.observe("click",(function(){this.showTab("graph")}).bind(this));this.tabs.data.observe("click",(function(){this.showTab("data")}).bind(this))},constructDataGrid:function(){if(this.datagrid){return this.datagrid}var D,B,L=this.series,J=this.loadDataGrid();var K=this.datagrid=new Element("table",{className:"flotr-datagrid",style:"height:100px;"});var C=["<colgroup><col />"];var F=['<tr class="first-row">'];F.push("<th> </th>");for(D=0;D<L.length;++D){F.push('<th scope="col">'+(L[D].label||String.fromCharCode(65+D))+"</th>");C.push("<col />")}F.push("</tr>");for(B=0;B<J.length;++B){F.push("<tr>");for(D=0;D<L.length+1;++D){var M="td";var G=(J[B][D]!=null?Math.round(J[B][D]*100000)/100000:"");if(D==0){M="th";var I;if(this.options.xaxis.ticks){var E=this.options.xaxis.ticks.find(function(N){return N[0]==J[B][D]});if(E){I=E[1]}}else{I=this.options.xaxis.tickFormatter(G)}if(I){G=I}}F.push("<"+M+(M=="th"?' scope="row"':"")+">"+G+"</"+M+">")}F.push("</tr>")}C.push("</colgroup>");K.update(C.join("")+F.join(""));if(!Prototype.Browser.IE){K.select("td").each(function(N){N.observe("mouseover",function(O){N=O.element();var P=N.previousSiblings();K.select("th[scope=col]")[P.length-1].addClassName("hover");K.select("colgroup col")[P.length].addClassName("hover")});N.observe("mouseout",function(){K.select("colgroup col.hover, th.hover").each(function(O){O.removeClassName("hover")})})})}var H=new Element("div",{className:"flotr-datagrid-toolbar"}).insert(new Element("button",{type:"button",className:"flotr-datagrid-toolbar-button"}).update(this.options.spreadsheet.toolbarDownload).observe("click",this.downloadCSV.bind(this))).insert(new Element("button",{type:"button",className:"flotr-datagrid-toolbar-button"}).update(this.options.spreadsheet.toolbarSelectAll).observe("click",this.selectAllData.bind(this)));var A=new Element("div",{className:"flotr-datagrid-container",style:"left:0px;top:0px;width:"+this.canvasWidth+"px;height:"+this.canvasHeight+"px;overflow:auto;"});A.insert(H);K.wrap(A.hide());this.el.insert(A);return K},selectAllData:function(){if(this.tabs){var B,A,E,D,C=this.constructDataGrid();this.showTab("data");(function(){if((E=C.ownerDocument)&&(D=E.defaultView)&&D.getSelection&&E.createRange&&(B=window.getSelection())&&B.removeAllRanges){A=E.createRange();A.selectNode(C);B.removeAllRanges();B.addRange(A)}else{if(document.body&&document.body.createTextRange&&(A=document.body.createTextRange())){A.moveToElementText(C);A.select()}}}).defer();return true}else{return false}},downloadCSV:function(){var D,A='"x"',C=this.series,E=this.loadDataGrid();for(D=0;D<C.length;++D){A+='%09"'+(C[D].label||String.fromCharCode(65+D))+'"'}A+="%0D%0A";for(D=0;D<E.length;++D){if(this.options.xaxis.ticks){var B=this.options.xaxis.ticks.find(function(F){return F[0]==E[D][0]});if(B){E[D][0]=B[1]}}else{E[D][0]=this.options.xaxis.tickFormatter(E[D][0])}A+=E[D].join("%09")+"%0D%0A"}if(Prototype.Browser.IE){A=A.gsub("%09","\t").gsub("%0A","\n").gsub("%0D","\r");window.open().document.write(A)}else{window.open("data:text/csv,"+A)}},initEvents:function(){this.overlay.stopObserving();this.overlay.observe("mousedown",this.mouseDownHandler.bind(this));this.overlay.observe("mousemove",this.mouseMoveHandler.bind(this));this.overlay.observe("click",this.clickHandler.bind(this))},findDataRanges:function(){var J=this.series,G=this.axes;G.x.datamin=0;G.x.datamax=0;G.x2.datamin=0;G.x2.datamax=0;G.y.datamin=0;G.y.datamax=0;G.y2.datamin=0;G.y2.datamax=0;if(J.length>0){var C,A,D,H,F,B,I,E;for(C=0;C<J.length;++C){B=J[C].data,I=J[C].xaxis,E=J[C].yaxis;if(B.length>0&&!J[C].hide){if(!I.used){I.datamin=I.datamax=B[0][0]}if(!E.used){E.datamin=E.datamax=B[0][1]}I.used=true;E.used=true;for(D=B.length-1;D>-1;--D){H=B[D][0];if(H<I.datamin){I.datamin=H}else{if(H>I.datamax){I.datamax=H}}for(A=1;A<B[D].length;A++){F=B[D][A];if(F<E.datamin){E.datamin=F}else{if(F>E.datamax){E.datamax=F}}}}}}}this.findXAxesValues();this.calculateRange(G.x);this.extendXRangeIfNeededByBar(G.x);if(G.x2.used){this.calculateRange(G.x2);this.extendXRangeIfNeededByBar(G.x2)}this.calculateRange(G.y);this.extendYRangeIfNeededByBar(G.y);if(G.y2.used){this.calculateRange(G.y2);this.extendYRangeIfNeededByBar(G.y2)}},calculateRange:function(D){var F=D.options,C=F.min!=null?F.min:D.datamin,A=F.max!=null?F.max:D.datamax,E;if(A-C==0){var B=(A==0)?1:0.01;C-=B;A+=B}D.tickSize=Flotr.getTickSize(F.noTicks,C,A,F.tickDecimals);if(F.min==null){E=F.autoscaleMargin;if(E!=0){C-=D.tickSize*E;if(C<0&&D.datamin>=0){C=0}C=D.tickSize*Math.floor(C/D.tickSize)}}if(F.max==null){E=F.autoscaleMargin;if(E!=0){A+=D.tickSize*E;if(A>0&&D.datamax<=0){A=0}A=D.tickSize*Math.ceil(A/D.tickSize)}}D.min=C;D.max=A},extendXRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.axis==A&&(F.show||E.show)){if(!F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+I.bars.barWidth}if(F.stacked&&F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},extendYRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.yaxis==A&&F.show&&!I.hide){if(F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+F.barWidth}if(F.stacked&&!F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},findXAxesValues:function(){for(i=this.series.length-1;i>-1;--i){s=this.series[i];s.xaxis.values=s.xaxis.values||[];for(j=s.data.length-1;j>-1;--j){s.xaxis.values[s.data[j][0]]={}}}},calculateTicks:function(D){var B=D.options,E,H;D.ticks=[];if(B.ticks){var G=B.ticks,I,F;if(Object.isFunction(G)){G=G({min:D.min,max:D.max})}for(E=0;E<G.length;++E){I=G[E];if(typeof (I)=="object"){H=I[0];F=(I.length>1)?I[1]:B.tickFormatter(H)}else{H=I;F=B.tickFormatter(H)}D.ticks[E]={v:H,label:F}}}else{var A=D.tickSize*Math.ceil(D.min/D.tickSize),C;for(E=0;A+E*D.tickSize<=D.max;++E){H=A+E*D.tickSize;C=B.tickDecimals;if(C==null){C=1-Math.floor(Math.log(D.tickSize)/Math.LN10)}if(C<0){C=0}H=H.toFixed(C);D.ticks.push({v:H,label:B.tickFormatter(H)})}}},calculateSpacing:function(){var L=this.axes,N=this.options,H=this.series,D=N.grid.labelMargin,M=L.x,A=L.x2,J=L.y,K=L.y2,F=2,G,E,C,I;[M,A,J,K].each(function(P){var O="";if(P.options.showLabels){for(G=0;G<P.ticks.length;++G){C=P.ticks[G].label.length;if(C>O.length){O=P.ticks[G].label}}}P.maxLabel=this.getTextDimensions(O,{size:N.fontSize,angle:Flotr.toRad(P.options.labelsAngle)},"font-size:smaller;","flotr-grid-label");P.titleSize=this.getTextDimensions(P.options.title,{size:N.fontSize*1.2,angle:Flotr.toRad(P.options.titleAngle)},"font-weight:bold;","flotr-axis-title")},this);I=this.getTextDimensions(N.title,{size:N.fontSize*1.5},"font-size:1em;font-weight:bold;","flotr-title");this.titleHeight=I.height;I=this.getTextDimensions(N.subtitle,{size:N.fontSize},"font-size:smaller;","flotr-subtitle");this.subtitleHeight=I.height;if(N.show){F=Math.max(F,N.points.radius+N.points.lineWidth/2)}for(E=0;E<N.length;++E){if(H[E].points.show){F=Math.max(F,H[E].points.radius+H[E].points.lineWidth/2)}}var B=this.plotOffset={left:0,right:0,top:0,bottom:0};B.left=B.right=B.top=B.bottom=F;B.bottom+=(M.options.showLabels?(M.maxLabel.height+D):0)+(M.options.title?(M.titleSize.height+D):0);B.top+=(A.options.showLabels?(A.maxLabel.height+D):0)+(A.options.title?(A.titleSize.height+D):0)+this.subtitleHeight+this.titleHeight;B.left+=(J.options.showLabels?(J.maxLabel.width+D):0)+(J.options.title?(J.titleSize.width+D):0);B.right+=(K.options.showLabels?(K.maxLabel.width+D):0)+(K.options.title?(K.titleSize.width+D):0);B.top=Math.floor(B.top);this.plotWidth=this.canvasWidth-B.left-B.right;this.plotHeight=this.canvasHeight-B.bottom-B.top;M.scale=this.plotWidth/(M.max-M.min);A.scale=this.plotWidth/(A.max-A.min);J.scale=this.plotHeight/(J.max-J.min);K.scale=this.plotHeight/(K.max-K.min)},draw:function(){this.drawGrid();this.drawLabels();this.drawTitles();if(this.series.length){this.el.fire("flotr:beforedraw",[this.series,this]);for(var A=0;A<this.series.length;A++){if(!this.series[A].hide){this.drawSeries(this.series[A])}}}this.el.fire("flotr:afterdraw",[this.series,this])},tHoz:function(A,B){B=B||this.axes.x;return(A-B.min)*B.scale},tVert:function(B,A){A=A||this.axes.y;return this.plotHeight-(B-A.min)*A.scale},drawGrid:function(){var B,E=this.options,A=this.ctx;if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire("flotr:beforegrid",[this.axes.x,this.axes.y,E,this])}A.save();A.translate(this.plotOffset.left,this.plotOffset.top);if(E.grid.backgroundColor!=null){A.fillStyle=E.grid.backgroundColor;A.fillRect(0,0,this.plotWidth,this.plotHeight)}A.lineWidth=1;A.strokeStyle=E.grid.tickColor;A.beginPath();if(E.grid.verticalLines){for(var D=0;D<this.axes.x.ticks.length;++D){B=this.axes.x.ticks[D].v;if((B==this.axes.x.min||B==this.axes.x.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(Math.floor(this.tHoz(B))+A.lineWidth/2,0);A.lineTo(Math.floor(this.tHoz(B))+A.lineWidth/2,this.plotHeight)}}if(E.grid.horizontalLines){for(var C=0;C<this.axes.y.ticks.length;++C){B=this.axes.y.ticks[C].v;if((B==this.axes.y.min||B==this.axes.y.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(0,Math.floor(this.tVert(B))+A.lineWidth/2);A.lineTo(this.plotWidth,Math.floor(this.tVert(B))+A.lineWidth/2)}}A.stroke();if(E.grid.outlineWidth!=0){A.lineWidth=E.grid.outlineWidth;A.strokeStyle=E.grid.color;A.lineJoin="round";A.strokeRect(0,0,this.plotWidth,this.plotHeight)}A.restore();if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire("flotr:aftergrid",[this.axes.x,this.axes.y,E,this])}},drawLabels:function(){var C=0,D,B,E,F,G,J=this.options,I=this.ctx,H=this.axes;for(E=0;E<H.x.ticks.length;++E){if(H.x.ticks[E].label){++C}}B=this.plotWidth/C;if(!J.HtmlText&&this.textEnabled){var A={size:J.fontSize,adjustAlign:true};D=H.x;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="c";A.valign="t";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+this.plotHeight+J.grid.labelMargin,A)}D=H.x2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="c";A.valign="b";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+J.grid.labelMargin,A)}D=H.y;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="r";A.valign="m";I.drawText(G.label,this.plotOffset.left-J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A)}D=H.y2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="l";A.valign="m";I.drawText(G.label,this.plotOffset.left+this.plotWidth+J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A);I.save();I.strokeStyle=A.color;I.beginPath();I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D));I.stroke();I.restore()}}else{if(H.x.options.showLabels||H.x2.options.showLabels||H.y.options.showLabels||H.y2.options.showLabels){F=['<div style="font-size:smaller;color:'+J.grid.color+';" class="flotr-labels">'];D=H.x;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight+J.grid.labelMargin)+"px;left:"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+"px;width:"+B+"px;text-align:center;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.x2;if(D.options.showLabels&&D.used){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top-J.grid.labelMargin-D.maxLabel.height)+"px;left:"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+"px;width:"+B+"px;text-align:center;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.y;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+"px;left:0;width:"+(this.plotOffset.left-J.grid.labelMargin)+"px;text-align:right;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.y2;if(D.options.showLabels&&D.used){I.save();I.strokeStyle=D.options.color||J.grid.color;I.beginPath();for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+"px;right:0;width:"+(this.plotOffset.right-J.grid.labelMargin)+"px;text-align:left;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>");I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D))}I.stroke();I.restore()}F.push("</div>");this.el.insert(F.join(""))}}},drawTitles:function(){var D,C=this.options,F=C.grid.labelMargin,B=this.ctx,A=this.axes;if(!C.HtmlText&&this.textEnabled){var E={size:C.fontSize,color:C.grid.color,halign:"c"};if(C.subtitle){B.drawText(C.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,E)}E.weight=1.5;E.size*=1.5;if(C.title){B.drawText(C.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,E)}E.weight=1.8;E.size*=0.8;E.adjustAlign=true;if(A.x.options.title&&A.x.used){E.halign="c";E.valign="t";E.angle=Flotr.toRad(A.x.options.titleAngle);B.drawText(A.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+A.x.maxLabel.height+this.plotHeight+2*F,E)}if(A.x2.options.title&&A.x2.used){E.halign="c";E.valign="b";E.angle=Flotr.toRad(A.x2.options.titleAngle);B.drawText(A.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-A.x2.maxLabel.height-2*F,E)}if(A.y.options.title&&A.y.used){E.halign="r";E.valign="m";E.angle=Flotr.toRad(A.y.options.titleAngle);B.drawText(A.y.options.title,this.plotOffset.left-A.y.maxLabel.width-2*F,this.plotOffset.top+this.plotHeight/2,E)}if(A.y2.options.title&&A.y2.used){E.halign="l";E.valign="m";E.angle=Flotr.toRad(A.y2.options.titleAngle);B.drawText(A.y2.options.title,this.plotOffset.left+this.plotWidth+A.y2.maxLabel.width+2*F,this.plotOffset.top+this.plotHeight/2,E)}}else{D=['<div style="color:'+C.grid.color+';" class="flotr-titles">'];if(C.title){D.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+"px;font-size:1em;font-weight:bold;text-align:center;width:"+this.plotWidth+'px;" class="flotr-title">'+C.title+"</div>")}if(C.subtitle){D.push('<div style="position:absolute;top:'+this.titleHeight+"px;left:"+this.plotOffset.left+"px;font-size:smaller;text-align:center;width:"+this.plotWidth+'px;" class="flotr-subtitle">'+C.subtitle+"</div>")}D.push("</div>");D.push('<div class="flotr-axis-title" style="font-weight:bold;">');if(A.x.options.title&&A.x.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight+C.grid.labelMargin+A.x.titleSize.height)+"px;left:"+this.plotOffset.left+"px;width:"+this.plotWidth+'px;text-align:center;" class="flotr-axis-title">'+A.x.options.title+"</div>")}if(A.x2.options.title&&A.x2.used){D.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+"px;width:"+this.plotWidth+'px;text-align:center;" class="flotr-axis-title">'+A.x2.options.title+"</div>")}if(A.y.options.title&&A.y.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;left:0;text-align:right;" class="flotr-axis-title">'+A.y.options.title+"</div>")}if(A.y2.options.title&&A.y2.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;right:0;text-align:right;" class="flotr-axis-title">'+A.y2.options.title+"</div>")}D.push("</div>");this.el.insert(D.join(""))}},drawSeries:function(A){A=A||this.series;var C=false;for(var B in Flotr._registeredTypes){if(A[B]&&A[B].show){this[Flotr._registeredTypes[B]](A);C=true}}if(!C){this[Flotr._registeredTypes[this.options.defaultType]](A)}},plotLine:function(I,F){var O=this.ctx,A=I.xaxis,K=I.yaxis,J=this.tHoz.bind(this),M=this.tVert.bind(this),H=I.data;if(H.length<2){return }var E=J(H[0][0],A),D=M(H[0][1],K)+F;O.beginPath();O.moveTo(E,D);for(var G=0;G<H.length-1;++G){var C=H[G][0],N=H[G][1],B=H[G+1][0],L=H[G+1][1];if(N===null||L===null){continue}if(N<=L&&N<K.min){if(L<K.min){continue}C=(K.min-N)/(L-N)*(B-C)+C;N=K.min}else{if(L<=N&&L<K.min){if(N<K.min){continue}B=(K.min-N)/(L-N)*(B-C)+C;L=K.min}}if(N>=L&&N>K.max){if(L>K.max){continue}C=(K.max-N)/(L-N)*(B-C)+C;N=K.max}else{if(L>=N&&L>K.max){if(N>K.max){continue}B=(K.max-N)/(L-N)*(B-C)+C;L=K.max}}if(C<=B&&C<A.min){if(B<A.min){continue}N=(A.min-C)/(B-C)*(L-N)+N;C=A.min}else{if(B<=C&&B<A.min){if(C<A.min){continue}L=(A.min-C)/(B-C)*(L-N)+N;B=A.min}}if(C>=B&&C>A.max){if(B>A.max){continue}N=(A.max-C)/(B-C)*(L-N)+N;C=A.max}else{if(B>=C&&B>A.max){if(C>A.max){continue}L=(A.max-C)/(B-C)*(L-N)+N;B=A.max}}if(E!=J(C,A)||D!=M(N,K)+F){O.moveTo(J(C,A),M(N,K)+F)}E=J(B,A);D=M(L,K)+F;O.lineTo(E,D)}O.stroke()},plotLineArea:function(J,D){var S=J.data;if(S.length<2){return }var L,G=0,N=this.ctx,Q=J.xaxis,B=J.yaxis,E=this.tHoz.bind(this),M=this.tVert.bind(this),H=Math.min(Math.max(0,B.min),B.max),F=true;N.beginPath();for(var O=0;O<S.length-1;++O){var R=S[O][0],C=S[O][1],P=S[O+1][0],A=S[O+1][1];if(R<=P&&R<Q.min){if(P<Q.min){continue}C=(Q.min-R)/(P-R)*(A-C)+C;R=Q.min}else{if(P<=R&&P<Q.min){if(R<Q.min){continue}A=(Q.min-R)/(P-R)*(A-C)+C;P=Q.min}}if(R>=P&&R>Q.max){if(P>Q.max){continue}C=(Q.max-R)/(P-R)*(A-C)+C;R=Q.max}else{if(P>=R&&P>Q.max){if(R>Q.max){continue}A=(Q.max-R)/(P-R)*(A-C)+C;P=Q.max}}if(F){N.moveTo(E(R,Q),M(H,B)+D);F=false}if(C>=B.max&&A>=B.max){N.lineTo(E(R,Q),M(B.max,B)+D);N.lineTo(E(P,Q),M(B.max,B)+D);continue}else{if(C<=B.min&&A<=B.min){N.lineTo(E(R,Q),M(B.min,B)+D);N.lineTo(E(P,Q),M(B.min,B)+D);continue}}var I=R,K=P;if(C<=A&&C<B.min&&A>=B.min){R=(B.min-C)/(A-C)*(P-R)+R;C=B.min}else{if(A<=C&&A<B.min&&C>=B.min){P=(B.min-C)/(A-C)*(P-R)+R;A=B.min}}if(C>=A&&C>B.max&&A<=B.max){R=(B.max-C)/(A-C)*(P-R)+R;C=B.max}else{if(A>=C&&A>B.max&&C<=B.max){P=(B.max-C)/(A-C)*(P-R)+R;A=B.max}}if(R!=I){L=(C<=B.min)?L=B.min:B.max;N.lineTo(E(I,Q),M(L,B)+D);N.lineTo(E(R,Q),M(L,B)+D)}N.lineTo(E(R,Q),M(C,B)+D);N.lineTo(E(P,Q),M(A,B)+D);if(P!=K){L=(A<=B.min)?B.min:B.max;N.lineTo(E(K,Q),M(L,B)+D);N.lineTo(E(P,Q),M(L,B)+D)}G=Math.max(P,K)}N.lineTo(E(G,Q),M(H,B)+D);N.closePath();N.fill()},drawSeriesLines:function(C){C=C||this.series;var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);B.lineJoin="round";var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;var E=D/2+B.lineWidth/2;B.strokeStyle="rgba(0,0,0,0.1)";this.plotLine(C,E+A/2);B.strokeStyle="rgba(0,0,0,0.2)";this.plotLine(C,E);if(C.lines.fill){B.fillStyle="rgba(0,0,0,0.05)";this.plotLineArea(C,E+A/2)}}B.lineWidth=D;B.strokeStyle=C.color;if(C.lines.fill){B.fillStyle=C.lines.fillColor!=null?C.lines.fillColor:Flotr.parseColor(C.color).scale(null,null,null,C.lines.fillOpacity).toString();this.plotLineArea(C,0)}this.plotLine(C,0);B.restore()},drawSeriesPoints:function(C){var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;B.strokeStyle="rgba(0,0,0,0.1)";this.plotPointShadows(C,A/2+B.lineWidth/2,C.points.radius);B.strokeStyle="rgba(0,0,0,0.2)";this.plotPointShadows(C,B.lineWidth/2,C.points.radius)}B.lineWidth=C.points.lineWidth;B.strokeStyle=C.color;B.fillStyle=C.points.fillColor!=null?C.points.fillColor:C.color;this.plotPoints(C,C.points.radius,C.points.fill);B.restore()},plotPoints:function(C,E,I){var A=C.xaxis,F=C.yaxis,J=this.ctx,D,B=C.data;for(D=B.length-1;D>-1;--D){var H=B[D][0],G=B[D][1];if(H<A.min||H>A.max||G<F.min||G>F.max){continue}J.beginPath();J.arc(this.tHoz(H,A),this.tVert(G,F),E,0,2*Math.PI,true);if(I){J.fill()}J.stroke()}},plotPointShadows:function(D,B,F){var A=D.xaxis,G=D.yaxis,J=this.ctx,E,C=D.data;for(E=C.length-1;E>-1;--E){var I=C[E][0],H=C[E][1];if(I<A.min||I>A.max||H<G.min||H>G.max){continue}J.beginPath();J.arc(this.tHoz(I,A),this.tVert(H,G)+B,F,0,Math.PI,false);J.stroke()}},drawSeriesBars:function(B){var A=this.ctx,D=B.bars.barWidth,C=Math.min(B.bars.lineWidth,D);A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin="miter";A.lineWidth=C;A.strokeStyle=B.color;this.plotBarsShadows(B,D,0,B.bars.fill);if(B.bars.fill){A.fillStyle=B.bars.fillColor!=null?B.bars.fillColor:Flotr.parseColor(B.color).scale(null,null,null,B.bars.fillOpacity).toString()}this.plotBars(B,D,0,B.bars.fill);A.restore()},plotBars:function(K,N,D,Q){var U=K.data;if(U.length<1){return }var S=K.xaxis,B=K.yaxis,P=this.ctx,F=this.tHoz.bind(this),O=this.tVert.bind(this);for(var R=0;R<U.length;R++){var J=U[R][0],I=U[R][1];var E=true,L=true,A=true;var H=0;if(K.bars.stacked){S.values.each(function(W,V){if(V==J){H=W.stack||0;W.stack=H+I}})}if(K.bars.horizontal){var C=H,T=J+H,G=I,M=I+N}else{var C=J,T=J+N,G=H,M=I+H}if(T<S.min||C>S.max||M<B.min||G>B.max){continue}if(C<S.min){C=S.min;E=false}if(T>S.max){T=S.max;if(S.lastSerie!=K&&K.bars.horizontal){L=false}}if(G<B.min){G=B.min}if(M>B.max){M=B.max;if(B.lastSerie!=K&&!K.bars.horizontal){L=false}}if(Q){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P.lineTo(F(C,S),O(M,B)+D);P.lineTo(F(T,S),O(M,B)+D);P.lineTo(F(T,S),O(G,B)+D);P.fill()}if(K.bars.lineWidth!=0&&(E||A||L)){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P[E?"lineTo":"moveTo"](F(C,S),O(M,B)+D);P[L?"lineTo":"moveTo"](F(T,S),O(M,B)+D);P[A?"lineTo":"moveTo"](F(T,S),O(G,B)+D);P.stroke()}}},plotBarsShadows:function(I,K,C){var T=I.data;if(T.length<1){return }var R=I.xaxis,A=I.yaxis,P=this.ctx,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var Q=0;Q<T.length;Q++){var H=T[Q][0],G=T[Q][1];var E=0;if(I.bars.stacked){R.values.each(function(V,U){if(U==H){E=V.stackShadow||0;V.stackShadow=E+G}})}if(I.bars.horizontal){var B=E,S=H+E,F=G,J=G+K}else{var B=H,S=H+K,F=E,J=G+E}if(S<R.min||B>R.max||J<A.min||F>A.max){continue}if(B<R.min){B=R.min}if(S>R.max){S=R.max}if(F<A.min){F=A.min}if(J>A.max){J=A.max}var O=D(S,R)-D(B,R)-((D(S,R)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(F,A)-M(J,A)-((M(F,A)+N<=this.plotHeight)?0:N));P.fillStyle="rgba(0,0,0,0.05)";P.fillRect(Math.min(D(B,R)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesCandles:function(B){var A=this.ctx,C=B.candles.candleWidth;A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin="miter";A.lineWidth=B.candles.lineWidth;this.plotCandlesShadows(B,C/2);this.plotCandles(B,C/2);A.restore()},plotCandles:function(K,D){var W=K.data;if(W.length<1){return }var T=K.xaxis,B=K.yaxis,P=this.ctx,E=this.tHoz.bind(this),O=this.tVert.bind(this);for(var S=0;S<W.length;S++){var U=W[S],J=U[0],L=U[1],I=U[2],X=U[3],N=U[4];var C=J,V=J+K.candles.candleWidth,G=Math.max(B.min,X),M=Math.min(B.max,I),A=Math.max(B.min,Math.min(L,N)),R=Math.min(B.max,Math.max(L,N));if(V<T.min||C>T.max||M<B.min||G>B.max){continue}var Q=K.candles[L>N?"downFillColor":"upFillColor"];if(K.candles.fill&&!K.candles.barcharts){P.fillStyle=Flotr.parseColor(Q).scale(null,null,null,K.candles.fillOpacity).toString();P.fillRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B))}if(K.candles.lineWidth||K.candles.wickLineWidth){var J,H,F=(K.candles.wickLineWidth%2)/2;J=Math.floor(E((C+V)/2),T)+F;P.save();P.strokeStyle=Q;P.lineWidth=K.candles.wickLineWidth;P.lineCap="butt";if(K.candles.barcharts){P.beginPath();P.moveTo(J,Math.floor(O(M,B)+D));P.lineTo(J,Math.floor(O(G,B)+D));H=Math.floor(O(L,B)+D)+0.5;P.moveTo(Math.floor(E(C,T))+F,H);P.lineTo(J,H);H=Math.floor(O(N,B)+D)+0.5;P.moveTo(Math.floor(E(V,T))+F,H);P.lineTo(J,H)}else{P.strokeRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B));P.beginPath();P.moveTo(J,Math.floor(O(R,B)+D));P.lineTo(J,Math.floor(O(M,B)+D));P.moveTo(J,Math.floor(O(A,B)+D));P.lineTo(J,Math.floor(O(G,B)+D))}P.stroke();P.restore()}}},plotCandlesShadows:function(H,C){var T=H.data;if(T.length<1||H.candles.barcharts){return }var Q=H.xaxis,A=H.yaxis,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var P=0;P<T.length;P++){var R=T[P],G=R[0],I=R[1],F=R[2],U=R[3],K=R[4];var B=G,S=G+H.candles.candleWidth,E=Math.max(A.min,Math.min(I,K)),J=Math.min(A.max,Math.max(I,K));if(S<Q.min||B>Q.max||J<A.min||E>A.max){continue}var O=D(S,Q)-D(B,Q)-((D(S,Q)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(E,A)-M(J,A)-((M(E,A)+N<=this.plotHeight)?0:N));this.ctx.fillStyle="rgba(0,0,0,0.05)";this.ctx.fillRect(Math.min(D(B,Q)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesPie:function(G){if(!this.options.pie.drawn){var K=this.ctx,C=this.options,E=G.pie.lineWidth,I=G.shadowSize,R=G.data,D=(Math.min(this.canvasWidth,this.canvasHeight)*G.pie.sizeRatio)/2,H=[];var L=1;var P=Math.sin(G.pie.viewAngle)*G.pie.spliceThickness/L;var M={size:C.fontSize*1.2,color:C.grid.color,weight:1.5};var Q={x:(this.canvasWidth+this.plotOffset.left)/2,y:(this.canvasHeight-this.plotOffset.bottom)/2};var O=this.series.collect(function(T,S){if(T.pie.show){return{name:(T.label||T.data[0][1]),value:[S,T.data[0][1]],explode:T.pie.explode}}});var B=O.pluck("value").pluck(1).inject(0,function(S,T){return S+T});var F=0,N=G.pie.startAngle,J=0;var A=O.collect(function(S){N+=F;J=parseFloat(S.value[1]);F=J/B;return{name:S.name,fraction:F,x:S.value[0],y:J,explode:S.explode,startAngle:2*N*Math.PI,endAngle:2*(N+F)*Math.PI}});K.save();if(I>0){A.each(function(V){var S=(V.startAngle+V.endAngle)/2;var T=Q.x+Math.cos(S)*V.explode+I;var U=Q.y+Math.sin(S)*V.explode+I;this.plotSlice(T,U,D,V.startAngle,V.endAngle,false,L);K.fillStyle="rgba(0,0,0,0.1)";K.fill()},this)}if(C.HtmlText){H=['<div style="color:'+this.options.grid.color+'" class="flotr-labels">']}A.each(function(c,X){var W=(c.startAngle+c.endAngle)/2;var V=C.colors[X];var Y=Q.x+Math.cos(W)*c.explode;var U=Q.y+Math.sin(W)*c.explode;this.plotSlice(Y,U,D,c.startAngle,c.endAngle,false,L);if(G.pie.fill){K.fillStyle=Flotr.parseColor(V).scale(null,null,null,G.pie.fillOpacity).toString();K.fill()}K.lineWidth=E;K.strokeStyle=V;K.stroke();var b=C.pie.labelFormatter(c);var S=(Math.cos(W)<0);var a=Y+Math.cos(W)*(G.pie.explode+D);var Z=U+Math.sin(W)*(G.pie.explode+D);if(c.fraction&&b){if(C.HtmlText){var T="position:absolute;top:"+(Z-5)+"px;";if(S){T+="right:"+(this.canvasWidth-a)+"px;text-align:right;"}else{T+="left:"+a+"px;text-align:left;"}H.push('<div style="'+T+'" class="flotr-grid-label">'+b+"</div>")}else{M.halign=S?"r":"l";K.drawText(b,a,Z+M.size/2,M)}}},this);if(C.HtmlText){H.push("</div>");this.el.insert(H.join(""))}K.restore();C.pie.drawn=true}},plotSlice:function(B,H,A,E,D,F,G){var C=this.ctx;G=G||1;C.save();C.scale(1,G);C.beginPath();C.moveTo(B,H);C.arc(B,H,A,E,D,F);C.lineTo(B,H);C.closePath();C.restore()},plotPie:function(){},insertLegend:function(){if(!this.options.legend.show){return }var H=this.series,I=this.plotOffset,B=this.options,b=[],A=false,O=this.ctx,R;var Q=H.findAll(function(c){return(c.label&&!c.hide)}).size();if(Q){if(!B.HtmlText&&this.textEnabled){var T={size:B.fontSize*1.1,color:B.grid.color};var M=B.legend.position,N=B.legend.margin,L=B.legend.labelBoxWidth,Z=B.legend.labelBoxHeight,S=B.legend.labelBoxMargin,W=I.left+N,U=I.top+N;var a=0;for(R=H.length-1;R>-1;--R){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);a=Math.max(a,O.measureText(E,T))}var K=Math.round(L+S*3+a),C=Math.round(Q*(S+Z)+S);if(M.charAt(0)=="s"){U=I.top+this.plotHeight-(N+C)}if(M.charAt(1)=="e"){W=I.left+this.plotWidth-(N+K)}var P=Flotr.parseColor(B.legend.backgroundColor||"rgb(240,240,240)").scale(null,null,null,B.legend.backgroundOpacity||0.1).toString();O.fillStyle=P;O.fillRect(W,U,K,C);O.strokeStyle=B.legend.labelBoxBorderColor;O.strokeRect(Flotr.toPixel(W),Flotr.toPixel(U),K,C);var G=W+S;var F=U+S;for(R=0;R<H.length;R++){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);O.fillStyle=H[R].color;O.fillRect(G,F,L-1,Z-1);O.strokeStyle=B.legend.labelBoxBorderColor;O.lineWidth=1;O.strokeRect(Math.ceil(G)-1.5,Math.ceil(F)-1.5,L+2,Z+2);O.drawText(E,G+L+S,F+(Z+T.size-O.fontDescent(T))/2,T);F+=Z+S}}else{for(R=0;R<H.length;++R){if(!H[R].label||H[R].hide){continue}if(R%B.legend.noColumns==0){b.push(A?"</tr><tr>":"<tr>");A=true}var E=B.legend.labelFormatter(H[R].label);b.push('<td class="flotr-legend-color-box"><div style="border:1px solid '+B.legend.labelBoxBorderColor+';padding:1px"><div style="width:'+B.legend.labelBoxWidth+"px;height:"+B.legend.labelBoxHeight+"px;background-color:"+H[R].color+'"></div></div></td><td class="flotr-legend-label">'+E+"</td>")}if(A){b.push("</tr>")}if(b.length>0){var V='<table style="font-size:smaller;color:'+B.grid.color+'">'+b.join("")+"</table>";if(B.legend.container!=null){$(B.legend.container).update(V)}else{var D="";var M=B.legend.position,N=B.legend.margin;if(M.charAt(0)=="n"){D+="top:"+(N+I.top)+"px;"}else{if(M.charAt(0)=="s"){D+="bottom:"+(N+I.bottom)+"px;"}}if(M.charAt(1)=="e"){D+="right:"+(N+I.right)+"px;"}else{if(M.charAt(1)=="w"){D+="left:"+(N+I.left)+"px;"}}var J=this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;'+D+'">'+V+"</div>").select("div.flotr-legend").first();if(B.legend.backgroundOpacity!=0){var Y=B.legend.backgroundColor;if(Y==null){var X=(B.grid.backgroundColor!=null)?B.grid.backgroundColor:Flotr.extractColor(J);Y=Flotr.parseColor(X).adjust(null,null,null,1).toString()}this.el.insert('<div class="flotr-legend-bg" style="position:absolute;width:'+J.getWidth()+"px;height:"+J.getHeight()+"px;"+D+"background-color:"+Y+';"> </div>').select("div.flotr-legend-bg").first().setStyle({opacity:B.legend.backgroundOpacity})}}}}}},getEventPosition:function(C){var G=this.overlay.cumulativeOffset(),F=(C.pageX-G.left-this.plotOffset.left),E=(C.pageY-G.top-this.plotOffset.top),D=0,B=0;if(C.pageX==null&&C.clientX!=null){var H=document.documentElement,A=document.body;D=C.clientX+(H&&H.scrollLeft||A.scrollLeft||0);B=C.clientY+(H&&H.scrollTop||A.scrollTop||0)}else{D=C.pageX;B=C.pageY}return{x:this.axes.x.min+F/this.axes.x.scale,x2:this.axes.x2.min+F/this.axes.x2.scale,y:this.axes.y.max-E/this.axes.y.scale,y2:this.axes.y2.max-E/this.axes.y2.scale,relX:F,relY:E,absX:D,absY:B}},clickHandler:function(A){if(this.ignoreClick){this.ignoreClick=false;return }this.el.fire("flotr:click",[this.getEventPosition(A),this])},mouseMoveHandler:function(A){var B=this.getEventPosition(A);this.lastMousePos.pageX=B.absX;this.lastMousePos.pageY=B.absY;if(this.selectionInterval==null&&(this.options.mouse.track||this.series.any(function(C){return C.mouse&&C.mouse.track}))){this.hit(B)}this.el.fire("flotr:mousemove",[A,B,this])},mouseDownHandler:function(C){if(C.isRightClick()){C.stop();var B=this.overlay;B.hide();function A(){B.show();$(document).stopObserving("mousemove",A)}$(document).observe("mousemove",A);return }if(!this.options.selection.mode||!C.isLeftClick()){return }this.setSelectionPos(this.selection.first,C);if(this.selectionInterval!=null){clearInterval(this.selectionInterval)}this.lastMousePos.pageX=null;this.selectionInterval=setInterval(this.updateSelection.bind(this),1000/this.options.selection.fps);this.mouseUpHandler=this.mouseUpHandler.bind(this);$(document).observe("mouseup",this.mouseUpHandler)},fireSelectEvent:function(){var A=this.axes,F=this.selection,C=(F.first.x<=F.second.x)?F.first.x:F.second.x,B=(F.first.x<=F.second.x)?F.second.x:F.first.x,E=(F.first.y>=F.second.y)?F.first.y:F.second.y,D=(F.first.y>=F.second.y)?F.second.y:F.first.y;C=A.x.min+C/A.x.scale;B=A.x.min+B/A.x.scale;E=A.y.max-E/A.y.scale;D=A.y.max-D/A.y.scale;this.el.fire("flotr:select",[{x1:C,y1:E,x2:B,y2:D},this])},mouseUpHandler:function(A){$(document).stopObserving("mouseup",this.mouseUpHandler);A.stop();if(this.selectionInterval!=null){clearInterval(this.selectionInterval);this.selectionInterval=null}this.setSelectionPos(this.selection.second,A);this.clearSelection();if(this.selectionIsSane()){this.drawSelection();this.fireSelectEvent();this.ignoreClick=true}},setSelectionPos:function(D,B){var A=this.options,C=$(this.overlay).cumulativeOffset();if(A.selection.mode.indexOf("x")==-1){D.x=(D==this.selection.first)?0:this.plotWidth}else{D.x=B.pageX-C.left-this.plotOffset.left;D.x=Math.min(Math.max(0,D.x),this.plotWidth)}if(A.selection.mode.indexOf("y")==-1){D.y=(D==this.selection.first)?0:this.plotHeight}else{D.y=B.pageY-C.top-this.plotOffset.top;D.y=Math.min(Math.max(0,D.y),this.plotHeight)}},updateSelection:function(){if(this.lastMousePos.pageX==null){return }this.setSelectionPos(this.selection.second,this.lastMousePos);this.clearSelection();if(this.selectionIsSane()){this.drawSelection()}},clearSelection:function(){if(this.prevSelection==null){return }var G=this.prevSelection,E=this.octx,C=this.plotOffset,A=Math.min(G.first.x,G.second.x),F=Math.min(G.first.y,G.second.y),B=Math.abs(G.second.x-G.first.x),D=Math.abs(G.second.y-G.first.y);E.clearRect(A+C.left-E.lineWidth,F+C.top-E.lineWidth,B+E.lineWidth*2,D+E.lineWidth*2);this.prevSelection=null},setSelection:function(G){var B=this.options,H=this.axes.x,A=this.axes.y,F=yaxis.scale,D=xaxis.scale,E=B.selection.mode.indexOf("x")!=-1,C=B.selection.mode.indexOf("y")!=-1;this.clearSelection();this.selection.first.y=E?0:(A.max-G.y1)*F;this.selection.second.y=E?this.plotHeight:(A.max-G.y2)*F;this.selection.first.x=C?0:(G.x1-H.min)*D;this.selection.second.x=C?this.plotWidth:(G.x2-H.min)*D;this.drawSelection();this.fireSelectEvent()},drawSelection:function(){var C=this.prevSelection,F=this.selection,H=this.octx,I=this.options,A=this.plotOffset;if(C!=null&&F.first.x==C.first.x&&F.first.y==C.first.y&&F.second.x==C.second.x&&F.second.y==C.second.y){return }H.strokeStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.8).toString();H.lineWidth=1;H.lineJoin="round";H.fillStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.4).toString();this.prevSelection={first:{x:F.first.x,y:F.first.y},second:{x:F.second.x,y:F.second.y}};var E=Math.min(F.first.x,F.second.x),D=Math.min(F.first.y,F.second.y),G=Math.abs(F.second.x-F.first.x),B=Math.abs(F.second.y-F.first.y);H.fillRect(E+A.left,D+A.top,G,B);H.strokeRect(E+A.left,D+A.top,G,B)},selectionIsSane:function(){var A=this.selection;return Math.abs(A.second.x-A.first.x)>=5&&Math.abs(A.second.y-A.first.y)>=5},clearHit:function(){if(this.prevHit){var B=this.options,A=this.plotOffset,C=this.prevHit;this.octx.clearRect(this.tHoz(C.x)+A.left-B.points.radius*2,this.tVert(C.y)+A.top-B.points.radius*2,B.points.radius*3+B.points.lineWidth*3,B.points.radius*3+B.points.lineWidth*3);this.prevHit=null}},hit:function(I){var G=this.series,C=this.options,R=this.prevHit,H=this.plotOffset,D=this.octx,S,A,M,Q,L={dist:Number.MAX_VALUE,x:null,y:null,relX:I.relX,relY:I.relY,absX:I.absX,absY:I.absY,mouse:null};for(Q=0;Q<G.length;Q++){s=G[Q];if(!s.mouse.track){continue}S=s.data;A=(s.xaxis.scale*s.mouse.sensibility);M=(s.yaxis.scale*s.mouse.sensibility);for(var P=0,B,E;P<S.length;P++){if(S[P][1]===null){continue}B=Math.pow(s.xaxis.scale*(S[P][0]-I.x),2);E=Math.pow(s.yaxis.scale*(S[P][1]-I.y),2);if(B<A&&E<M&&Math.sqrt(B+E)<L.dist){L.dist=Math.sqrt(B+E);L.x=S[P][0];L.y=S[P][1];L.mouse=s.mouse}}}if(L.mouse&&L.mouse.track&&!R||(R&&(L.x!=R.x||L.y!=R.y))){var K=this.mouseTrack||this.el.select(".flotr-mouse-value")[0],F="",J=C.mouse.position,N=C.mouse.margin,O="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;";if(!C.mouse.relative){if(J.charAt(0)=="n"){F+="top:"+(N+H.top)+"px;"}else{if(J.charAt(0)=="s"){F+="bottom:"+(N+H.bottom)+"px;"}}if(J.charAt(1)=="e"){F+="right:"+(N+H.right)+"px;"}else{if(J.charAt(1)=="w"){F+="left:"+(N+H.left)+"px;"}}}else{if(J.charAt(0)=="n"){F+="bottom:"+(N-H.top-this.tVert(L.y)+this.canvasHeight)+"px;"}else{if(J.charAt(0)=="s"){F+="top:"+(N+H.top+this.tVert(L.y))+"px;"}}if(J.charAt(1)=="e"){F+="left:"+(N+H.left+this.tHoz(L.x))+"px;"}else{if(J.charAt(1)=="w"){F+="right:"+(N-H.left-this.tHoz(L.x)+this.canvasWidth)+"px;"}}}O+=F;if(!K){this.el.insert('<div class="flotr-mouse-value" style="'+O+'"></div>');K=this.mouseTrack=this.el.select(".flotr-mouse-value").first()}else{this.mouseTrack=K.setStyle(O)}if(L.x!==null&&L.y!==null){K.show();this.clearHit();if(L.mouse.lineColor!=null){D.save();D.translate(H.left,H.top);D.lineWidth=C.points.lineWidth;D.strokeStyle=L.mouse.lineColor;D.fillStyle="#ffffff";D.beginPath();D.arc(this.tHoz(L.x),this.tVert(L.y),C.mouse.radius,0,2*Math.PI,true);D.fill();D.stroke();D.restore()}this.prevHit=L;var T=L.mouse.trackDecimals;if(T==null||T<0){T=0}K.innerHTML=L.mouse.trackFormatter({x:L.x.toFixed(T),y:L.y.toFixed(T)});K.fire("flotr:hit",[L,this])}else{if(R){K.hide();this.clearHit()}}}},saveImage:function(D,C,A,B){var E=null;switch(D){case"jpeg":case"jpg":E=Canvas2Image.saveAsJPEG(this.canvas,B,C,A);break;default:case"png":E=Canvas2Image.saveAsPNG(this.canvas,B,C,A);break;case"bmp":E=Canvas2Image.saveAsBMP(this.canvas,B,C,A);break}if(Object.isElement(E)&&B){this.restoreCanvas();this.canvas.hide();this.overlay.hide();this.el.insert(E.setStyle({position:"absolute"}))}},restoreCanvas:function(){this.canvas.show();this.overlay.show();this.el.select("img").invoke("remove")}});Flotr.Color=Class.create({initialize:function(E,D,B,C){this.rgba=["r","g","b","a"];var A=4;while(-1<--A){this[this.rgba[A]]=arguments[A]||((A==3)?1:0)}this.normalize()},adjust:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]+=arguments[A]}}return this.normalize()},clone:function(){return new Flotr.Color(this.r,this.b,this.g,this.a)},limit:function(B,A,C){return Math.max(Math.min(B,C),A)},normalize:function(){var A=this.limit;this.r=A(parseInt(this.r),0,255);this.g=A(parseInt(this.g),0,255);this.b=A(parseInt(this.b),0,255);this.a=A(this.a,0,1);return this},scale:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]*=arguments[A]}}return this.normalize()},distance:function(B){if(!B){return }B=new Flotr.parseColor(B);var C=0;var A=3;while(-1<--A){C+=Math.abs(this[this.rgba[A]]-B[this.rgba[A]])}return C},toString:function(){return(this.a>=1)?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"}});Flotr.Color.lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};Flotr.Date={format:function(F,E){if(!F){return }var A=function(H){H=H.toString();return H.length==1?"0"+H:H};var D=[];var C=false;for(var B=0;B<E.length;++B){var G=E.charAt(B);if(C){switch(G){case"h":G=F.getUTCHours().toString();break;case"H":G=A(F.getUTCHours());break;case"M":G=A(F.getUTCMinutes());break;case"S":G=A(F.getUTCSeconds());break;case"d":G=F.getUTCDate().toString();break;case"m":G=(F.getUTCMonth()+1).toString();break;case"y":G=F.getUTCFullYear().toString();break;case"b":G=Flotr.Date.monthNames[F.getUTCMonth()];break}D.push(G);C=false}else{if(G=="%"){C=true}else{D.push(G)}}}return D.join("")},timeUnits:{second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000},spec:[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]};
+
--- a/js/flotr/flotr.debug-0.2.0-alpha_radar1.js
+++ /dev/null
@@ -1,3349 +1,1 @@
-//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.
-//
-//Radar chart added by Ryan Simmons
-//
-/* $Id: flotr.js 82 2009-01-12 19:19:31Z fabien.menager $ */
-
-var Flotr = {
- version: '0.2.0-alpha',
- author: 'Bas Wenneker',
- website: 'http://www.solutoire.com',
- /**
- * An object of the default registered graph types. Use Flotr.register(type, functionName)
- * to add your own type.
- */
- _registeredTypes:{
- 'lines': 'drawSeriesLines',
- 'points': 'drawSeriesPoints',
- 'bars': 'drawSeriesBars',
- 'candles': 'drawSeriesCandles',
- 'pie': 'drawSeriesPie',
- 'radar':'drawSeriesRadar'
- },
- /**
- * Can be used to register your own chart type. Default types are 'lines', 'points' and 'bars'.
- * This is still experimental.
- * @todo Test and confirm.
- * @param {String} type - type of chart, like 'pies', 'bars' etc.
- * @param {String} functionName - Name of the draw function, like 'drawSeriesPies', 'drawSeriesBars' etc.
- */
- register: function(type, functionName){
- Flotr._registeredTypes[type] = functionName+'';
- },
- /**
- * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.
- * You could also draw graphs by directly calling Flotr.Graph(element, data, options).
- * @param {Element} el - element to insert the graph into
- * @param {Object} data - an array or object of dataseries
- * @param {Object} options - an object containing options
- * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph
- * @return {Class} returns a new graph object and of course draws the graph.
- */
- draw: function(el, data, options, _GraphKlass_){
- _GraphKlass_ = _GraphKlass_ || Flotr.Graph;
- return new _GraphKlass_(el, data, options);
- },
- /**
- * Collects dataseries from input and parses the series into the right format. It returns an Array
- * of Objects each having at least the 'data' key set.
- * @param {Array/Object} data - Object or array of dataseries
- * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)})
- */
- getSeries: function(data){
- return data.collect(function(serie){
- var i, serie = (serie.data) ? Object.clone(serie) : {'data': serie};
- for (i = serie.data.length-1; i > -1; --i) {
- serie.data[i][1] = (serie.data[i][1] === null ? null : parseFloat(serie.data[i][1]));
- }
- return serie;
- });
- },
- /**
- * Recursively merges two objects.
- * @param {Object} src - source object (likely the object with the least properties)
- * @param {Object} dest - destination object (optional, object with the most properties)
- * @return {Object} recursively merged Object
- */
- merge: function(src, dest){
- var result = dest || {};
- for(var i in src){
- result[i] = (src[i] != null && typeof(src[i]) == 'object' && !(src[i].constructor == Array || src[i].constructor == RegExp) && !Object.isElement(src[i])) ? Flotr.merge(src[i], dest[i]) : result[i] = src[i];
- }
- return result;
- },
- /**
- * Function calculates the ticksize and returns it.
- * @param {Integer} noTicks - number of ticks
- * @param {Integer} min - lower bound integer value for the current axis
- * @param {Integer} max - upper bound integer value for the current axis
- * @param {Integer} decimals - number of decimals for the ticks
- * @return {Integer} returns the ticksize in pixels
- */
- getTickSize: function(noTicks, min, max, decimals){
- var delta = (max - min) / noTicks;
- var magn = Flotr.getMagnitude(delta);
-
- // Norm is between 1.0 and 10.0.
- var norm = delta / magn;
-
- var tickSize = 10;
- if(norm < 1.5) tickSize = 1;
- else if(norm < 2.25) tickSize = 2;
- else if(norm < 3) tickSize = ((decimals == 0) ? 2 : 2.5);
- else if(norm < 7.5) tickSize = 5;
-
- return tickSize * magn;
- },
- /**
- * Default tick formatter.
- * @param {String/Integer} val - tick value integer
- * @return {String} formatted tick string
- */
- defaultTickFormatter: function(val){
- return val+'';
- },
- /**
- * Formats the mouse tracker values.
- * @param {Object} obj - Track value Object {x:..,y:..}
- * @return {String} Formatted track string
- */
- defaultTrackFormatter: function(obj){
- return '('+obj.x+', '+obj.y+')';
- },
- defaultPieLabelFormatter: function(slice) {
- return (slice.fraction*100).toFixed(2)+'%';
- },
- /**
- * Returns the magnitude of the input value.
- * @param {Integer/Float} x - integer or float value
- * @return {Integer/Float} returns the magnitude of the input value
- */
- getMagnitude: function(x){
- return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
- },
- toPixel: function(val){
- return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);
- },
- toRad: function(angle){
- return -angle * (Math.PI/180);
- },
- /**
- * Parses a color string and returns a corresponding Color.
- * @param {String} str - string thats representing a color
- * @return {Color} returns a Color object or false
- */
- parseColor: function(str){
- if (str instanceof Flotr.Color) return str;
-
- var result, Color = Flotr.Color;
-
- // rgb(num,num,num)
- if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)))
- return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));
-
- // rgba(num,num,num,num)
- if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
- return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));
-
- // rgb(num%,num%,num%)
- if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)))
- return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);
-
- // rgba(num%,num%,num%,num)
- if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
- return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));
-
- // #a0b1c2
- if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))
- return new Color(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16));
-
- // #fff
- if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))
- return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));
-
- // Otherwise, we're most likely dealing with a named color.
- var name = str.strip().toLowerCase();
- if(name == 'transparent'){
- return new Color(255, 255, 255, 0);
- }
- return ((result = Color.lookupColors[name])) ? new Color(result[0], result[1], result[2]) : false;
- },
- /**
- * Extracts the background-color of the passed element.
- * @param {Element} element
- * @return {String} color string
- */
- extractColor: function(element){
- var color;
- // Loop until we find an element with a background color and stop when we hit the body element.
- do {
- color = element.getStyle('background-color').toLowerCase();
- if(!(color == '' || color == 'transparent')) break;
- element = element.up(0);
- } while(!element.nodeName.match(/^body$/i));
-
- // Catch Safari's way of signaling transparent.
- return (color == 'rgba(0, 0, 0, 0)') ? 'transparent' : color;
- }
-};
-/**
- * Flotr Graph class that plots a graph on creation.
-
- */
-Flotr.Graph = Class.create({
- /**
- * Flotr Graph constructor.
- * @param {Element} el - element to insert the graph into
- * @param {Object} data - an array or object of dataseries
- * @param {Object} options - an object containing options
- */
- initialize: function(el, data, options){
- this.el = $(el);
-
- if (!this.el) throw 'The target container doesn\'t exist';
-
- this.data = data;
- this.series = Flotr.getSeries(data);
- this.setOptions(options);
-
- // Initialize some variables
- this.lastMousePos = { pageX: null, pageY: null };
- this.selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} };
- this.prevSelection = null;
- this.selectionInterval = null;
- this.ignoreClick = false;
- this.prevHit = null;
-
- // Create and prepare canvas.
- this.constructCanvas();
-
- // Add event handlers for mouse tracking, clicking and selection
- this.initEvents();
-
- this.findDataRanges();
- this.calculateTicks(this.axes.x);
- this.calculateTicks(this.axes.x2);
- this.calculateTicks(this.axes.y);
- this.calculateTicks(this.axes.y2);
-
- this.calculateSpacing();
- this.draw();
- this.insertLegend();
-
- // Graph and Data tabs
- if (this.options.spreadsheet.show)
- this.constructTabs();
- },
- /**
- * Sets options and initializes some variables and color specific values, used by the constructor.
- * @param {Object} opts - options object
- */
- setOptions: function(opts){
- var options = {
- colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.
- title: null,
- subtitle: null,
- legend: {
- show: true, // => setting to true will show the legend, hide otherwise
- noColumns: 1, // => number of colums in legend table // @todo: doesn't work for HtmlText = false
- labelFormatter: Prototype.K, // => fn: string -> string
- labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes
- labelBoxWidth: 14,
- labelBoxHeight: 10,
- labelBoxMargin: 5,
- container: null, // => container (as jQuery object) to put legend in, null means default on top of graph
- position: 'nw', // => position of default legend container within plot
- margin: 5, // => distance from grid edge to default legend container within plot
- backgroundColor: null, // => null means auto-detect
- backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background
- },
- xaxis: {
- ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]
- showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise
- labelsAngle: 0, // => Labels' angle, in degrees
- title: null, // => axis title
- titleAngle: 0, // => axis title's angle, in degrees
- noTicks: 5, // => number of ticks for automagically generated ticks
- tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string
- tickDecimals: null, // => no. of decimals, null means auto
- min: null, // => min. value to show, null means set automatically
- max: null, // => max. value to show, null means set automatically
- autoscaleMargin: 0, // => margin in % to add if auto-setting min/max
- color: null
- },
- x2axis: {},
- yaxis: {
- ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]
- showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise
- labelsAngle: 0, // => Labels' angle, in degrees
- title: null, // => axis title
- titleAngle: 90, // => axis title's angle, in degrees
- noTicks: 5, // => number of ticks for automagically generated ticks
- tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string
- tickDecimals: null, // => no. of decimals, null means auto
- min: null, // => min. value to show, null means set automatically
- max: null, // => max. value to show, null means set automatically
- autoscaleMargin: 0, // => margin in % to add if auto-setting min/max
- color: null
- },
- y2axis: {
- titleAngle: 270
- },
- points: {
- show: false, // => setting to true will show points, false will hide
- radius: 3, // => point radius (pixels)
- lineWidth: 2, // => line width in pixels
- fill: true, // => true to fill the points with a color, false for (transparent) no fill
- fillColor: '#FFFFFF', // => fill color
- fillOpacity: 0.4
- },
- lines: {
- show: false, // => setting to true will show lines, false will hide
- lineWidth: 2, // => line width in pixels
- fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill
- fillColor: null, // => fill color
- fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
- },
- radar: {
- show: false, // => setting to true will show radar chart, false will hide
- lineWidth: 2, // => line width in pixels
- fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill
- fillColor: null, // => fill color
- fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
- },
- bars: {
- show: false, // => setting to true will show bars, false will hide
- lineWidth: 2, // => in pixels
- barWidth: 1, // => in units of the x axis
- fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill
- fillColor: null, // => fill color
- fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
- horizontal: false,
- stacked: false
- },
- candles: {
- show: false, // => setting to true will show candle sticks, false will hide
- lineWidth: 1, // => in pixels
- wickLineWidth: 1, // => in pixels
- candleWidth: 0.6, // => in units of the x axis
- fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill
- upFillColor: '#00A8F0',// => up sticks fill color
- downFillColor: '#CB4B4B',// => down sticks fill color
- fillOpacity: 0.5, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
- barcharts: false // => draw as barcharts (not standard bars but financial barcharts)
- },
- pie: {
- show: false, // => setting to true will show bars, false will hide
- lineWidth: 1, // => in pixels
- fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill
- fillColor: null, // => fill color
- fillOpacity: 0.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
- explode: 6,
- sizeRatio: 0.6,
- startAngle: Math.PI/4,
- labelFormatter: Flotr.defaultPieLabelFormatter,
- pie3D: false,
- pie3DviewAngle: (Math.PI/2 * 0.8),
- pie3DspliceThickness: 20
- },
- grid: {
- color: '#545454', // => primary color used for outline and labels
- backgroundColor: null, // => null for transparent, else color
- tickColor: '#DDDDDD', // => color used for the ticks
- labelMargin: 3, // => margin in pixels
- verticalLines: true, // => whether to show gridlines in vertical direction
- horizontalLines: true, // => whether to show gridlines in horizontal direction
- outlineWidth: 2 // => width of the grid outline/border in pixels
- },
- selection: {
- mode: null, // => one of null, 'x', 'y' or 'xy'
- color: '#B6D9FF', // => selection box color
- fps: 20 // => frames-per-second
- },
- mouse: {
- track: false, // => true to track the mouse, no tracking otherwise
- position: 'se', // => position of the value box (default south-east)
- relative: false, // => next to the mouse cursor
- trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box
- margin: 5, // => margin in pixels of the valuebox
- lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series
- trackDecimals: 1, // => decimals for the track values
- sensibility: 2, // => the lower this number, the more precise you have to aim to show a value
- radius: 3 // => radius of the track point
- },
- radarChartMode: false, // => true to render radar grid / and setup scaling for radar chart
- shadowSize: 4, // => size of the 'fake' shadow
- defaultType: 'lines', // => default series type
- HtmlText: true, // => wether to draw the text using HTML or on the canvas
- fontSize: 7.5, // => canvas' text font size
- spreadsheet: {
- show: false, // => show the data grid using two tabs
- tabGraphLabel: 'Graph',
- tabDataLabel: 'Data',
- toolbarDownload: 'Download CSV', // @todo: add language support
- toolbarSelectAll: 'Select all'
- }
- }
-
- options.x2axis = Object.extend(Object.clone(options.xaxis), options.x2axis);
- options.y2axis = Object.extend(Object.clone(options.yaxis), options.y2axis);
- this.options = Flotr.merge((opts || {}), options);
-
- this.axes = {
- x: {options: this.options.xaxis, n: 1},
- x2: {options: this.options.x2axis, n: 2},
- y: {options: this.options.yaxis, n: 1},
- y2: {options: this.options.y2axis, n: 2}
- };
-
- // Initialize some variables used throughout this function.
- var assignedColors = [],
- colors = [],
- ln = this.series.length,
- neededColors = this.series.length,
- oc = this.options.colors,
- usedColors = [],
- variation = 0,
- c, i, j, s, tooClose;
-
- // Collect user-defined colors from series.
- for(i = neededColors - 1; i > -1; --i){
- c = this.series[i].color;
- if(c != null){
- --neededColors;
- if(Object.isNumber(c)) assignedColors.push(c);
- else usedColors.push(Flotr.parseColor(c));
- }
- }
-
- // Calculate the number of colors that need to be generated.
- for(i = assignedColors.length - 1; i > -1; --i)
- neededColors = Math.max(neededColors, assignedColors[i] + 1);
-
- // Generate needed number of colors.
- for(i = 0; colors.length < neededColors;){
- c = (oc.length == i) ? new Flotr.Color(100, 100, 100) : Flotr.parseColor(oc[i]);
-
- // Make sure each serie gets a different color.
- var sign = variation % 2 == 1 ? -1 : 1;
- var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
- c.scale(factor, factor, factor);
-
- /**
- * @todo if we're getting too close to something else, we should probably skip this one
- */
- colors.push(c);
-
- if(++i >= oc.length){
- i = 0;
- ++variation;
- }
- }
-
- // Fill the options with the generated colors.
- for(i = 0, j = 0; i < ln; ++i){
- s = this.series[i];
-
- // Assign the color.
- if(s.color == null){
- s.color = colors[j++].toString();
- }else if(Object.isNumber(s.color)){
- s.color = colors[s.color].toString();
- }
-
- if (!s.xaxis) s.xaxis = this.axes.x;
- if (s.xaxis == 1) s.xaxis = this.axes.x;
- else if (s.xaxis == 2) s.xaxis = this.axes.x2;
-
- if (!s.yaxis) s.yaxis = this.axes.y;
- if (s.yaxis == 1) s.yaxis = this.axes.y;
- else if (s.yaxis == 2) s.yaxis = this.axes.y2;
-
- // Apply missing options to the series.
- s.lines = Object.extend(Object.clone(this.options.lines), s.lines);
- s.points = Object.extend(Object.clone(this.options.points), s.points);
- s.bars = Object.extend(Object.clone(this.options.bars), s.bars);
- s.candles = Object.extend(Object.clone(this.options.candles), s.candles);
- s.pie = Object.extend(Object.clone(this.options.pie), s.pie);
- s.radar = Object.extend(Object.clone(this.options.radar), s.radar);
- s.mouse = Object.extend(Object.clone(this.options.mouse), s.mouse);
-
- if(s.shadowSize == null) s.shadowSize = this.options.shadowSize;
- }
- },
- /**
- * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use
- * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements
- * are created, the elements are inserted into the container element.
- */
- constructCanvas: function(){
- var el = this.el,
- size, c, oc;
-
- this.canvas = el.select('.flotr-canvas')[0];
- this.overlay = el.select('.flotr-overlay')[0];
-
- el.childElements().invoke('remove');
-
- // For positioning labels and overlay.
- el.setStyle({position:'relative', cursor:'default'});
-
- this.canvasWidth = el.getWidth();
- this.canvasHeight = el.getHeight();
- size = {'width': this.canvasWidth, 'height': this.canvasHeight};
-
- if(this.canvasWidth <= 0 || this.canvasHeight <= 0){
- throw 'Invalid dimensions for plot, width = ' + this.canvasWidth + ', height = ' + this.canvasHeight;
- }
-
- // Insert main canvas.
- if (!this.canvas) {
- c = this.canvas = new Element('canvas', size);
- c.className = 'flotr-canvas';
- c = c.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
- } else {
- c = this.canvas.writeAttribute(size);
- }
- el.insert(c);
-
- if(Prototype.Browser.IE){
- c = window.G_vmlCanvasManager.initElement(c);
- }
- this.ctx = c.getContext('2d');
-
- // Insert overlay canvas for interactive features.
- if (!this.overlay) {
- oc = this.overlay = new Element('canvas', size);
- oc.className = 'flotr-overlay';
- oc = oc.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
- } else {
- oc = this.overlay.writeAttribute(size);
- }
- el.insert(oc);
-
- if(Prototype.Browser.IE){
- oc = window.G_vmlCanvasManager.initElement(oc);
- }
- this.octx = oc.getContext('2d');
-
- // Enable text functions
- if (window.CanvasText) {
- CanvasText.enable(this.ctx);
- CanvasText.enable(this.octx);
- this.textEnabled = true;
- }
- },
- getTextDimensions: function(text, canvasStyle, HtmlStyle, className) {
- if (!text) return {width:0, height:0};
-
- if (!this.options.HtmlText && this.textEnabled) {
- var bounds = this.ctx.getTextBounds(text, canvasStyle);
- return {
- width: bounds.width+2,
- height: bounds.height+6
- };
- }
- else {
- var dummyDiv = this.el.insert('<div style="position:absolute;top:-10000px;'+HtmlStyle+'" class="'+className+' flotr-dummy-div">' + text + '</div>').select(".flotr-dummy-div")[0];
- dim = dummyDiv.getDimensions();
- dummyDiv.remove();
- return dim;
- }
- },
- loadDataGrid: function(){
- if (this.seriesData) return this.seriesData;
-
- var s = this.series;
- var dg = [];
-
- /* The data grid is a 2 dimensions array. There is a row for each X value.
- * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one)
- **/
- for(i = 0; i < s.length; ++i){
- s[i].data.each(function(v) {
- var x = v[0],
- y = v[1];
- if (r = dg.find(function(row) {return row[0] == x})) {
- r[i+1] = y;
- }
- else {
- var newRow = [];
- newRow[0] = x;
- newRow[i+1] = y
- dg.push(newRow);
- }
- });
- }
-
- // The data grid is sorted by x value
- dg = dg.sortBy(function(v) {
- return v[0];
- });
- return this.seriesData = dg;
- },
-
- // @todo: make a tab manager (Flotr.Tabs)
- showTab: function(tabName, onComplete){
- var elementsClassNames = 'canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle';
- switch(tabName) {
- case 'graph':
- this.datagrid.up().hide();
- this.el.select(elementsClassNames).invoke('show');
- this.tabs.data.removeClassName('selected');
- this.tabs.graph.addClassName('selected');
- break;
- case 'data':
- this.constructDataGrid();
- this.datagrid.up().show();
- this.el.select(elementsClassNames).invoke('hide');
- this.tabs.data.addClassName('selected');
- this.tabs.graph.removeClassName('selected');
- break;
- }
- },
- constructTabs: function(){
- var tabsContainer = new Element('div', {className:'flotr-tabs-group', style:'position:absolute;left:0px;top:'+this.canvasHeight+'px;width:'+this.canvasWidth+'px;'});
- this.el.insert({bottom: tabsContainer});
- this.tabs = {
- graph: new Element('div', {className:'flotr-tab selected', style:'float:left;'}).update(this.options.spreadsheet.tabGraphLabel),
- data: new Element('div', {className:'flotr-tab', style:'float:left;'}).update(this.options.spreadsheet.tabDataLabel)
- }
-
- tabsContainer.insert(this.tabs.graph).insert(this.tabs.data);
-
- this.el.setStyle({height: this.canvasHeight+this.tabs.data.getHeight()+2+'px'});
-
- this.tabs.graph.observe('click', (function() {this.showTab('graph')}).bind(this));
- this.tabs.data.observe('click', (function() {this.showTab('data')}).bind(this));
- },
-
- // @todo: make a spreadsheet manager (Flotr.Spreadsheet)
- constructDataGrid: function(){
- // If the data grid has already been built, nothing to do here
- if (this.datagrid) return this.datagrid;
-
- var i, j,
- s = this.series,
- datagrid = this.loadDataGrid();
-
- var t = this.datagrid = new Element('table', {className:'flotr-datagrid', style:'height:100px;'});
- var colgroup = ['<colgroup><col />'];
-
- // First row : series' labels
- var html = ['<tr class="first-row">'];
- html.push('<th> </th>');
- for (i = 0; i < s.length; ++i) {
- html.push('<th scope="col">'+(s[i].label || String.fromCharCode(65+i))+'</th>');
- colgroup.push('<col />');
- }
- html.push('</tr>');
-
- // Data rows
- for (j = 0; j < datagrid.length; ++j) {
- html.push('<tr>');
- for (i = 0; i < s.length+1; ++i) {
- var tag = 'td';
- var content = (datagrid[j][i] != null ? Math.round(datagrid[j][i]*100000)/100000 : '');
-
- if (i == 0) {
- tag = 'th';
- var label;
- if(this.options.xaxis.ticks) {
- var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == datagrid[j][i] });
- if (tick) label = tick[1];
- }
- else {
- label = this.options.xaxis.tickFormatter(content);
- }
-
- if (label) content = label;
- }
-
- html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+'</'+tag+'>');
- }
- html.push('</tr>');
- }
- colgroup.push('</colgroup>');
- t.update(colgroup.join('')+html.join(''));
-
- if (!Prototype.Browser.IE) {
- t.select('td').each(function(td) {
- td.observe('mouseover', function(e){
- td = e.element();
- var siblings = td.previousSiblings();
-
- t.select('th[scope=col]')[siblings.length-1].addClassName('hover');
- t.select('colgroup col')[siblings.length].addClassName('hover');
- });
-
- td.observe('mouseout', function(){
- t.select('colgroup col.hover, th.hover').each(function(e){e.removeClassName('hover')});
- });
- });
- }
-
- var toolbar = new Element('div', {className: 'flotr-datagrid-toolbar'}).
- insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarDownload).observe('click', this.downloadCSV.bind(this))).
- insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarSelectAll).observe('click', this.selectAllData.bind(this)));
-
- var container = new Element('div', {className:'flotr-datagrid-container', style:'left:0px;top:0px;width:'+this.canvasWidth+'px;height:'+this.canvasHeight+'px;overflow:auto;'});
- container.insert(toolbar);
- t.wrap(container.hide());
-
- this.el.insert(container);
- return t;
- },
- selectAllData: function(){
- if (this.tabs) {
- var selection, range, doc, win, node = this.constructDataGrid();
-
- this.showTab('data');
-
- // deferred to be able to select the table
- (function () {
- if ((doc = node.ownerDocument) && (win = doc.defaultView) &&
- win.getSelection && doc.createRange &&
- (selection = window.getSelection()) &&
- selection.removeAllRanges) {
- range = doc.createRange();
- range.selectNode(node);
- selection.removeAllRanges();
- selection.addRange(range);
- }
- else if (document.body && document.body.createTextRange &&
- (range = document.body.createTextRange())) {
- range.moveToElementText(node);
- range.select();
- }
- }).defer();
- return true;
- }
- else return false;
- },
- downloadCSV: function(){
- var i, csv = '"x"',
- series = this.series,
- dg = this.loadDataGrid();
-
- for (i = 0; i < series.length; ++i) {
- csv += '%09"'+(series[i].label || String.fromCharCode(65+i))+'"'; // \t
- }
- csv += "%0D%0A"; // \r\n
-
- for (i = 0; i < dg.length; ++i) {
- if (this.options.xaxis.ticks) {
- var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == dg[i][0] });
- if (tick) dg[i][0] = tick[1];
- } else {
- dg[i][0] = this.options.xaxis.tickFormatter(dg[i][0]);
- }
- csv += dg[i].join('%09')+"%0D%0A"; // \t and \r\n
- }
- if (Prototype.Browser.IE) {
- csv = csv.gsub('%09', '\t').gsub('%0A', '\n').gsub('%0D', '\r');
- window.open().document.write(csv);
- }
- else {
- window.open('data:text/csv,'+csv);
- }
- },
- /**
- * Initializes event some handlers.
- */
- initEvents: function () {
- //@todo: maybe stopObserving with only flotr functions
- this.overlay.stopObserving();
- this.overlay.observe('mousedown', this.mouseDownHandler.bind(this));
- this.overlay.observe('mousemove', this.mouseMoveHandler.bind(this));
- this.overlay.observe('click', this.clickHandler.bind(this));
- },
- /**
- * Function determines the min and max values for the xaxis and yaxis.
- */
- findDataRanges: function(){
- var s = this.series,
- a = this.axes;
-
- a.x.datamin = 0; a.x.datamax = 0;
- a.x2.datamin = 0; a.x2.datamax = 0;
- a.y.datamin = 0; a.y.datamax = 0;
- a.y2.datamin = 0; a.y2.datamax = 0;
-
- if(s.length > 0){
- var i, j, h, x, y, data, xaxis, yaxis;
-
- // Get datamin, datamax start values
- for(i = 0; i < s.length; ++i) {
- data = s[i].data,
- xaxis = s[i].xaxis,
- yaxis = s[i].yaxis;
-
- if (data.length > 0 && !s[i].hide) {
- if (!xaxis.used) xaxis.datamin = xaxis.datamax = data[0][0];
- if (!yaxis.used) yaxis.datamin = yaxis.datamax = data[0][1];
- xaxis.used = true;
- yaxis.used = true;
-
- for(h = data.length - 1; h > -1; --h){
- x = data[h][0];
- if(x < xaxis.datamin) xaxis.datamin = x;
- else if(x > xaxis.datamax) xaxis.datamax = x;
-
- for(j = 1; j < data[h].length; j++){
- y = data[h][j];
- if(y < yaxis.datamin) yaxis.datamin = y;
- else if(y > yaxis.datamax) yaxis.datamax = y;
- }
- }
- }
- if (this.options.radarChartMode) {
- xaxis.datamin = yaxis.datamin = - yaxis.datamax;
- xaxis.datamax = yaxis.datamax;
- if (!this.options.radarChartSides) this.options.radarChartSides = data.length;
- }
- }
- }
-
- this.findXAxesValues();
-
- this.calculateRange(a.x);
- this.extendXRangeIfNeededByBar(a.x);
-
- if (a.x2.used) {
- this.calculateRange(a.x2);
- this.extendXRangeIfNeededByBar(a.x2);
- }
-
- this.calculateRange(a.y);
- this.extendYRangeIfNeededByBar(a.y);
-
- if (a.y2.used) {
- this.calculateRange(a.y2);
- this.extendYRangeIfNeededByBar(a.y2);
- }
- },
- /**
- * Calculates the range of an axis to apply autoscaling.
- */
- calculateRange: function(axis){
- var o = axis.options,
- min = o.min != null ? o.min : axis.datamin,
- max = o.max != null ? o.max : axis.datamax,
- margin;
-
- if(max - min == 0.0){
- var widen = (max == 0.0) ? 1.0 : 0.01;
- min -= widen;
- max += widen;
- }
- axis.tickSize = Flotr.getTickSize(o.noTicks, ((this.options.radarChartMode) ? 0 : min), max, o.tickDecimals);
-
- // Autoscaling.
- if(o.min == null){
- // Add a margin.
- margin = o.autoscaleMargin;
- if(margin != 0){
- min -= axis.tickSize * margin;
-
- // Make sure we don't go below zero if all values are positive.
- if(min < 0 && axis.datamin >= 0) min = 0;
- min = axis.tickSize * Math.floor(min / axis.tickSize);
- }
- }
- if(o.max == null){
- margin = o.autoscaleMargin;
- if(margin != 0){
- max += axis.tickSize * margin;
- if(max > 0 && axis.datamax <= 0) max = 0;
- max = axis.tickSize * Math.ceil(max / axis.tickSize);
- }
- }
- axis.min = min;
- axis.max = max;
- },
- /**
- * Bar series autoscaling in x direction.
- */
- extendXRangeIfNeededByBar: function(axis){
- if(axis.options.max == null){
- var newmax = axis.max,
- i, s, b, c,
- stackedSums = [],
- lastSerie = null;
-
- for(i = 0; i < this.series.length; ++i){
- s = this.series[i];
- b = s.bars;
- c = s.candles;
- if(s.axis == axis && (b.show || c.show)) {
- if (!b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){
- newmax = axis.max + s.bars.barWidth;
- }
- if(b.stacked && b.horizontal){
- for (j = 0; j < s.data.length; j++) {
- if (s.bars.show && s.bars.stacked) {
- var x = s.data[j][0];
- stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
- lastSerie = s;
- }
- }
-
- for (j = 0; j < stackedSums.length; j++) {
- newmax = Math.max(stackedSums[j], newmax);
- }
- }
- }
- }
- axis.lastSerie = lastSerie;
- axis.max = newmax;
- }
- },
- /**
- * Bar series autoscaling in y direction.
- */
- extendYRangeIfNeededByBar: function(axis){
- if(axis.options.max == null){
- var newmax = axis.max,
- i, s, b, c,
- stackedSums = [],
- lastSerie = null;
-
- for(i = 0; i < this.series.length; ++i){
- s = this.series[i];
- b = s.bars;
- c = s.candles;
- if (s.yaxis == axis && b.show && !s.hide) {
- if (b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){
- newmax = axis.max + b.barWidth;
- }
- if(b.stacked && !b.horizontal){
- for (j = 0; j < s.data.length; j++) {
- if (s.bars.show && s.bars.stacked) {
- var x = s.data[j][0];
- stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
- lastSerie = s;
- }
- }
-
- for (j = 0; j < stackedSums.length; j++) {
- newmax = Math.max(stackedSums[j], newmax);
- }
- }
- }
- }
- axis.lastSerie = lastSerie;
- axis.max = newmax;
- }
- },
- /**
- * Find every values of the x axes
- */
- findXAxesValues: function(){
- for(i = this.series.length-1; i > -1 ; --i){
- s = this.series[i];
- s.xaxis.values = s.xaxis.values || [];
- for (j = s.data.length-1; j > -1 ; --j){
- s.xaxis.values[s.data[j][0]] = {};
- }
- }
- },
- /**
- * Calculate axis ticks.
- * @param {Object} axis - axis object
- * @param {Object} o - axis options
- */
- calculateTicks: function(axis){
- var o = axis.options, i, v;
-
- axis.ticks = [];
- if(o.ticks){
- var ticks = o.ticks, t, label;
-
- if(Object.isFunction(ticks)){
- ticks = ticks({min: axis.min, max: axis.max});
- }
-
- // Clean up the user-supplied ticks, copy them over.
- for(i = 0; i < ticks.length; ++i){
- t = ticks[i];
- if(typeof(t) == 'object'){
- v = t[0];
- label = (t.length > 1) ? t[1] : o.tickFormatter(v);
- }else{
- v = t;
- label = o.tickFormatter(v);
- }
- axis.ticks[i] = { v: v, label: label };
- }
- }
- else {
- // Round to nearest multiple of tick size.
- var start = axis.tickSize * Math.ceil(axis.min / axis.tickSize),
- decimals;
-
- // Then store all possible ticks.
- for(i = 0; start + i * axis.tickSize <= axis.max; ++i){
- v = start + i * axis.tickSize;
-
- // Round (this is always needed to fix numerical instability).
- decimals = o.tickDecimals;
- if(decimals == null) decimals = 1 - Math.floor(Math.log(axis.tickSize) / Math.LN10);
- if(decimals < 0) decimals = 0;
-
- v = v.toFixed(decimals);
- axis.ticks.push({ v: v, label: o.tickFormatter(v) });
- }
- }
- },
- /**
- * Calculates axis label sizes.
- */
- calculateSpacing: function(){
- var a = this.axes,
- options = this.options,
- series = this.series,
- margin = options.grid.labelMargin,
- x = a.x,
- x2 = a.x2,
- y = a.y,
- y2 = a.y2,
- maxOutset = 2,
- i, j, l, dim;
-
- // Labels width and height
- [x, x2, y, y2].each(function(axis) {
- var maxLabel = '';
-
- if (axis.options.showLabels) {
- for(i = 0; i < axis.ticks.length; ++i){
- l = axis.ticks[i].label.length;
- if(l > maxLabel.length){
- maxLabel = axis.ticks[i].label;
- }
- }
- }
- axis.maxLabel = this.getTextDimensions(maxLabel, {size:options.fontSize, angle: Flotr.toRad(axis.options.labelsAngle)}, 'font-size:smaller;', 'flotr-grid-label');
- axis.titleSize = this.getTextDimensions(axis.options.title, {size: options.fontSize*1.2, angle: Flotr.toRad(axis.options.titleAngle)}, 'font-weight:bold;', 'flotr-axis-title');
- }, this);
-
- // Title height
- dim = this.getTextDimensions(options.title, {size: options.fontSize*1.5}, 'font-size:1em;font-weight:bold;', 'flotr-title');
- this.titleHeight = dim.height;
-
- // Subtitle height
- dim = this.getTextDimensions(options.subtitle, {size: options.fontSize}, 'font-size:smaller;', 'flotr-subtitle');
- this.subtitleHeight = dim.height;
-
- // Grid outline line width.
- if(options.show){
- maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2);
- }
- for(j = 0; j < options.length; ++j){
- if (series[j].points.show){
- maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);
- }
- }
-
- var p = this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};
- p.left = p.right = p.top = p.bottom = maxOutset;
-
- p.bottom += (x.options.showLabels ? (x.maxLabel.height + margin) : 0) +
- (x.options.title ? (x.titleSize.height + margin) : 0);
-
- p.top += (x2.options.showLabels ? (x2.maxLabel.height + margin) : 0) +
- (x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight +
- this.options.radarChartMode ? (y.options.showLabels ? (y.maxLabel.height + margin) : 0) : 0;
-
- p.left += (y.options.showLabels ? (y.maxLabel.width + margin) : 0) +
- (y.options.title ? (y.titleSize.width + margin) : 0);
-
- p.right += (y2.options.showLabels ? (y2.maxLabel.width + margin) : 0) +
- (y2.options.title ? (y2.titleSize.width + margin) : 0) +
- this.options.radarChartMode ? (x.options.showLabels ? (x.maxLabel.width + margin) : 0) : 0;
-
- p.top = Math.floor(p.top); // In order the outline not to be blured
-
- this.plotWidth = this.canvasWidth - p.left - p.right;
- this.plotHeight = this.canvasHeight - p.bottom - p.top;
-
- x.scale = this.plotWidth / (x.max - x.min);
- x2.scale = this.plotWidth / (x2.max - x2.min);
- y.scale = this.plotHeight / (y.max - y.min);
- y2.scale = this.plotHeight / (y2.max - y2.min);
- },
- /**
- * Draws grid, labels and series.
- */
- draw: function() {
- this.drawGrid();
- this.drawLabels();
- this.drawTitles();
-
- if(this.series.length){
- this.el.fire('flotr:beforedraw', [this.series, this]);
- for(var i = 0; i < this.series.length; i++){
- if (!this.series[i].hide)
- this.drawSeries(this.series[i]);
- }
- }
- this.el.fire('flotr:afterdraw', [this.series, this]);
- },
- /**
- * Translates absolute horizontal x coordinates to relative coordinates.
- * @param {Integer} x - absolute integer x coordinate
- * @return {Integer} translated relative x coordinate
- */
- tHoz: function(x, axis){
- axis = axis || this.axes.x;
- return (x - axis.min) * axis.scale;
- },
- /**
- * Translates absolute vertical x coordinates to relative coordinates.
- * @param {Integer} y - absolute integer y coordinate
- * @return {Integer} translated relative y coordinate
- */
- tVert: function(y, axis){
- axis = axis || this.axes.y;
- return this.plotHeight - (y - axis.min) * axis.scale;
- },
- /**
- * Draws a grid for the graph.
- */
- drawGrid: function(){
- if (this.options.radarChartMode) { // If we are in radar chart mode call drawRadarGrid instead and exit
- this.drawRadarGrid();
- return;
- }
- var v, o = this.options,
- ctx = this.ctx;
- if(o.grid.verticalLines || o.grid.horizontalLines){
- this.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);
- }
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
-
- // Draw grid background, if present in options.
- if(o.grid.backgroundColor != null){
- ctx.fillStyle = o.grid.backgroundColor;
- ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);
- }
-
- // Draw grid lines in vertical direction.
- ctx.lineWidth = 1;
- ctx.strokeStyle = o.grid.tickColor;
- ctx.beginPath();
- if(o.grid.verticalLines){
- for(var i = 0; i < this.axes.x.ticks.length; ++i){
- v = this.axes.x.ticks[i].v;
- // Don't show lines on upper and lower bounds.
- if ((v == this.axes.x.min || v == this.axes.x.max) && o.grid.outlineWidth != 0)
- continue;
-
- ctx.moveTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, 0);
- ctx.lineTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, this.plotHeight);
- }
- }
-
- // Draw grid lines in horizontal direction.
- if(o.grid.horizontalLines){
- for(var j = 0; j < this.axes.y.ticks.length; ++j){
- v = this.axes.y.ticks[j].v;
- // Don't show lines on upper and lower bounds.
- if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)
- continue;
-
- ctx.moveTo(0, Math.floor(this.tVert(v)) + ctx.lineWidth/2);
- ctx.lineTo(this.plotWidth, Math.floor(this.tVert(v)) + ctx.lineWidth/2);
- }
- }
- ctx.stroke();
-
- // Draw axis/grid border.
- if(o.grid.outlineWidth != 0) {
- ctx.lineWidth = o.grid.outlineWidth;
- ctx.strokeStyle = o.grid.color;
- ctx.lineJoin = 'round';
- ctx.strokeRect(0, 0, this.plotWidth, this.plotHeight);
- }
- ctx.restore();
- if(o.grid.verticalLines || o.grid.horizontalLines){
- this.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);
- }
- },
- /**
- * Draws a grid for the graph.
- */
- drawRadarGrid: function(){
-
- var v, o = this.options,
- ctx = this.ctx;
-
- var sides = this.options.radarChartSides,
- degreesInRadiansForAngle = Math.PI * 2 / sides,
- nintyDegrees = Math.PI / 2;
-
- if(o.grid.verticalLines || o.grid.horizontalLines){
- this.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);
- }
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
- ctx.lineJoin = 'round';
-
- // Draw grid background, if present in options.
- if(o.grid.backgroundColor != null){
- ctx.fillStyle = o.grid.backgroundColor;
- ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);
- }
-
- // Draw grid lines
- var regPoly = {};
- regPoly.xaxis = {};
- regPoly.yaxis = {};
- regPoly.xaxis.min = regPoly.yaxis.min = this.axes.x.min;
- regPoly.xaxis.max = regPoly.yaxis.max = this.axes.x.max;
- regPoly.xaxis.scale = this.plotWidth / (this.axes.x.max - this.axes.x.min);
- regPoly.yaxis.scale = this.plotHeight / (this.axes.x.max - this.axes.x.min);
-
- ctx.lineWidth = 1;
- ctx.strokeStyle = o.grid.tickColor;
-
- if(o.grid.horizontalLines){
- for(var j = 0; j < this.axes.y.ticks.length; ++j){
- v = this.axes.y.ticks[j].v;
- if (v < 0) continue;
- // Don't show lines on upper and lower bounds.
- if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)
- continue;
- regPoly.data = new Array();
- for (i = 0; i < sides; i++) {
- angle = nintyDegrees + (degreesInRadiansForAngle * i);
- regPoly.data[i] = [v * Math.cos(angle), v * Math.sin(angle)]
- }
- regPoly.data[sides] = regPoly.data[0];
- this.plotLine(regPoly,0);
- }
- }
-
- // Draw axis/grid border.
- if(o.grid.outlineWidth != 0) {
- ctx.lineWidth = o.grid.outlineWidth;
- ctx.strokeStyle = o.grid.color;
- regPoly.data = new Array();
- var radius = this.axes.x.max;
- for (i = 0; i < sides; i++) {
- angle = nintyDegrees + (degreesInRadiansForAngle * i);
- regPoly.data[i] = [radius * Math.cos(angle), radius * Math.sin(angle)]
- }
- regPoly.data[sides] = regPoly.data[0];
- this.plotLine(regPoly,0);
- }
-
- ctx.lineWidth = 1;
- ctx.strokeStyle = o.grid.tickColor;
- ctx.beginPath();
-
- if(o.grid.verticalLines){
- for(var i = 0; i < sides; ++i){
- ctx.moveTo(Math.floor(this.tHoz(0)) + ctx.lineWidth/2,
- Math.floor(this.tVert(0)) + ctx.lineWidth/2);
- ctx.lineTo(Math.floor(this.tHoz(regPoly.data[i][0])) + ctx.lineWidth/2,
- Math.floor(this.tVert(regPoly.data[i][1])) + ctx.lineWidth/2);
- }
- }
-
- ctx.stroke();
-
- ctx.restore();
- if(o.grid.verticalLines || o.grid.horizontalLines){
- this.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);
- }
- },
- /**
- * Draws labels aroung radar chart
- */
- drawRadarLabels:function(){
- var ctx = this.ctx,
- options = this.options,
- axis = this.axes.x,
- tick, minY = 0, maxY = 0,
- xOffset, yOffset;
- var style = {
- size: options.fontSize,
- adjustAlign: true
- };
- style.color = axis.options.color || options.grid.color;
- style.angle = Flotr.toRad(axis.options.labelsAngle);
- var radius = axis.max * 1,
- closeTo = axis.max * 0.1,
- sides = this.options.radarChartSides,
- degreesInRadiansForAngle = Math.PI * 2 / sides,
- nintyDegrees = Math.PI / 2,
- posdata = new Array();
- for (i = 0; i < sides; i++) {
- angle = nintyDegrees + (degreesInRadiansForAngle * i);
- posdata[i] = [radius * Math.cos(angle), radius * Math.sin(angle)];
- if (minY > posdata[i][1]) minY = posdata[i][1];
- if (maxY < posdata[i][1]) maxY = posdata[i][1];
- }
- for (i = 0; i < sides; i++) {
- tick = axis.ticks[i];
- if(!tick.label || tick.label.length == 0) continue;
- yOffset = 0;
- if (posdata[i][0] > 0) {
- style.halign = 'l';
- xOffset = options.grid.labelMargin;
- } else {
- style.halign = 'r';
- xOffset = - options.grid.labelMargin;
- }
- style.valign = 'm';
-
- if ((posdata[i][1] + closeTo) >= minY && (posdata[i][1] - closeTo) <= minY) {
- style.valign = 't' ;
- style.halign = 'c';
- yOffset = options.grid.labelMargin;
- };
- if (posdata[i][1] == maxY) {
- style.valign = 'b' ;
- style.halign = 'c';
- yOffset = - options.grid.labelMargin;
- }
- ctx.drawText(
- tick.label,
- this.plotOffset.left + this.tHoz(posdata[i][0]) + xOffset,
- this.plotOffset.top + this.tVert(posdata[i][1]) + yOffset,
- style
- );
- }
-
- },
- /**
- * Draws labels for x and y axis.
- */
- drawLabels: function(){
- // Construct fixed width label boxes, which can be styled easily.
- var noLabels = 0, axis,
- xBoxWidth, i, html, tick,
- options = this.options,
- ctx = this.ctx,
- a = this.axes;
-
- for(i = 0; i < a.x.ticks.length; ++i){
- if (a.x.ticks[i].label) {
- ++noLabels;
- }
- }
- xBoxWidth = this.plotWidth / noLabels;
-
- if (!options.HtmlText && this.textEnabled) {
- var style = {
- size: options.fontSize,
- adjustAlign: true
- };
-
- // Add x labels.
- if (options.radarChartMode) {
- this.drawRadarLabels();} else {
- axis = a.x;
- style.color = axis.options.color || options.grid.color;
- for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
- tick = axis.ticks[i];
- if(!tick.label || tick.label.length == 0) continue;
-
- style.angle = Flotr.toRad(axis.options.labelsAngle);
- style.halign = 'c';
- style.valign = 't';
-
- ctx.drawText(
- tick.label,
- this.plotOffset.left + this.tHoz(tick.v, axis),
- this.plotOffset.top + this.plotHeight + options.grid.labelMargin,
- style
- );
- }}
-
- // Add x2 labels.
- axis = a.x2;
- style.color = axis.options.color || options.grid.color;
- for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
- tick = axis.ticks[i];
- if(!tick.label || tick.label.length == 0) continue;
-
- style.angle = Flotr.toRad(axis.options.labelsAngle);
- style.halign = 'c';
- style.valign = 'b';
-
- ctx.drawText(
- tick.label,
- this.plotOffset.left + this.tHoz(tick.v, axis),
- this.plotOffset.top + options.grid.labelMargin,
- style
- );
- }
-
- // Add y labels.
- axis = a.y;
- style.color = axis.options.color || options.grid.color;
- for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
- tick = axis.ticks[i];
- if (!tick.label || tick.label.length == 0 || (tick.v < 0 && this.options.radarChartMode)) continue;
-
- style.angle = Flotr.toRad(axis.options.labelsAngle);
- style.halign = 'r';
- style.valign = 'm';
-
- ctx.drawText(
- tick.label,
- this.plotOffset.left + (this.options.radarChartMode ? this.tHoz(0) : 0) - options.grid.labelMargin,
- this.plotOffset.top + this.tVert(tick.v, axis),
- style
- );
- }
-
- // Add y2 labels.
- axis = a.y2;
- style.color = axis.options.color || options.grid.color;
- for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){
- tick = axis.ticks[i];
- if (!tick.label || tick.label.length == 0) continue;
-
- style.angle = Flotr.toRad(axis.options.labelsAngle);
- style.halign = 'l';
- style.valign = 'm';
-
- ctx.drawText(
- tick.label,
- this.plotOffset.left + this.plotWidth + options.grid.labelMargin,
- this.plotOffset.top + this.tVert(tick.v, axis),
- style
- );
-
- ctx.save();
- ctx.strokeStyle = style.color;
- ctx.beginPath();
- ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
- ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));
- ctx.stroke();
- ctx.restore();
- }
- }
- else if (a.x.options.showLabels ||
- a.x2.options.showLabels ||
- a.y.options.showLabels ||
- a.y2.options.showLabels) {
- html = ['<div style="font-size:smaller;color:' + options.grid.color + ';" class="flotr-labels">'];
-
- // Add x labels.
- axis = a.x;
- if (axis.options.showLabels){
- for(i = 0; i < axis.ticks.length; ++i){
- tick = axis.ticks[i];
- if(!tick.label || tick.label.length == 0) continue;
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');
- }
- }
-
- // Add x2 labels.
- axis = a.x2;
- if (axis.options.showLabels && axis.used){
- for(i = 0; i < axis.ticks.length; ++i){
- tick = axis.ticks[i];
- if(!tick.label || tick.label.length == 0) continue;
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top - options.grid.labelMargin - axis.maxLabel.height) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');
- }
- }
-
- // Add y labels.
- axis = a.y;
- if (axis.options.showLabels){
- for(i = 0; i < axis.ticks.length; ++i){
- tick = axis.ticks[i];
- if (!tick.label || tick.label.length == 0) continue;
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;left:0;width:' + (this.plotOffset.left - options.grid.labelMargin) + 'px;text-align:right;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');
- }
- }
-
- // Add y2 labels.
- axis = a.y2;
- if (axis.options.showLabels && axis.used){
- ctx.save();
- ctx.strokeStyle = axis.options.color || options.grid.color;
- ctx.beginPath();
-
- for(i = 0; i < axis.ticks.length; ++i){
- tick = axis.ticks[i];
- if (!tick.label || tick.label.length == 0) continue;
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;right:0;width:' + (this.plotOffset.right - options.grid.labelMargin) + 'px;text-align:left;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');
-
- ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
- ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));
- }
- ctx.stroke();
- ctx.restore();
- }
-
- html.push('</div>');
- this.el.insert(html.join(''));
- }
- },
- /**
- * Draws the title and the subtitle
- */
- drawTitles: function(){
- var html,
- options = this.options,
- margin = options.grid.labelMargin,
- ctx = this.ctx,
- a = this.axes;
-
- if (!options.HtmlText && this.textEnabled) {
- var style = {
- size: options.fontSize,
- color: options.grid.color,
- halign: 'c'
- };
-
- // Add subtitle
- if (options.subtitle){
- ctx.drawText(
- options.subtitle,
- this.plotOffset.left + this.plotWidth/2,
- this.titleHeight + this.subtitleHeight - 2,
- style
- );
- }
-
- style.weight = 1.5;
- style.size *= 1.5;
-
- // Add title
- if (options.title){
- ctx.drawText(
- options.title,
- this.plotOffset.left + this.plotWidth/2,
- this.titleHeight - 2,
- style
- );
- }
-
- style.weight = 1.8;
- style.size *= 0.8;
- style.adjustAlign = true;
-
- // Add x axis title
- if (a.x.options.title && a.x.used){
- style.halign = 'c';
- style.valign = 't';
- style.angle = Flotr.toRad(a.x.options.titleAngle);
- ctx.drawText(
- a.x.options.title,
- this.plotOffset.left + this.plotWidth/2,
- this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin,
- style
- );
- }
-
- // Add x2 axis title
- if (a.x2.options.title && a.x2.used){
- style.halign = 'c';
- style.valign = 'b';
- style.angle = Flotr.toRad(a.x2.options.titleAngle);
- ctx.drawText(
- a.x2.options.title,
- this.plotOffset.left + this.plotWidth/2,
- this.plotOffset.top - a.x2.maxLabel.height - 2 * margin,
- style
- );
- }
-
- // Add y axis title
- if (a.y.options.title && a.y.used){
- style.halign = 'r';
- style.valign = 'm';
- style.angle = Flotr.toRad(a.y.options.titleAngle);
- ctx.drawText(
- a.y.options.title,
- this.plotOffset.left - a.y.maxLabel.width - 2 * margin,
- this.plotOffset.top + this.plotHeight / 2,
- style
- );
- }
-
- // Add y2 axis title
- if (a.y2.options.title && a.y2.used){
- style.halign = 'l';
- style.valign = 'm';
- style.angle = Flotr.toRad(a.y2.options.titleAngle);
- ctx.drawText(
- a.y2.options.title,
- this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin,
- this.plotOffset.top + this.plotHeight / 2,
- style
- );
- }
- }
- else {
- html = ['<div style="color:'+options.grid.color+';" class="flotr-titles">'];
-
- // Add title
- if (options.title){
- html.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+'px;font-size:1em;font-weight:bold;text-align:center;width:'+this.plotWidth+'px;" class="flotr-title">'+options.title+'</div>');
- }
-
- // Add subtitle
- if (options.subtitle){
- html.push('<div style="position:absolute;top:'+this.titleHeight+'px;left:'+this.plotOffset.left+'px;font-size:smaller;text-align:center;width:'+this.plotWidth+'px;" class="flotr-subtitle">'+options.subtitle+'</div>');
- }
- html.push('</div>');
-
-
- html.push('<div class="flotr-axis-title" style="font-weight:bold;">');
- // Add x axis title
- if (a.x.options.title && a.x.used){
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin + a.x.titleSize.height) + 'px;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;" class="flotr-axis-title">' + a.x.options.title + '</div>');
- }
-
- // Add x2 axis title
- if (a.x2.options.title && a.x2.used){
- html.push('<div style="position:absolute;top:0;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;" class="flotr-axis-title">' + a.x2.options.title + '</div>');
- }
-
- // Add y axis title
- if (a.y.options.title && a.y.used){
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;left:0;text-align:right;" class="flotr-axis-title">' + a.y.options.title + '</div>');
- }
-
- // Add y2 axis title
- if (a.y2.options.title && a.y2.used){
- html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;right:0;text-align:right;" class="flotr-axis-title">' + a.y2.options.title + '</div>');
- }
- html.push('</div>');
-
- this.el.insert(html.join(''));
- }
- },
- /**
- * Actually draws the graph.
- * @param {Object} series - series to draw
- */
- drawSeries: function(series){
- series = series || this.series;
-
- var drawn = false;
- for(var type in Flotr._registeredTypes){
- if(series[type] && series[type].show){
- this[Flotr._registeredTypes[type]](series);
- drawn = true;
- }
- }
-
- if(!drawn){
- this[Flotr._registeredTypes[this.options.defaultType]](series);
- }
- },
-
- plotLine: function(series, offset){
- var ctx = this.ctx,
- xa = series.xaxis,
- ya = series.yaxis,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this),
- data = series.data;
-
- if(data.length < 2) return;
-
- var prevx = tHoz(data[0][0], xa),
- prevy = tVert(data[0][1], ya) + offset;
- ctx.beginPath();
- ctx.moveTo(prevx, prevy);
- for(var i = 0; i < data.length - 1; ++i){
- var x1 = data[i][0], y1 = data[i][1],
- x2 = data[i+1][0], y2 = data[i+1][1];
-
- // To allow empty values
- if (y1 === null || y2 === null) continue;
-
- /**
- * Clip with ymin.
- */
- if(y1 <= y2 && y1 < ya.min){
- /**
- * Line segment is outside the drawing area.
- */
- if(y2 < ya.min) continue;
-
- /**
- * Compute new intersection point.
- */
- x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = ya.min;
- }else if(y2 <= y1 && y2 < ya.min){
- if(y1 < ya.min) continue;
- x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = ya.min;
- }
-
- /**
- * Clip with ymax.
- */
- if(y1 >= y2 && y1 > ya.max) {
- if(y2 > ya.max) continue;
- x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = ya.max;
- }
- else if(y2 >= y1 && y2 > ya.max){
- if(y1 > ya.max) continue;
- x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = ya.max;
- }
-
- /**
- * Clip with xmin.
- */
- if(x1 <= x2 && x1 < xa.min){
- if(x2 < xa.min) continue;
- y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = xa.min;
- }else if(x2 <= x1 && x2 < xa.min){
- if(x1 < xa.min) continue;
- y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = xa.min;
- }
-
- /**
- * Clip with xmax.
- */
- if(x1 >= x2 && x1 > xa.max){
- if (x2 > xa.max) continue;
- y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = xa.max;
- }else if(x2 >= x1 && x2 > xa.max){
- if(x1 > xa.max) continue;
- y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = xa.max;
- }
-
- if(prevx != tHoz(x1, xa) || prevy != tVert(y1, ya) + offset)
- ctx.moveTo(tHoz(x1, xa), tVert(y1, ya) + offset);
-
- prevx = tHoz(x2, xa);
- prevy = tVert(y2, ya) + offset;
- ctx.lineTo(prevx, prevy);
- }
- ctx.stroke();
- },
- /**
- * Function used to fill
- * @param {Object} data
- */
- plotLineArea: function(series, offset){
- var data = series.data;
- if(data.length < 2) return;
-
- var top, lastX = 0,
- ctx = this.ctx,
- xa = series.xaxis,
- ya = series.yaxis,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this),
- bottom = Math.min(Math.max(0, ya.min), ya.max),
- first = true;
-
- ctx.beginPath();
- for(var i = 0; i < data.length - 1; ++i){
-
- var x1 = data[i][0], y1 = data[i][1],
- x2 = data[i+1][0], y2 = data[i+1][1];
-
- if(x1 <= x2 && x1 < xa.min){
- if(x2 < xa.min) continue;
- y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = xa.min;
- }else if(x2 <= x1 && x2 < xa.min){
- if(x1 < xa.min) continue;
- y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = xa.min;
- }
-
- if(x1 >= x2 && x1 > xa.max){
- if(x2 > xa.max) continue;
- y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = xa.max;
- }else if(x2 >= x1 && x2 > xa.max){
- if (x1 > xa.max) continue;
- y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = xa.max;
- }
-
- if(first){
- ctx.moveTo(tHoz(x1, xa), tVert(bottom, ya) + offset);
- first = false;
- }
-
- /**
- * Now check the case where both is outside.
- */
- if(y1 >= ya.max && y2 >= ya.max){
- ctx.lineTo(tHoz(x1, xa), tVert(ya.max, ya) + offset);
- ctx.lineTo(tHoz(x2, xa), tVert(ya.max, ya) + offset);
- continue;
- }else if(y1 <= ya.min && y2 <= ya.min){
- ctx.lineTo(tHoz(x1, xa), tVert(ya.min, ya) + offset);
- ctx.lineTo(tHoz(x2, xa), tVert(ya.min, ya) + offset);
- continue;
- }
-
- /**
- * Else it's a bit more complicated, there might
- * be two rectangles and two triangles we need to fill
- * in; to find these keep track of the current x values.
- */
- var x1old = x1, x2old = x2;
-
- /**
- * And clip the y values, without shortcutting.
- * Clip with ymin.
- */
- if(y1 <= y2 && y1 < ya.min && y2 >= ya.min){
- x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = ya.min;
- }else if(y2 <= y1 && y2 < ya.min && y1 >= ya.min){
- x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = ya.min;
- }
-
- /**
- * Clip with ymax.
- */
- if(y1 >= y2 && y1 > ya.max && y2 <= ya.max){
- x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = ya.max;
- }else if(y2 >= y1 && y2 > ya.max && y1 <= ya.max){
- x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = ya.max;
- }
-
- /**
- * If the x value was changed we got a rectangle to fill.
- */
- if(x1 != x1old){
- top = (y1 <= ya.min) ? top = ya.min : ya.max;
- ctx.lineTo(tHoz(x1old, xa), tVert(top, ya) + offset);
- ctx.lineTo(tHoz(x1, xa), tVert(top, ya) + offset);
- }
-
- /**
- * Fill the triangles.
- */
- ctx.lineTo(tHoz(x1, xa), tVert(y1, ya) + offset);
- ctx.lineTo(tHoz(x2, xa), tVert(y2, ya) + offset);
-
- /**
- * Fill the other rectangle if it's there.
- */
- if(x2 != x2old){
- top = (y2 <= ya.min) ? ya.min : ya.max;
- ctx.lineTo(tHoz(x2old, xa), tVert(top, ya) + offset);
- ctx.lineTo(tHoz(x2, xa), tVert(top, ya) + offset);
- }
-
- lastX = Math.max(x2, x2old);
- }
-
- ctx.lineTo(tHoz(lastX, xa), tVert(bottom, ya) + offset);
- ctx.closePath();
- ctx.fill();
- },
- /**
- * Function: (private) drawSeriesLines
- *
- * Function draws lines series in the canvas element.
- *
- * Parameters:
- * series - Series with options.lines.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesLines: function(series){
- series = series || this.series;
- var ctx = this.ctx;
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
- ctx.lineJoin = 'round';
-
- var lw = series.lines.lineWidth;
- var sw = series.shadowSize;
-
- if(sw > 0){
- ctx.lineWidth = sw / 2;
-
- var offset = lw/2 + ctx.lineWidth/2;
-
- ctx.strokeStyle = "rgba(0,0,0,0.1)";
- this.plotLine(series, offset + sw/2);
-
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
- this.plotLine(series, offset);
-
- if(series.lines.fill) {
- ctx.fillStyle = "rgba(0,0,0,0.05)";
- this.plotLineArea(series, offset + sw/2);
- }
- }
-
- ctx.lineWidth = lw;
- ctx.strokeStyle = series.color;
- if(series.lines.fill){
- ctx.fillStyle = series.lines.fillColor != null ? series.lines.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.lines.fillOpacity).toString();
- this.plotLineArea(series, 0);
- }
-
- this.plotLine(series, 0);
- ctx.restore();
- },
- /**
- * Function: drawSeriesPoints
- *
- * Function draws point series in the canvas element.
- *
- * Parameters:
- * series - Series with options.points.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesPoints: function(series) {
- var ctx = this.ctx;
-
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
-
- var lw = series.lines.lineWidth;
- var sw = series.shadowSize;
-
- if(sw > 0){
- ctx.lineWidth = sw / 2;
-
- ctx.strokeStyle = 'rgba(0,0,0,0.1)';
- this.plotPointShadows(series, sw/2 + ctx.lineWidth/2, series.points.radius);
-
- ctx.strokeStyle = 'rgba(0,0,0,0.2)';
- this.plotPointShadows(series, ctx.lineWidth/2, series.points.radius);
- }
-
- ctx.lineWidth = series.points.lineWidth;
- ctx.strokeStyle = series.color;
- ctx.fillStyle = series.points.fillColor != null ? series.points.fillColor : series.color;
- this.plotPoints(series, series.points.radius, series.points.fill);
- ctx.restore();
- },
- plotPoints: function (series, radius, fill) {
- var xa = series.xaxis,
- ya = series.yaxis,
- ctx = this.ctx, i,
- data = series.data;
-
- for(i = data.length - 1; i > -1; --i){
- var x = data[i][0], y = data[i][1];
- if(x < xa.min || x > xa.max || y < ya.min || y > ya.max)
- continue;
-
- ctx.beginPath();
- ctx.arc(this.tHoz(x, xa), this.tVert(y, ya), radius, 0, 2 * Math.PI, true);
- if(fill) ctx.fill();
- ctx.stroke();
- }
- },
- plotPointShadows: function(series, offset, radius){
- var xa = series.xaxis,
- ya = series.yaxis,
- ctx = this.ctx, i,
- data = series.data;
-
- for(i = data.length - 1; i > -1; --i){
- var x = data[i][0], y = data[i][1];
- if (x < xa.min || x > xa.max || y < ya.min || y > ya.max)
- continue;
- ctx.beginPath();
- ctx.arc(this.tHoz(x, xa), this.tVert(y, ya) + offset, radius, 0, Math.PI, false);
- ctx.stroke();
- }
- },
- /**
- * Function: drawSeriesBars
- *
- * Function draws bar series in the canvas element.
- *
- * Parameters:
- * series - Series with options.bars.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesBars: function(series) {
- var ctx = this.ctx,
- bw = series.bars.barWidth,
- lw = Math.min(series.bars.lineWidth, bw);
-
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
- ctx.lineJoin = 'miter';
-
- /**
- * @todo linewidth not interpreted the right way.
- */
- ctx.lineWidth = lw;
- ctx.strokeStyle = series.color;
-
- this.plotBarsShadows(series, bw, 0, series.bars.fill);
-
- if(series.bars.fill){
- ctx.fillStyle = series.bars.fillColor != null ? series.bars.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.bars.fillOpacity).toString();
- }
-
- this.plotBars(series, bw, 0, series.bars.fill);
- ctx.restore();
- },
- plotBars: function(series, barWidth, offset, fill){
- var data = series.data;
- if(data.length < 1) return;
-
- var xa = series.xaxis,
- ya = series.yaxis,
- ctx = this.ctx,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this);
-
- for(var i = 0; i < data.length; i++){
- var x = data[i][0],
- y = data[i][1];
- var drawLeft = true, drawTop = true, drawRight = true;
-
- // Stacked bars
- var stackOffset = 0;
- if(series.bars.stacked) {
- xa.values.each(function(o, v) {
- if (v == x) {
- stackOffset = o.stack || 0;
- o.stack = stackOffset + y;
- }
- });
- }
-
- // @todo: fix horizontal bars support
- // Horizontal bars
- if(series.bars.horizontal)
- var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
- else
- var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;
-
- if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
- continue;
-
- if(left < xa.min){
- left = xa.min;
- drawLeft = false;
- }
-
- if(right > xa.max){
- right = xa.max;
- if (xa.lastSerie != series && series.bars.horizontal)
- drawTop = false;
- }
-
- if(bottom < ya.min)
- bottom = ya.min;
-
- if(top > ya.max){
- top = ya.max;
- if (ya.lastSerie != series && !series.bars.horizontal)
- drawTop = false;
- }
-
- /**
- * Fill the bar.
- */
- if(fill){
- ctx.beginPath();
- ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
- ctx.lineTo(tHoz(left, xa), tVert(top, ya) + offset);
- ctx.lineTo(tHoz(right, xa), tVert(top, ya) + offset);
- ctx.lineTo(tHoz(right, xa), tVert(bottom, ya) + offset);
- ctx.fill();
- }
-
- /**
- * Draw bar outline/border.
- */
- if(series.bars.lineWidth != 0 && (drawLeft || drawRight || drawTop)){
- ctx.beginPath();
- ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
-
- ctx[drawLeft ?'lineTo':'moveTo'](tHoz(left, xa), tVert(top, ya) + offset);
- ctx[drawTop ?'lineTo':'moveTo'](tHoz(right, xa), tVert(top, ya) + offset);
- ctx[drawRight?'lineTo':'moveTo'](tHoz(right, xa), tVert(bottom, ya) + offset);
-
- ctx.stroke();
- }
- }
- },
- plotBarsShadows: function(series, barWidth, offset){
- var data = series.data;
- if(data.length < 1) return;
-
- var xa = series.xaxis,
- ya = series.yaxis,
- ctx = this.ctx,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this),
- sw = this.options.shadowSize;
-
- for(var i = 0; i < data.length; i++){
- var x = data[i][0],
- y = data[i][1];
-
- // Stacked bars
- var stackOffset = 0;
- if(series.bars.stacked) {
- xa.values.each(function(o, v) {
- if (v == x) {
- stackOffset = o.stackShadow || 0;
- o.stackShadow = stackOffset + y;
- }
- });
- }
-
- // Horizontal bars
- if(series.bars.horizontal)
- var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
- else
- var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;
-
- if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
- continue;
-
- if(left < xa.min) left = xa.min;
- if(right > xa.max) right = xa.max;
- if(bottom < ya.min) bottom = ya.min;
- if(top > ya.max) top = ya.max;
-
- var width = tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);
- var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));
-
- ctx.fillStyle = 'rgba(0,0,0,0.05)';
- ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);
- }
- },
- /**
- * Function: drawSeriesCandles
- *
- * Function draws candles series in the canvas element.
- *
- * Parameters:
- * series - Series with options.candles.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesCandles: function(series) {
- var ctx = this.ctx,
- bw = series.candles.candleWidth;
-
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
- ctx.lineJoin = 'miter';
-
- /**
- * @todo linewidth not interpreted the right way.
- */
- ctx.lineWidth = series.candles.lineWidth;
- this.plotCandlesShadows(series, bw/2);
- this.plotCandles(series, bw/2);
-
- ctx.restore();
- },
- plotCandles: function(series, offset){
- var data = series.data;
- if(data.length < 1) return;
-
- var xa = series.xaxis,
- ya = series.yaxis,
- ctx = this.ctx,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this);
-
- for(var i = 0; i < data.length; i++){
- var d = data[i],
- x = d[0],
- open = d[1],
- high = d[2],
- low = d[3],
- close = d[4];
-
- var left = x,
- right = x + series.candles.candleWidth,
- bottom = Math.max(ya.min, low),
- top = Math.min(ya.max, high),
- bottom2 = Math.max(ya.min, Math.min(open, close)),
- top2 = Math.min(ya.max, Math.max(open, close));
-
- if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
- continue;
-
- var color = series.candles[open>close?'downFillColor':'upFillColor'];
- /**
- * Fill the candle.
- */
- if(series.candles.fill && !series.candles.barcharts){
- ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.candles.fillOpacity).toString();
- ctx.fillRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));
- }
-
- /**
- * Draw candle outline/border, high, low.
- */
- if(series.candles.lineWidth || series.candles.wickLineWidth){
- var x, y, pixelOffset = (series.candles.wickLineWidth % 2) / 2;
-
- x = Math.floor(tHoz((left + right) / 2), xa) + pixelOffset;
-
- ctx.save();
- ctx.strokeStyle = color;
- ctx.lineWidth = series.candles.wickLineWidth;
- ctx.lineCap = 'butt';
-
- if (series.candles.barcharts) {
- ctx.beginPath();
-
- ctx.moveTo(x, Math.floor(tVert(top, ya) + offset));
- ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));
-
- y = Math.floor(tVert(open, ya) + offset)+0.5;
- ctx.moveTo(Math.floor(tHoz(left, xa))+pixelOffset, y);
- ctx.lineTo(x, y);
-
- y = Math.floor(tVert(close, ya) + offset)+0.5;
- ctx.moveTo(Math.floor(tHoz(right, xa))+pixelOffset, y);
- ctx.lineTo(x, y);
- }
- else {
- ctx.strokeRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));
-
- ctx.beginPath();
- ctx.moveTo(x, Math.floor(tVert(top2, ya) + offset));
- ctx.lineTo(x, Math.floor(tVert(top, ya) + offset));
- ctx.moveTo(x, Math.floor(tVert(bottom2, ya) + offset));
- ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));
- }
-
- ctx.stroke();
- ctx.restore();
- }
- }
- },
- plotCandlesShadows: function(series, offset){
- var data = series.data;
- if(data.length < 1 || series.candles.barcharts) return;
-
- var xa = series.xaxis,
- ya = series.yaxis,
- tHoz = this.tHoz.bind(this),
- tVert = this.tVert.bind(this),
- sw = this.options.shadowSize;
-
- for(var i = 0; i < data.length; i++){
- var d = data[i],
- x = d[0],
- open = d[1],
- high = d[2],
- low = d[3],
- close = d[4];
-
- var left = x,
- right = x + series.candles.candleWidth,
- bottom = Math.max(ya.min, Math.min(open, close)),
- top = Math.min(ya.max, Math.max(open, close));
-
- if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
- continue;
-
- var width = tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);
- var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));
-
- this.ctx.fillStyle = 'rgba(0,0,0,0.05)';
- this.ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);
- }
- },
- /**
- * Function: drawSeriesRadar
- *
- * Function draws a radar chart on the canvas element.
- *
- * Parameters:
- * series - Series with options.radar.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesRadar: function(series) {
- var ctx = this.ctx,
- options = this.options, sides= series.data.length;
-
- var degreesInRadiansForAngle = Math.PI * 2 / sides,
- nintyDegrees = Math.PI / 2;
-
- var poly = {};
-
- /*
- Draw radar grid
-
- poly.xaxis = series.xaxis;
- poly.yaxis = series.yaxis;
- ctx.save();
- ctx.translate(this.plotOffset.left, this.plotOffset.top);
- ctx.lineJoin = 'round';
- for (radius = 20; radius <= 100; radius += 20) {
- poly.data = new Array();
- for (i = 0; i < sides; i++) {
- angle = nintyDegrees + (degreesInRadiansForAngle * i);
- poly.data[i] = [radius * Math.cos(angle), radius * Math.sin(angle)]
- }
- poly.data[sides] = poly.data[0];
- this.plotLine(poly,0);}
-
- var outside = poly.data;
- for (i = 0; i < sides; i++) {
- poly.data = new Array();
- poly.data[0] = [0,0];
- poly.data[1] = outside[i];
- this.plotLine(poly,0);
- }
- */
-
- /*
- Convert Series data into X, Y co-ordinates
- */
- if (!series.dataInRadarFormat) {
- poly.data = new Array();
- for (i = 0; i < sides; i++) {
- angle = nintyDegrees + (degreesInRadiansForAngle * i);
- poly.data[i] = [series.data[i][1] * Math.cos(angle), series.data[i][1] * Math.sin(angle), series.data[i][0], series.data[i][1]]
- }
- poly.data[sides] = poly.data[0];
- series.data = poly.data;
- series.lines = series.radar;
- series.lines.show = false;
- series.dataInRadarFormat = true;
- }
-
- this.drawSeriesLines(series);
-
-},
-
-
- /**
- * Function: drawSeriesPie
- *
- * Function draws a pie in the canvas element.
- *
- * Parameters:
- * series - Series with options.pie.show = true.
- *
- * Returns:
- * void
- */
- drawSeriesPie: function(series) {
- if (!this.options.pie.drawn) {
- var ctx = this.ctx,
- options = this.options,
- lw = series.pie.lineWidth,
- sw = series.shadowSize,
- data = series.data,
- radius = (Math.min(this.canvasWidth, this.canvasHeight) * series.pie.sizeRatio) / 2,
- html = [];
-
- var vScale = 1;//Math.cos(series.pie.viewAngle);
- var plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;
-
- var style = {
- size: options.fontSize*1.2,
- color: options.grid.color,
- weight: 1.5
- };
-
- var center = {
- x: (this.canvasWidth+this.plotOffset.left)/2,
- y: (this.canvasHeight-this.plotOffset.bottom)/2
- };
-
- // Pie portions
- var portions = this.series.collect(function(hash, index){
- if (hash.pie.show)
- return {
- name: (hash.label || hash.data[0][1]),
- value: [index, hash.data[0][1]],
- explode: hash.pie.explode
- };
- });
-
- // Sum of the portions' angles
- var sum = portions.pluck('value').pluck(1).inject(0, function(acc, n) { return acc + n; });
-
- var fraction = 0.0,
- angle = series.pie.startAngle,
- value = 0.0;
-
- var slices = portions.collect(function(slice){
- angle += fraction;
- value = parseFloat(slice.value[1]); // @warning : won't support null values !!
- fraction = value/sum;
- return {
- name: slice.name,
- fraction: fraction,
- x: slice.value[0],
- y: value,
- explode: slice.explode,
- startAngle: 2 * angle * Math.PI,
- endAngle: 2 * (angle + fraction) * Math.PI
- };
- });
-
- ctx.save();
-
- if(sw > 0){
- slices.each(function (slice) {
- var bisection = (slice.startAngle + slice.endAngle) / 2;
-
- var xOffset = center.x + Math.cos(bisection) * slice.explode + sw;
- var yOffset = center.y + Math.sin(bisection) * slice.explode + sw;
-
- this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);
-
- ctx.fillStyle = 'rgba(0,0,0,0.1)';
- ctx.fill();
- }, this);
- }
-
- if (options.HtmlText) {
- html = ['<div style="color:' + this.options.grid.color + '" class="flotr-labels">'];
- }
-
- slices.each(function (slice, index) {
- var bisection = (slice.startAngle + slice.endAngle) / 2;
- var color = options.colors[index];
-
- var xOffset = center.x + Math.cos(bisection) * slice.explode;
- var yOffset = center.y + Math.sin(bisection) * slice.explode;
-
- this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);
-
- if(series.pie.fill){
- ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();
- ctx.fill();
- }
- ctx.lineWidth = lw;
- ctx.strokeStyle = color;
- ctx.stroke();
-
- /*ctx.save();
- ctx.scale(1, vScale);
-
- ctx.moveTo(xOffset, yOffset);
- ctx.beginPath();
- ctx.lineTo(xOffset, yOffset+plotTickness);
- ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);
- ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);
- ctx.lineTo(xOffset, yOffset);
- ctx.closePath();
- ctx.fill();ctx.stroke();
-
- ctx.moveTo(xOffset, yOffset);
- ctx.beginPath();
- ctx.lineTo(xOffset, yOffset+plotTickness);
- ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius+plotTickness);
- ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);
- ctx.lineTo(xOffset, yOffset);
- ctx.closePath();
- ctx.fill();ctx.stroke();
-
- ctx.moveTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);
- ctx.beginPath();
- ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);
- ctx.arc(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false);
- ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);
- ctx.arc(xOffset, yOffset, radius, slice.endAngle, slice.startAngle, true);
- ctx.closePath();
- ctx.fill();ctx.stroke();
-
- ctx.scale(1, 1/vScale);
- this.plotSlice(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false, vScale);
- ctx.stroke();
- if(series.pie.fill){
- ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();
- ctx.fill();
- }
-
- ctx.restore();*/
-
- var label = options.pie.labelFormatter(slice);
-
- var textAlignRight = (Math.cos(bisection) < 0);
- var distX = xOffset + Math.cos(bisection) * (series.pie.explode + radius);
- var distY = yOffset + Math.sin(bisection) * (series.pie.explode + radius);
-
- if (slice.fraction && label) {
- if (options.HtmlText) {
- var divStyle = 'position:absolute;top:' + (distY - 5) + 'px;'; //@todo: change
- if (textAlignRight) {
- divStyle += 'right:'+(this.canvasWidth - distX)+'px;text-align:right;';
- }
- else {
- divStyle += 'left:'+distX+'px;text-align:left;';
- }
- html.push('<div style="' + divStyle + '" class="flotr-grid-label">' + label + '</div>');
- }
- else {
- style.halign = textAlignRight ? 'r' : 'l';
- ctx.drawText(
- label,
- distX,
- distY + style.size / 2,
- style
- );
- }
- }
- }, this);
-
- if (options.HtmlText) {
- html.push('</div>');
- this.el.insert(html.join(''));
- }
-
- ctx.restore();
- options.pie.drawn = true;
- }
- },
- plotSlice: function(x, y, radius, startAngle, endAngle, fill, vScale) {
- var ctx = this.ctx;
- vScale = vScale || 1;
-
- ctx.save();
- ctx.scale(1, vScale);
- ctx.beginPath();
- ctx.moveTo(x, y);
- ctx.arc (x, y, radius, startAngle, endAngle, fill);
- ctx.lineTo(x, y);
- ctx.closePath();
- ctx.restore();
- },
- plotPie: function() {},
- /**
- * Function: insertLegend
- *
- * Function adds a legend div to the canvas container or draws it on the canvas.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- insertLegend: function(){
- if(!this.options.legend.show)
- return;
-
- var series = this.series,
- plotOffset = this.plotOffset,
- options = this.options,
- fragments = [],
- rowStarted = false,
- ctx = this.ctx,
- i;
-
- var noLegendItems = series.findAll(function(s) {return (s.label && !s.hide)}).size();
-
- if (noLegendItems) {
- if (!options.HtmlText && this.textEnabled) {
- var style = {
- size: options.fontSize*1.1,
- color: options.grid.color
- };
-
- // @todo: take css into account
- //var dummyDiv = this.el.insert('<div class="flotr-legend" style="position:absolute;top:-10000px;"></div>');
-
- var p = options.legend.position,
- m = options.legend.margin,
- lbw = options.legend.labelBoxWidth,
- lbh = options.legend.labelBoxHeight,
- lbm = options.legend.labelBoxMargin,
- offsetX = plotOffset.left + m,
- offsetY = plotOffset.top + m;
-
- // We calculate the labels' max width
- var labelMaxWidth = 0;
- for(i = series.length - 1; i > -1; --i){
- if(!series[i].label || series[i].hide) continue;
- var label = options.legend.labelFormatter(series[i].label);
- labelMaxWidth = Math.max(labelMaxWidth, ctx.measureText(label, style));
- }
-
- var legendWidth = Math.round(lbw + lbm*3 + labelMaxWidth),
- legendHeight = Math.round(noLegendItems*(lbm+lbh) + lbm);
-
- if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight);
- if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth);
-
- // Legend box
- var color = Flotr.parseColor(options.legend.backgroundColor || 'rgb(240,240,240)').scale(null, null, null, options.legend.backgroundOpacity || 0.1).toString();
-
- ctx.fillStyle = color;
- ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight);
- ctx.strokeStyle = options.legend.labelBoxBorderColor;
- ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight);
-
- // Legend labels
- var x = offsetX + lbm;
- var y = offsetY + lbm;
- for(i = 0; i < series.length; i++){
- if(!series[i].label || series[i].hide) continue;
- var label = options.legend.labelFormatter(series[i].label);
-
- ctx.fillStyle = series[i].color;
- ctx.fillRect(x, y, lbw-1, lbh-1);
-
- ctx.strokeStyle = options.legend.labelBoxBorderColor;
- ctx.lineWidth = 1;
- ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2);
-
- // Legend text
- ctx.drawText(
- label,
- x + lbw + lbm,
- y + (lbh + style.size - ctx.fontDescent(style))/2,
- style
- );
-
- y += lbh + lbm;
- }
- }
- else {
- for(i = 0; i < series.length; ++i){
- if(!series[i].label || series[i].hide) continue;
-
- if(i % options.legend.noColumns == 0){
- fragments.push(rowStarted ? '</tr><tr>' : '<tr>');
- rowStarted = true;
- }
-
- var label = options.legend.labelFormatter(series[i].label);
-
- fragments.push('<td class="flotr-legend-color-box"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:' + options.legend.labelBoxWidth + 'px;height:' + options.legend.labelBoxHeight + 'px;background-color:' + series[i].color + '"></div></div></td>' +
- '<td class="flotr-legend-label">' + label + '</td>');
- }
- if(rowStarted) fragments.push('</tr>');
-
- if(fragments.length > 0){
- var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
- if(options.legend.container != null){
- $(options.legend.container).update(table);
- }else{
- var pos = '';
- var p = options.legend.position, m = options.legend.margin;
-
- if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';
- else if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';
- if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';
- else if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';
-
- var div = this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;' + pos +'">' + table + '</div>').select('div.flotr-legend').first();
-
- if(options.legend.backgroundOpacity != 0.0){
- /**
- * Put in the transparent background separately to avoid blended labels and
- * label boxes.
- */
- var c = options.legend.backgroundColor;
- if(c == null){
- var tmp = (options.grid.backgroundColor != null) ? options.grid.backgroundColor : Flotr.extractColor(div);
- c = Flotr.parseColor(tmp).adjust(null, null, null, 1).toString();
- }
- this.el.insert('<div class="flotr-legend-bg" style="position:absolute;width:' + div.getWidth() + 'px;height:' + div.getHeight() + 'px;' + pos +'background-color:' + c + ';"> </div>').select('div.flotr-legend-bg').first().setStyle({
- 'opacity': options.legend.backgroundOpacity
- });
- }
- }
- }
- }
- }
- },
- /**
- * Function: getEventPosition
- *
- * Calculates the coordinates from a mouse event object.
- *
- * Parameters:
- * event - Mouse Event object.
- *
- * Returns:
- * Object with x and y coordinates of the mouse.
- */
- getEventPosition: function (event){
- var offset = this.overlay.cumulativeOffset(),
- rx = (event.pageX - offset.left - this.plotOffset.left),
- ry = (event.pageY - offset.top - this.plotOffset.top),
- ax = 0, ay = 0
-
- if(event.pageX == null && event.clientX != null){
- var de = document.documentElement, b = document.body;
- ax = event.clientX + (de && de.scrollLeft || b.scrollLeft || 0);
- ay = event.clientY + (de && de.scrollTop || b.scrollTop || 0);
- }else{
- ax = event.pageX;
- ay = event.pageY;
- }
-
- return {
- x: this.axes.x.min + rx / this.axes.x.scale,
- x2: this.axes.x2.min + rx / this.axes.x2.scale,
- y: this.axes.y.max - ry / this.axes.y.scale,
- y2: this.axes.y2.max - ry / this.axes.y2.scale,
- relX: rx,
- relY: ry,
- absX: ax,
- absY: ay
- };
- },
- /**
- * Function: clickHandler
- *
- * Handler observes the 'click' event and fires the 'flotr:click' event.
- *
- * Parameters:
- * event - 'click' Event object.
- *
- * Returns:
- * void
- */
- clickHandler: function(event){
- if(this.ignoreClick){
- this.ignoreClick = false;
- return;
- }
- this.el.fire('flotr:click', [this.getEventPosition(event), this]);
- },
- /**
- * Function: mouseMoveHandler
- *
- * Handler observes mouse movement over the graph area. Fires the
- * 'flotr:mousemove' event.
- *
- * Parameters:
- * event - 'mousemove' Event object.
- *
- * Returns:
- * void
- */
- mouseMoveHandler: function(event){
- var pos = this.getEventPosition(event);
-
- this.lastMousePos.pageX = pos.absX;
- this.lastMousePos.pageY = pos.absY;
- if(this.selectionInterval == null && (this.options.mouse.track || this.series.any(function(s){return s.mouse && s.mouse.track;}))){
- this.hit(pos);
- }
-
- this.el.fire('flotr:mousemove', [event, pos, this]);
- },
- /**
- * Function: mouseDownHandler
- *
- * Handler observes the 'mousedown' event.
- *
- * Parameters:
- * event - 'mousedown' Event object.
- *
- * Returns:
- * void
- */
- mouseDownHandler: function (event){
- if(event.isRightClick()) {
- event.stop();
- var overlay = this.overlay;
- overlay.hide();
-
- function cancelContextMenu () {
- overlay.show();
- $(document).stopObserving('mousemove', cancelContextMenu);
- }
- $(document).observe('mousemove', cancelContextMenu);
- return;
- }
-
- if(!this.options.selection.mode || !event.isLeftClick()) return;
-
- this.setSelectionPos(this.selection.first, event);
- if(this.selectionInterval != null){
- clearInterval(this.selectionInterval);
- }
- this.lastMousePos.pageX = null;
- this.selectionInterval = setInterval(this.updateSelection.bind(this), 1000/this.options.selection.fps);
-
- this.mouseUpHandler = this.mouseUpHandler.bind(this);
- $(document).observe('mouseup', this.mouseUpHandler);
- },
- /**
- * Function: (private) fireSelectEvent
- *
- * Fires the 'flotr:select' event when the user made a selection.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- fireSelectEvent: function(){
- var a = this.axes, selection = this.selection,
- x1 = (selection.first.x <= selection.second.x) ? selection.first.x : selection.second.x,
- x2 = (selection.first.x <= selection.second.x) ? selection.second.x : selection.first.x,
- y1 = (selection.first.y >= selection.second.y) ? selection.first.y : selection.second.y,
- y2 = (selection.first.y >= selection.second.y) ? selection.second.y : selection.first.y;
-
- x1 = a.x.min + x1 / a.x.scale;
- x2 = a.x.min + x2 / a.x.scale;
- y1 = a.y.max - y1 / a.y.scale;
- y2 = a.y.max - y2 / a.y.scale;
-
- this.el.fire('flotr:select', [{x1:x1, y1:y1, x2:x2, y2:y2}, this]);
- },
- /**
- * Function: (private) mouseUpHandler
- *
- * Handler observes the mouseup event for the document.
- *
- * Parameters:
- * event - 'mouseup' Event object.
- *
- * Returns:
- * void
- */
- mouseUpHandler: function(event){
- $(document).stopObserving('mouseup', this.mouseUpHandler);
- event.stop();
-
- if(this.selectionInterval != null){
- clearInterval(this.selectionInterval);
- this.selectionInterval = null;
- }
-
- this.setSelectionPos(this.selection.second, event);
- this.clearSelection();
-
- if(this.selectionIsSane()){
- this.drawSelection();
- this.fireSelectEvent();
- this.ignoreClick = true;
- }
- },
- /**
- * Function: setSelectionPos
- *
- * Calculates the position of the selection.
- *
- * Parameters:
- * pos - Position object.
- * event - Event object.
- *
- * Returns:
- * void
- */
- setSelectionPos: function(pos, event) {
- var options = this.options,
- offset = $(this.overlay).cumulativeOffset();
-
- if(options.selection.mode.indexOf('x') == -1){
- pos.x = (pos == this.selection.first) ? 0 : this.plotWidth;
- }else{
- pos.x = event.pageX - offset.left - this.plotOffset.left;
- pos.x = Math.min(Math.max(0, pos.x), this.plotWidth);
- }
-
- if (options.selection.mode.indexOf('y') == -1){
- pos.y = (pos == this.selection.first) ? 0 : this.plotHeight;
- }else{
- pos.y = event.pageY - offset.top - this.plotOffset.top;
- pos.y = Math.min(Math.max(0, pos.y), this.plotHeight);
- }
- },
- /**
- * Function: updateSelection
- *
- * Updates (draws) the selection box.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- updateSelection: function(){
- if(this.lastMousePos.pageX == null) return;
-
- this.setSelectionPos(this.selection.second, this.lastMousePos);
- this.clearSelection();
-
- if(this.selectionIsSane()) this.drawSelection();
- },
- /**
- * Function: clearSelection
- *
- * Removes the selection box from the overlay canvas.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- clearSelection: function() {
- if(this.prevSelection == null) return;
-
- var prevSelection = this.prevSelection,
- octx = this.octx,
- plotOffset = this.plotOffset,
- x = Math.min(prevSelection.first.x, prevSelection.second.x),
- y = Math.min(prevSelection.first.y, prevSelection.second.y),
- w = Math.abs(prevSelection.second.x - prevSelection.first.x),
- h = Math.abs(prevSelection.second.y - prevSelection.first.y);
-
- octx.clearRect(x + plotOffset.left - octx.lineWidth,
- y + plotOffset.top - octx.lineWidth,
- w + octx.lineWidth*2,
- h + octx.lineWidth*2);
-
- this.prevSelection = null;
- },
- /**
- * Function: setSelection
- *
- * Allows the user the manually select an area.
- *
- * Parameters:
- * area - Object with coordinates to select.
- *
- * Returns:
- * void
- */
- setSelection: function(area){
- var options = this.options,
- xa = this.axes.x,
- ya = this.axes.y,
- vertScale = yaxis.scale,
- hozScale = xaxis.scale,
- selX = options.selection.mode.indexOf('x') != -1,
- selY = options.selection.mode.indexOf('y') != -1;
-
- this.clearSelection();
-
- this.selection.first.y = selX ? 0 : (ya.max - area.y1) * vertScale;
- this.selection.second.y = selX ? this.plotHeight : (ya.max - area.y2) * vertScale;
- this.selection.first.x = selY ? 0 : (area.x1 - xa.min) * hozScale;
- this.selection.second.x = selY ? this.plotWidth : (area.x2 - xa.min) * hozScale;
-
- this.drawSelection();
- this.fireSelectEvent();
- },
- /**
- * Function: (private) drawSelection
- *
- * Draws the selection box.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- drawSelection: function() {
- var prevSelection = this.prevSelection,
- selection = this.selection,
- octx = this.octx,
- options = this.options,
- plotOffset = this.plotOffset;
-
- if(prevSelection != null &&
- selection.first.x == prevSelection.first.x &&
- selection.first.y == prevSelection.first.y &&
- selection.second.x == prevSelection.second.x &&
- selection.second.y == prevSelection.second.y)
- return;
-
- octx.strokeStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.8).toString();
- octx.lineWidth = 1;
- octx.lineJoin = 'round';
- octx.fillStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.4).toString();
-
- this.prevSelection = {
- first: { x: selection.first.x, y: selection.first.y },
- second: { x: selection.second.x, y: selection.second.y }
- };
-
- var x = Math.min(selection.first.x, selection.second.x),
- y = Math.min(selection.first.y, selection.second.y),
- w = Math.abs(selection.second.x - selection.first.x),
- h = Math.abs(selection.second.y - selection.first.y);
-
- octx.fillRect(x + plotOffset.left, y + plotOffset.top, w, h);
- octx.strokeRect(x + plotOffset.left, y + plotOffset.top, w, h);
- },
- /**
- * Function: (private) selectionIsSane
- *
- * Determines whether or not the selection is sane and should be drawn.
- *
- * Parameters:
- * none
- *
- * Returns:
- * boolean - True when sane, false otherwise.
- */
- selectionIsSane: function(){
- var selection = this.selection;
- return Math.abs(selection.second.x - selection.first.x) >= 5 &&
- Math.abs(selection.second.y - selection.first.y) >= 5;
- },
- /**
- * Function: clearHit
- *
- * Removes the mouse tracking point from the overlay.
- *
- * Parameters:
- * none
- *
- * Returns:
- * void
- */
- clearHit: function(){
- if(this.prevHit){
- var options = this.options,
- plotOffset = this.plotOffset,
- prevHit = this.prevHit;
-
- this.octx.clearRect(
- this.tHoz(prevHit.x) + plotOffset.left - options.points.radius*2,
- this.tVert(prevHit.y) + plotOffset.top - options.points.radius*2,
- options.points.radius*3 + options.points.lineWidth*3,
- options.points.radius*3 + options.points.lineWidth*3
- );
- this.prevHit = null;
- }
- },
- /**
- * Function: hit
- *
- * Retrieves the nearest data point from the mouse cursor. If it's within
- * a certain range, draw a point on the overlay canvas and display the x and y
- * value of the data.
- *
- * Parameters:
- * mouse - Object that holds the relative x and y coordinates of the cursor.
- *
- * Returns:
- * void
- */
- hit: function(mouse){
- var series = this.series,
- options = this.options,
- prevHit = this.prevHit,
- plotOffset = this.plotOffset,
- octx = this.octx,
- data, xsens, ysens,
- /**
- * Nearest data element.
- */
- i, n = {
- dist:Number.MAX_VALUE,
- x:null,
- y:null,
- relX:mouse.relX,
- relY:mouse.relY,
- absX:mouse.absX,
- absY:mouse.absY,
- mouse:null,
- radarData:null
- };
-
- for(i = 0; i < series.length; i++){
- s = series[i];
- if(!s.mouse.track) continue;
- data = s.data;
- xsens = (s.xaxis.scale*s.mouse.sensibility);
- ysens = (s.yaxis.scale*s.mouse.sensibility);
-
- for(var j = 0, xpow, ypow; j < data.length; j++){
- if (data[j][1] === null) continue;
- xpow = Math.pow(s.xaxis.scale*(data[j][0] - mouse.x), 2);
- ypow = Math.pow(s.yaxis.scale*(data[j][1] - mouse.y), 2);
- if(xpow < xsens && ypow < ysens && Math.sqrt(xpow+ypow) < n.dist){
- n.dist = Math.sqrt(xpow+ypow);
- n.x = data[j][0];
- n.y = data[j][1];
- n.radarLabel = data[j][2];
- n.radarData = data[j][3];
- n.mouse = s.mouse;
- }
- }
- }
-
- if(n.mouse && n.mouse.track && !prevHit || (prevHit && (n.x != prevHit.x || n.y != prevHit.y))){
- var mt = this.mouseTrack || this.el.select(".flotr-mouse-value")[0],
- pos = '',
- p = options.mouse.position,
- m = options.mouse.margin,
- elStyle = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;';
-
- if (!options.mouse.relative) { // absolute to the canvas
- if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';
- else if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';
- if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';
- else if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';
- }
- else { // relative to the mouse
- if(p.charAt(0) == 'n') pos += 'bottom:' + (m - plotOffset.top - this.tVert(n.y) + this.canvasHeight) + 'px;';
- else if(p.charAt(0) == 's') pos += 'top:' + (m + plotOffset.top + this.tVert(n.y)) + 'px;';
- if(p.charAt(1) == 'e') pos += 'left:' + (m + plotOffset.left + this.tHoz(n.x)) + 'px;';
- else if(p.charAt(1) == 'w') pos += 'right:' + (m - plotOffset.left - this.tHoz(n.x) + this.canvasWidth) + 'px;';
- }
-
- elStyle += pos;
-
- if(!mt){
- this.el.insert('<div class="flotr-mouse-value" style="'+elStyle+'"></div>');
- mt = this.mouseTrack = this.el.select('.flotr-mouse-value').first();
- }
- else {
- this.mouseTrack = mt.setStyle(elStyle);
- }
-
- if(n.x !== null && n.y !== null){
- mt.show();
-
- this.clearHit();
- if(n.mouse.lineColor != null){
- octx.save();
- octx.translate(plotOffset.left, plotOffset.top);
- octx.lineWidth = options.points.lineWidth;
- octx.strokeStyle = n.mouse.lineColor;
- octx.fillStyle = '#ffffff';
- octx.beginPath();
- octx.arc(this.tHoz(n.x), this.tVert(n.y), options.mouse.radius, 0, 2 * Math.PI, true);
- octx.fill();
- octx.stroke();
- octx.restore();
- }
- this.prevHit = n;
-
- var decimals = n.mouse.trackDecimals;
- if(decimals == null || decimals < 0) decimals = 0;
-
- mt.innerHTML = n.mouse.trackFormatter({x: n.x.toFixed(decimals), y: n.y.toFixed(decimals),
- radarLabel: n.radarLabel, radarData: n.radarData.toFixed(decimals)});
- mt.fire('flotr:hit', [n, this]);
- }
- else if(prevHit){
- mt.hide();
- this.clearHit();
- }
- }
- },
- saveImage: function (type, width, height, replaceCanvas) {
- var image = null;
- switch (type) {
- case 'jpeg':
- case 'jpg': image = Canvas2Image.saveAsJPEG(this.canvas, replaceCanvas, width, height); break;
- default:
- case 'png': image = Canvas2Image.saveAsPNG(this.canvas, replaceCanvas, width, height); break;
- case 'bmp': image = Canvas2Image.saveAsBMP(this.canvas, replaceCanvas, width, height); break;
- }
- if (Object.isElement(image) && replaceCanvas) {
- this.restoreCanvas();
- this.canvas.hide();
- this.overlay.hide();
- this.el.insert(image.setStyle({position: 'absolute'}));
- }
- },
- restoreCanvas: function() {
- this.canvas.show();
- this.overlay.show();
- this.el.select('img').invoke('remove');
- }
-});
-
-Flotr.Color = Class.create({
- initialize: function(r, g, b, a){
- this.rgba = ['r','g','b','a'];
- var x = 4;
- while(-1<--x){
- this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
- }
- this.normalize();
- },
-
- adjust: function(rd, gd, bd, ad) {
- var x = 4;
- while(-1<--x){
- if(arguments[x] != null)
- this[this.rgba[x]] += arguments[x];
- }
- return this.normalize();
- },
-
- clone: function(){
- return new Flotr.Color(this.r, this.b, this.g, this.a);
- },
-
- limit: function(val,minVal,maxVal){
- return Math.max(Math.min(val, maxVal), minVal);
- },
-
- normalize: function(){
- var limit = this.limit;
- this.r = limit(parseInt(this.r), 0, 255);
- this.g = limit(parseInt(this.g), 0, 255);
- this.b = limit(parseInt(this.b), 0, 255);
- this.a = limit(this.a, 0, 1);
- return this;
- },
-
- scale: function(rf, gf, bf, af){
- var x = 4;
- while(-1<--x){
- if(arguments[x] != null)
- this[this.rgba[x]] *= arguments[x];
- }
- return this.normalize();
- },
-
- distance: function(color){
- if (!color) return;
- color = new Flotr.parseColor(color);
- var dist = 0;
- var x = 3;
- while(-1<--x){
- dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);
- }
- return dist;
- },
-
- toString: function(){
- return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')';
- }
-});
-
-Flotr.Color.lookupColors = {
- aqua:[0,255,255],
- azure:[240,255,255],
- beige:[245,245,220],
- black:[0,0,0],
- blue:[0,0,255],
- brown:[165,42,42],
- cyan:[0,255,255],
- darkblue:[0,0,139],
- darkcyan:[0,139,139],
- darkgrey:[169,169,169],
- darkgreen:[0,100,0],
- darkkhaki:[189,183,107],
- darkmagenta:[139,0,139],
- darkolivegreen:[85,107,47],
- darkorange:[255,140,0],
- darkorchid:[153,50,204],
- darkred:[139,0,0],
- darksalmon:[233,150,122],
- darkviolet:[148,0,211],
- fuchsia:[255,0,255],
- gold:[255,215,0],
- green:[0,128,0],
- indigo:[75,0,130],
- khaki:[240,230,140],
- lightblue:[173,216,230],
- lightcyan:[224,255,255],
- lightgreen:[144,238,144],
- lightgrey:[211,211,211],
- lightpink:[255,182,193],
- lightyellow:[255,255,224],
- lime:[0,255,0],
- magenta:[255,0,255],
- maroon:[128,0,0],
- navy:[0,0,128],
- olive:[128,128,0],
- orange:[255,165,0],
- pink:[255,192,203],
- purple:[128,0,128],
- violet:[128,0,128],
- red:[255,0,0],
- silver:[192,192,192],
- white:[255,255,255],
- yellow:[255,255,0]
-};
-
-// not used yet
-Flotr.Date = {
- format: function(d, format) {
- if (!d) return;
-
- var leftPad = function(n) {
- n = n.toString();
- return n.length == 1 ? "0" + n : n;
- };
-
- var r = [];
- var escape = false;
-
- for (var i = 0; i < format.length; ++i) {
- var c = format.charAt(i);
-
- if (escape) {
- switch (c) {
- case 'h': c = d.getUTCHours().toString(); break;
- case 'H': c = leftPad(d.getUTCHours()); break;
- case 'M': c = leftPad(d.getUTCMinutes()); break;
- case 'S': c = leftPad(d.getUTCSeconds()); break;
- case 'd': c = d.getUTCDate().toString(); break;
- case 'm': c = (d.getUTCMonth() + 1).toString(); break;
- case 'y': c = d.getUTCFullYear().toString(); break;
- case 'b': c = Flotr.Date.monthNames[d.getUTCMonth()]; break;
- }
- r.push(c);
- escape = false;
- }
- else {
- if (c == "%")
- escape = true;
- else
- r.push(c);
- }
- }
- return r.join("");
- },
- timeUnits: {
- "second": 1000,
- "minute": 60 * 1000,
- "hour": 60 * 60 * 1000,
- "day": 24 * 60 * 60 * 1000,
- "month": 30 * 24 * 60 * 60 * 1000,
- "year": 365.2425 * 24 * 60 * 60 * 1000
- },
- // the allowed tick sizes, after 1 year we use an integer algorithm
- spec: [
- [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"],
- [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"],
- [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"],
- [1, "day"], [2, "day"], [3, "day"],
- [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"],
- [1, "year"]
- ],
- monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-};
--- a/js/flotr/lib/base64.js
+++ /dev/null
@@ -1,113 +1,1 @@
-/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
- * Version: 1.0
- * LastModified: Dec 25 1999
- * This library is free. You can redistribute it and/or modify it.
- */
-
-/*
- * Interfaces:
- * b64 = base64encode(data);
- * data = base64decode(b64);
- */
-
-(function() {
-
-var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-var base64DecodeChars = [
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1];
-
-function base64encode(str) {
- var out, i, len;
- var c1, c2, c3;
-
- len = str.length;
- i = 0;
- out = "";
- while(i < len) {
- c1 = str.charCodeAt(i++) & 0xff;
- if(i == len)
- {
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt((c1 & 0x3) << 4);
- out += "==";
- break;
- }
- c2 = str.charCodeAt(i++);
- if(i == len)
- {
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
- out += base64EncodeChars.charAt((c2 & 0xF) << 2);
- out += "=";
- break;
- }
- c3 = str.charCodeAt(i++);
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
- out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
- out += base64EncodeChars.charAt(c3 & 0x3F);
- }
- return out;
-}
-
-function base64decode(str) {
- var c1, c2, c3, c4;
- var i, len, out;
-
- len = str.length;
- i = 0;
- out = "";
- while(i < len) {
- /* c1 */
- do {
- c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while(i < len && c1 == -1);
- if(c1 == -1)
- break;
-
- /* c2 */
- do {
- c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while(i < len && c2 == -1);
- if(c2 == -1)
- break;
-
- out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
-
- /* c3 */
- do {
- c3 = str.charCodeAt(i++) & 0xff;
- if(c3 == 61)
- return out;
- c3 = base64DecodeChars[c3];
- } while(i < len && c3 == -1);
- if(c3 == -1)
- break;
-
- out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
-
- /* c4 */
- do {
- c4 = str.charCodeAt(i++) & 0xff;
- if(c4 == 61)
- return out;
- c4 = base64DecodeChars[c4];
- } while(i < len && c4 == -1);
- if(c4 == -1)
- break;
- out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
- }
- return out;
-}
-
-if (!window.btoa) window.btoa = base64encode;
-if (!window.atob) window.atob = base64decode;
-
-})();
+
--- a/js/flotr/lib/canvas2image.js
+++ /dev/null
@@ -1,230 +1,1 @@
-/*
- * Canvas2Image v0.1
- * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
- * MIT License [http://www.opensource.org/licenses/mit-license.php]
- */
-
-var Canvas2Image = (function() {
- // check if we have canvas support
- var oCanvas = document.createElement("canvas");
-
- // no canvas, bail out.
- if (!oCanvas.getContext) {
- return {
- saveAsBMP : function(){},
- saveAsPNG : function(){},
- saveAsJPEG : function(){}
- }
- }
-
- var bHasImageData = !!(oCanvas.getContext("2d").getImageData);
- var bHasDataURL = !!(oCanvas.toDataURL);
- var bHasBase64 = !!(window.btoa);
-
- var strDownloadMime = "image/octet-stream";
-
- // ok, we're good
- var readCanvasData = function(oCanvas) {
- var iWidth = parseInt(oCanvas.width);
- var iHeight = parseInt(oCanvas.height);
- return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
- }
-
- // base64 encodes either a string or an array of charcodes
- var encodeData = function(data) {
- var strData = "";
- if (typeof data == "string") {
- strData = data;
- } else {
- var aData = data;
- for (var i = 0; i < aData.length; i++) {
- strData += String.fromCharCode(aData[i]);
- }
- }
- return btoa(strData);
- }
-
- // creates a base64 encoded string containing BMP data
- // takes an imagedata object as argument
- var createBMP = function(oData) {
- var aHeader = [];
-
- var iWidth = oData.width;
- var iHeight = oData.height;
-
- aHeader.push(0x42); // magic 1
- aHeader.push(0x4D);
-
- var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes
- aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
- aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
- aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
- aHeader.push(iFileSize % 256);
-
- aHeader.push(0); // reserved
- aHeader.push(0);
- aHeader.push(0); // reserved
- aHeader.push(0);
-
- aHeader.push(54); // data offset
- aHeader.push(0);
- aHeader.push(0);
- aHeader.push(0);
-
- var aInfoHeader = [];
- aInfoHeader.push(40); // info header size
- aInfoHeader.push(0);
- aInfoHeader.push(0);
- aInfoHeader.push(0);
-
- var iImageWidth = iWidth;
- aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
- aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
- aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
- aInfoHeader.push(iImageWidth % 256);
-
- var iImageHeight = iHeight;
- aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
- aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
- aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
- aInfoHeader.push(iImageHeight % 256);
-
- aInfoHeader.push(1); // num of planes
- aInfoHeader.push(0);
-
- aInfoHeader.push(24); // num of bits per pixel
- aInfoHeader.push(0);
-
- aInfoHeader.push(0); // compression = none
- aInfoHeader.push(0);
- aInfoHeader.push(0);
- aInfoHeader.push(0);
-
- var iDataSize = iWidth*iHeight*3;
- aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
- aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
- aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
- aInfoHeader.push(iDataSize % 256);
-
- for (var i = 0; i < 16; i++) {
- aInfoHeader.push(0); // these bytes not used
- }
-
- var iPadding = (4 - ((iWidth * 3) % 4)) % 4;
-
- var aImgData = oData.data;
-
- var strPixelData = "";
- var y = iHeight;
- do {
- var iOffsetY = iWidth*(y-1)*4;
- var strPixelRow = "";
- for (var x=0;x<iWidth;x++) {
- var iOffsetX = 4*x;
-
- strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
- strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
- strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
- }
- for (var c=0;c<iPadding;c++) {
- strPixelRow += String.fromCharCode(0);
- }
- strPixelData += strPixelRow;
- } while (--y);
-
- return encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);
- }
-
- // sends the generated file to the client
- var saveFile = function(strData) {
- if (!window.open(strData)) {
- document.location.href = strData;
- }
- }
-
- var makeDataURI = function(strData, strMime) {
- return "data:" + strMime + ";base64," + strData;
- }
-
- // generates a <img> object containing the imagedata
- var makeImageObject = function(strSource) {
- var oImgElement = document.createElement("img");
- oImgElement.src = strSource;
- return oImgElement;
- }
-
- var scaleCanvas = function(oCanvas, iWidth, iHeight) {
- if (iWidth && iHeight) {
- var oSaveCanvas = document.createElement("canvas");
-
- oSaveCanvas.width = iWidth;
- oSaveCanvas.height = iHeight;
- oSaveCanvas.style.width = iWidth+"px";
- oSaveCanvas.style.height = iHeight+"px";
-
- var oSaveCtx = oSaveCanvas.getContext("2d");
-
- oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
-
- return oSaveCanvas;
- }
- return oCanvas;
- }
-
- return {
- saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
- if (!bHasDataURL) {
- return false;
- }
- var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
- var strData = oScaledCanvas.toDataURL("image/png");
- if (bReturnImg) {
- return makeImageObject(strData);
- } else {
- saveFile(strData.replace("image/png", strDownloadMime));
- }
- return true;
- },
-
- saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
- if (!bHasDataURL) {
- return false;
- }
-
- var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
- var strMime = "image/jpeg";
- var strData = oScaledCanvas.toDataURL(strMime);
-
- // check if browser actually supports jpeg by looking for the mime type in the data uri.
- // if not, return false
- if (strData.indexOf(strMime) != 5) {
- return false;
- }
-
- if (bReturnImg) {
- return makeImageObject(strData);
- } else {
- saveFile(strData.replace(strMime, strDownloadMime));
- }
- return true;
- },
-
- saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
- if (!(bHasImageData && bHasBase64)) {
- return false;
- }
-
- var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
-
- var oData = readCanvasData(oScaledCanvas);
- var strImgData = createBMP(oData);
- if (bReturnImg) {
- return makeImageObject(makeDataURI(strImgData, "image/bmp"));
- } else {
- saveFile(makeDataURI(strImgData, strDownloadMime));
- }
- return true;
- }
- };
-
-})();
+
--- a/js/flotr/lib/canvastext.js
+++ /dev/null
@@ -1,397 +1,1 @@
-/**
- * This code is released to the public domain by Jim Studt, 2007.
- * He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
- * A partial support for accentuated letters as been added too.
- */
-var CanvasText = {
- /** The letters definition. It is a list of letters,
- * with their width, and the coordinates of points compositing them.
- * The syntax for the points is : [x, y], null value means "pen up"
- */
- letters: {
- '\n':{ width: -1, points: [] },
- ' ': { width: 10, points: [] },
- '!': { width: 10, points: [[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
- '"': { width: 16, points: [[4,21],[4,14],null,[12,21],[12,14]] },
- '#': { width: 21, points: [[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]] },
- '$': { width: 20, points: [[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
- '%': { width: 24, points: [[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
- '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
- '\'':{ width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
- '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
- ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
- '*': { width: 16, points: [[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]] },
- '+': { width: 26, points: [[13,18],[13,0],null,[4,9],[22,9]] },
- ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
- '-': { width: 26, points: [[4,9],[22,9]] },
- '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
- '/': { width: 22, points: [[20,25],[2,-7]] },
- '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
- '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
- '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
- '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
- '4': { width: 20, points: [[13,21],[3,7],[18,7],null,[13,21],[13,0]] },
- '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
- '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
- '7': { width: 20, points: [[17,21],[7,0],null,[3,21],[17,21]] },
- '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
- '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
- ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
- ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
- '<': { width: 24, points: [[20,18],[4,9],[20,0]] },
- '=': { width: 26, points: [[4,12],[22,12],null,[4,6],[22,6]] },
- '>': { width: 24, points: [[4,18],[20,9],[4,0]] },
- '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]] },
- '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]] },
- 'A': { width: 18, points: [[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]] },
- 'B': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
- 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
- 'D': { width: 21, points: [[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
- 'E': { width: 19, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]] },
- 'F': { width: 18, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]] },
- 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]] },
- 'H': { width: 22, points: [[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]] },
- 'I': { width: 8, points: [[4,21],[4,0]] },
- 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
- 'K': { width: 21, points: [[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]] },
- 'L': { width: 17, points: [[4,21],[4,0],null,[4,0],[16,0]] },
- 'M': { width: 24, points: [[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]] },
- 'N': { width: 22, points: [[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]] },
- 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
- 'P': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
- 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]] },
- 'R': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]] },
- 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
- 'T': { width: 16, points: [[8,21],[8,0],null,[1,21],[15,21]] },
- 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
- 'V': { width: 18, points: [[1,21],[9,0],null,[17,21],[9,0]] },
- 'W': { width: 24, points: [[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]] },
- 'X': { width: 20, points: [[3,21],[17,0],null,[17,21],[3,0]] },
- 'Y': { width: 18, points: [[1,21],[9,11],[9,0],null,[17,21],[9,11]] },
- 'Z': { width: 20, points: [[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]] },
- '[': { width: 14, points: [[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]] },
- '\\':{ width: 14, points: [[0,21],[14,-3]] },
- ']': { width: 14, points: [[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]] },
- '^': { width: 14, points: [[3,10],[8,18],[13,10]] },
- '_': { width: 16, points: [[0,-2],[16,-2]] },
- '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
- 'a': { width: 19, points: [[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'b': { width: 19, points: [[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
- 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'd': { width: 19, points: [[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]] },
- 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'h': { width: 19, points: [[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
- 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]] },
- 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
- 'k': { width: 17, points: [[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]] },
- 'l': { width: 8, points: [[4,21],[4,0]] },
- 'm': { width: 30, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
- 'n': { width: 19, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
- 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
- 'p': { width: 19, points: [[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
- 'q': { width: 19, points: [[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
- 'r': { width: 13, points: [[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]] },
- 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
- 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]] },
- 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]] },
- 'v': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0]] },
- 'w': { width: 22, points: [[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]] },
- 'x': { width: 17, points: [[3,14],[14,0],null,[14,14],[3,0]] },
- 'y': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
- 'z': { width: 17, points: [[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]] },
- '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
- '|': { width: 8, points: [[4,25],[4,-7]] },
- '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
- '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] },
- },
-
- specialchars: {
- 'pi': { width: 19, points: [[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]] }
- },
-
- /** Diacritics, used to draw accentuated letters */
- diacritics: {
- '`': { entity: 'grave', points: [[7,22],[12,19]] },
- '^': { entity: 'circ', points: [[5.5,19],[9.5,23],[12.5,19]] },
- '~': { entity: 'tilde', points: [[4,18],[7,22],[10,18],[13,22]] }
- },
-
- /** The default font styling */
- style: {
- size: 8, // font height in pixels
- font: null, // not yet implemented
- color: '#000000', //
- weight: 1, // float, 1 for 'normal'
- halign: 'l', // l: left, r: right, c: center
- valign: 'b', // t: top, m: middle, b: bottom
- adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position
- angle: 0, // in radians, anticlockwise
- tracking: 1, // space between the letters, float, 1 for 'normal'
- boundingBoxColor: '#ff0000', //null // color of the bounding box (null to hide), can be used for debug and font drawing
- originPointColor: '#000000' //null // color of the bounding box (null to hide), can be used for debug and font drawing
- },
-
- debug: false,
- _bufferLexemes: {},
-
- /** Get the letter data corresponding to a char
- * @param {String} ch - The char
- */
- letter: function(ch) {
- return CanvasText.letters[ch];
- },
-
- parseLexemes: function(str) {
- if (CanvasText._bufferLexemes[str])
- return CanvasText._bufferLexemes[str];
-
- var i, c, matches = str.match(/&[A-Za-z]{2,5};|\s|./g);
- var result = [], chars = [];
- for (i = 0; i < matches.length; i++) {
- c = matches[i];
- if (c.length == 1)
- chars.push(c);
- else {
- var entity = c.substring(1, c.length-1);
- if (CanvasText.specialchars[entity])
- chars.push(entity);
- else
- chars = chars.concat(c.toArray());
- }
- }
- for (i = 0; i < chars.length; i++) {
- c = chars[i];
- if (c = CanvasText.letters[c] || CanvasText.specialchars[c])
- result.push(c);
- }
- return CanvasText._bufferLexemes[str] = result.compact();
- },
-
- /** Get the font ascent for a given style
- * @param {Object} style - The reference style
- */
- ascent: function(style) {
- style = style || {};
- return (style.size || CanvasText.style.size);
- },
-
- /** Get the font descent for a given style
- * @param {Object} style - The reference style
- * */
- descent: function(style) {
- style = style || {};
- return 7.0*(style.size || CanvasText.style.size)/25.0;
- },
-
- /** Measure the text horizontal size
- * @param {String} str - The text
- * @param {Object} style - Text style
- * */
- measure: function(str, style) {
- if (!str) return;
- style = style || {};
-
- var i, width, lexemes = CanvasText.parseLexemes(str),
- total = 0;
-
- for (i = lexemes.length-1; i > -1; --i) {
- c = lexemes[i];
- width = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width;
- total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0;
- }
- return total;
- },
-
- getDimensions: function(str, style) {
- var width = CanvasText.measure(str, style),
- height = style.size || CanvasText.style.size,
- angle = style.angle || CanvasText.style.angle;
-
- if (style.angle == 0) return {width: width, height: height};
- return {
- width: Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height),
- height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height)
- }
- },
-
- getBestAlign: function(angle, style) {
- angle += CanvasText.getAngleFromAlign(style.halign, style.valign);
- var a = {h:'c', v:'m'};
- if (Math.round(Math.cos(angle)*1000)/1000 != 0)
- a.h = (Math.cos(angle) > 0 ? 'r' : 'l');
-
- if (Math.round(Math.sin(angle)*1000)/1000 != 0)
- a.v = (Math.sin(angle) > 0 ? 't' : 'b');
- return a;
- },
-
- getAngleFromAlign: function(halign, valign) {
- var pi = Math.PI, table = {
- 'rm': 0,
- 'rt': pi/4,
- 'ct': pi/2,
- 'lt': 3*(pi/4),
- 'lm': pi,
- 'lb': -3*(pi/4),
- 'cb': -pi/2,
- 'rb': -pi/4,
- 'cm': 0
- }
- return table[halign+valign];
- },
-
- /** Draws serie of points at given coordinates
- * @param {Canvas context} ctx - The canvas context
- * @param {Array} points - The points to draw
- * @param {Number} x - The X coordinate
- * @param {Number} y - The Y coordinate
- * @param {Number} mag - The scale
- */
- drawPoints: function (ctx, points, x, y, mag, offset) {
- var i, a, penUp = true, needStroke = 0;
- offset = offset || {x:0, y:0};
-
- ctx.beginPath();
- for (i = 0; i < points.length; i++) {
- a = points[i];
- if (!a) {
- penUp = true;
- continue;
- }
- if (penUp) {
- ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
- penUp = false;
- }
- else {
- ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
- }
- }
- ctx.stroke();
- },
-
- /** Draws a text at given coordinates and with a given style
- * @param {Canvas context} ctx - The canvas context
- * @param {String} str - The text to draw
- * @param {Number} xOrig - The X coordinate
- * @param {Number} yOrig - The Y coordinate
- * @param {Object} style - The font style
- */
- draw: function(ctx, str, xOrig, yOrig, style) {
- if (!str) return;
- style = style || CanvasText.style;
- style.halign = style.halign || CanvasText.style.halign;
- style.valign = style.valign || CanvasText.style.valign;
- style.angle = style.angle || CanvasText.style.angle;
- style.size = style.size || CanvasText.style.size;
- style.adjustAlign = style.adjustAlign || CanvasText.style.adjustAlign;
-
- var i, c, total = 0,
- mag = style.size / 25.0,
- x = 0, y = 0,
- lexemes = CanvasText.parseLexemes(str);
-
- var offset = {x:0, y:0},
- measure = CanvasText.measure(str, style),
- align;
-
- if (style.adjustAlign) {
- align = CanvasText.getBestAlign(style.angle, style);
- style.halign = align.h;
- style.valign = align.v;
- }
-
- switch (style.halign) {
- case 'l': break;
- case 'c': offset.x = -measure / 2; break;
- case 'r': offset.x = -measure; break;
- }
-
- switch (style.valign) {
- case 'b': break;
- case 'm': offset.y = style.size / 2; break;
- case 't': offset.y = style.size; break;
- }
-
- ctx.save();
- ctx.translate(xOrig, yOrig);
- ctx.rotate(style.angle);
- ctx.lineCap = "round";
- ctx.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight);
- ctx.strokeStyle = style.color || CanvasText.style.color;
-
- for (i = 0; i < lexemes.length; i++) {
- c = lexemes[i];
- if (c.width == -1) {
- x = 0;
- y = style.size * 1.4;
- continue;
- }
-
- var points = c.points,
- width = c.width;
-
- if (c.diacritic) {
- var dia = CanvasText.diacritics[c.diacritic];
- var char = CanvasText.letter(c.letter);
-
- CanvasText.drawPoints(ctx, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset);
- points = char.points;
- width = char.width;
- }
-
- CanvasText.drawPoints(ctx, points, x, y, mag, offset);
-
- if (CanvasText.debug) {
- ctx.save();
- ctx.lineJoin = "miter";
- ctx.lineWidth = 0.5;
- ctx.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor);
- ctx.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size);
-
- ctx.fillStyle = (style.originPointColor || CanvasText.style.originPointColor);
- ctx.beginPath();
- ctx.arc(0, 0, 1.5, 0, Math.PI*2, true);
- ctx.fill();
-
- ctx.restore();
- }
-
- x += width*mag*(style.tracking || CanvasText.style.tracking);
- }
- ctx.restore();
- return total;
- },
-
- /** Enables the text function for a Canvas context
- * @param {Canvas context} ctx - The canvas context
- */
- enable: function(ctx) {
- ctx.drawText = function(text, x, y, style) { return CanvasText.draw(ctx, text, x, y, style); };
- ctx.measureText = function(text, style) { return CanvasText.measure(text, style); };
- ctx.getTextBounds = function(text, style) { return CanvasText.getDimensions(text, style); };
- ctx.fontAscent = function(style) { return CanvasText.ascent(style); };
- ctx.fontDescent = function(style) { return CanvasText.descent(style); };
- }
-};
+
--- a/js/flotr/lib/excanvas.js
+++ /dev/null
@@ -1,885 +1,1 @@
-// Copyright 2006 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Known Issues:
-//
-// * Patterns are not implemented.
-// * Radial gradient are not implemented. The VML version of these look very
-// different from the canvas one.
-// * Clipping paths are not implemented.
-// * Coordsize. The width and height attribute have higher priority than the
-// width and height style values which isn't correct.
-// * Painting mode isn't implemented.
-// * Canvas width/height should is using content-box by default. IE in
-// Quirks mode will draw the canvas using border-box. Either change your
-// doctype to HTML5
-// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
-// or use Box Sizing Behavior from WebFX
-// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
-// * Non uniform scaling does not correctly scale strokes.
-// * Optimize. There is always room for speed improvements.
-
-// Only add this code if we do not already have a canvas implementation
-if (!document.createElement('canvas').getContext) {
-
-(function() {
-
- // alias some functions to make (compiled) code shorter
- var m = Math;
- var mr = m.round;
- var ms = m.sin;
- var mc = m.cos;
- var abs = m.abs;
- var sqrt = m.sqrt;
-
- // this is used for sub pixel precision
- var Z = 10;
- var Z2 = Z / 2;
-
- /**
- * This funtion is assigned to the <canvas> elements as element.getContext().
- * @this {HTMLElement}
- * @return {CanvasRenderingContext2D_}
- */
- function getContext() {
- return this.context_ ||
- (this.context_ = new CanvasRenderingContext2D_(this));
- }
-
- var slice = Array.prototype.slice;
-
- /**
- * Binds a function to an object. The returned function will always use the
- * passed in {@code obj} as {@code this}.
- *
- * Example:
- *
- * g = bind(f, obj, a, b)
- * g(c, d) // will do f.call(obj, a, b, c, d)
- *
- * @param {Function} f The function to bind the object to
- * @param {Object} obj The object that should act as this when the function
- * is called
- * @param {*} var_args Rest arguments that will be used as the initial
- * arguments when the function is called
- * @return {Function} A new function that has bound this
- */
- function bind(f, obj, var_args) {
- var a = slice.call(arguments, 2);
- return function() {
- return f.apply(obj, a.concat(slice.call(arguments)));
- };
- }
-
- var G_vmlCanvasManager_ = {
- init: function(opt_doc) {
- if (/MSIE/.test(navigator.userAgent) && !window.opera) {
- var doc = opt_doc || document;
- // Create a dummy element so that IE will allow canvas elements to be
- // recognized.
- doc.createElement('canvas');
- doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
- }
- },
-
- init_: function(doc) {
- // create xmlns
- if (!doc.namespaces['g_vml_']) {
- doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
- '#default#VML');
-
- }
- if (!doc.namespaces['g_o_']) {
- doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
- '#default#VML');
- }
-
- // Setup default CSS. Only add one style sheet per document
- if (!doc.styleSheets['ex_canvas_']) {
- var ss = doc.createStyleSheet();
- ss.owningElement.id = 'ex_canvas_';
- ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
- // default size is 300x150 in Gecko and Opera
- 'text-align:left;width:300px;height:150px}' +
- 'g_vml_\\:*{behavior:url(#default#VML)}' +
- 'g_o_\\:*{behavior:url(#default#VML)}';
-
- }
-
- // find all canvas elements
- var els = doc.getElementsByTagName('canvas');
- for (var i = 0; i < els.length; i++) {
- this.initElement(els[i]);
- }
- },
-
- /**
- * Public initializes a canvas element so that it can be used as canvas
- * element from now on. This is called automatically before the page is
- * loaded but if you are creating elements using createElement you need to
- * make sure this is called on the element.
- * @param {HTMLElement} el The canvas element to initialize.
- * @return {HTMLElement} the element that was created.
- */
- initElement: function(el) {
- if (!el.getContext) {
-
- el.getContext = getContext;
-
- // Remove fallback content. There is no way to hide text nodes so we
- // just remove all childNodes. We could hide all elements and remove
- // text nodes but who really cares about the fallback content.
- el.innerHTML = '';
-
- // do not use inline function because that will leak memory
- el.attachEvent('onpropertychange', onPropertyChange);
- el.attachEvent('onresize', onResize);
-
- var attrs = el.attributes;
- if (attrs.width && attrs.width.specified) {
- // TODO: use runtimeStyle and coordsize
- // el.getContext().setWidth_(attrs.width.nodeValue);
- el.style.width = attrs.width.nodeValue + 'px';
- } else {
- el.width = el.clientWidth;
- }
- if (attrs.height && attrs.height.specified) {
- // TODO: use runtimeStyle and coordsize
- // el.getContext().setHeight_(attrs.height.nodeValue);
- el.style.height = attrs.height.nodeValue + 'px';
- } else {
- el.height = el.clientHeight;
- }
- //el.getContext().setCoordsize_()
- }
- return el;
- }
- };
-
- function onPropertyChange(e) {
- var el = e.srcElement;
-
- switch (e.propertyName) {
- case 'width':
- el.style.width = el.attributes.width.nodeValue + 'px';
- el.getContext().clearRect();
- break;
- case 'height':
- el.style.height = el.attributes.height.nodeValue + 'px';
- el.getContext().clearRect();
- break;
- }
- }
-
- function onResize(e) {
- var el = e.srcElement;
- if (el.firstChild) {
- el.firstChild.style.width = el.clientWidth + 'px';
- el.firstChild.style.height = el.clientHeight + 'px';
- }
- }
-
- G_vmlCanvasManager_.init();
-
- // precompute "00" to "FF"
- var dec2hex = [];
- for (var i = 0; i < 16; i++) {
- for (var j = 0; j < 16; j++) {
- dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
- }
- }
-
- function createMatrixIdentity() {
- return [
- [1, 0, 0],
- [0, 1, 0],
- [0, 0, 1]
- ];
- }
-
- function matrixMultiply(m1, m2) {
- var result = createMatrixIdentity();
-
- for (var x = 0; x < 3; x++) {
- for (var y = 0; y < 3; y++) {
- var sum = 0;
-
- for (var z = 0; z < 3; z++) {
- sum += m1[x][z] * m2[z][y];
- }
-
- result[x][y] = sum;
- }
- }
- return result;
- }
-
- function copyState(o1, o2) {
- o2.fillStyle = o1.fillStyle;
- o2.lineCap = o1.lineCap;
- o2.lineJoin = o1.lineJoin;
- o2.lineWidth = o1.lineWidth;
- o2.miterLimit = o1.miterLimit;
- o2.shadowBlur = o1.shadowBlur;
- o2.shadowColor = o1.shadowColor;
- o2.shadowOffsetX = o1.shadowOffsetX;
- o2.shadowOffsetY = o1.shadowOffsetY;
- o2.strokeStyle = o1.strokeStyle;
- o2.globalAlpha = o1.globalAlpha;
- o2.arcScaleX_ = o1.arcScaleX_;
- o2.arcScaleY_ = o1.arcScaleY_;
- o2.lineScale_ = o1.lineScale_;
- }
-
- function processStyle(styleString) {
- var str, alpha = 1;
-
- styleString = String(styleString);
- if (styleString.substring(0, 3) == 'rgb') {
- var start = styleString.indexOf('(', 3);
- var end = styleString.indexOf(')', start + 1);
- var guts = styleString.substring(start + 1, end).split(',');
-
- str = '#';
- for (var i = 0; i < 3; i++) {
- str += dec2hex[Number(guts[i])];
- }
-
- if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
- alpha = guts[3];
- }
- } else {
- str = styleString;
- }
-
- return {color: str, alpha: alpha};
- }
-
- function processLineCap(lineCap) {
- switch (lineCap) {
- case 'butt':
- return 'flat';
- case 'round':
- return 'round';
- case 'square':
- default:
- return 'square';
- }
- }
-
- /**
- * This class implements CanvasRenderingContext2D interface as described by
- * the WHATWG.
- * @param {HTMLElement} surfaceElement The element that the 2D context should
- * be associated with
- */
- function CanvasRenderingContext2D_(surfaceElement) {
- this.m_ = createMatrixIdentity();
-
- this.mStack_ = [];
- this.aStack_ = [];
- this.currentPath_ = [];
-
- // Canvas context properties
- this.strokeStyle = '#000';
- this.fillStyle = '#000';
-
- this.lineWidth = 1;
- this.lineJoin = 'miter';
- this.lineCap = 'butt';
- this.miterLimit = Z * 1;
- this.globalAlpha = 1;
- this.canvas = surfaceElement;
-
- var el = surfaceElement.ownerDocument.createElement('div');
- el.style.width = surfaceElement.clientWidth + 'px';
- el.style.height = surfaceElement.clientHeight + 'px';
- el.style.overflow = 'hidden';
- el.style.position = 'absolute';
- surfaceElement.appendChild(el);
-
- this.element_ = el;
- this.arcScaleX_ = 1;
- this.arcScaleY_ = 1;
- this.lineScale_ = 1;
- }
-
- var contextPrototype = CanvasRenderingContext2D_.prototype;
- contextPrototype.clearRect = function() {
- this.element_.innerHTML = '';
- };
-
- contextPrototype.beginPath = function() {
- // TODO: Branch current matrix so that save/restore has no effect
- // as per safari docs.
- this.currentPath_ = [];
- };
-
- contextPrototype.moveTo = function(aX, aY) {
- var p = this.getCoords_(aX, aY);
- this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
- this.currentX_ = p.x;
- this.currentY_ = p.y;
- };
-
- contextPrototype.lineTo = function(aX, aY) {
- var p = this.getCoords_(aX, aY);
- this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
-
- this.currentX_ = p.x;
- this.currentY_ = p.y;
- };
-
- contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
- aCP2x, aCP2y,
- aX, aY) {
- var p = this.getCoords_(aX, aY);
- var cp1 = this.getCoords_(aCP1x, aCP1y);
- var cp2 = this.getCoords_(aCP2x, aCP2y);
- bezierCurveTo(this, cp1, cp2, p);
- };
-
- // Helper function that takes the already fixed cordinates.
- function bezierCurveTo(self, cp1, cp2, p) {
- self.currentPath_.push({
- type: 'bezierCurveTo',
- cp1x: cp1.x,
- cp1y: cp1.y,
- cp2x: cp2.x,
- cp2y: cp2.y,
- x: p.x,
- y: p.y
- });
- self.currentX_ = p.x;
- self.currentY_ = p.y;
- }
-
- contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
- // the following is lifted almost directly from
- // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
-
- var cp = this.getCoords_(aCPx, aCPy);
- var p = this.getCoords_(aX, aY);
-
- var cp1 = {
- x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
- y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
- };
- var cp2 = {
- x: cp1.x + (p.x - this.currentX_) / 3.0,
- y: cp1.y + (p.y - this.currentY_) / 3.0
- };
-
- bezierCurveTo(this, cp1, cp2, p);
- };
-
- contextPrototype.arc = function(aX, aY, aRadius,
- aStartAngle, aEndAngle, aClockwise) {
- aRadius *= Z;
- var arcType = aClockwise ? 'at' : 'wa';
-
- var xStart = aX + mc(aStartAngle) * aRadius - Z2;
- var yStart = aY + ms(aStartAngle) * aRadius - Z2;
-
- var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
- var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
-
- // IE won't render arches drawn counter clockwise if xStart == xEnd.
- if (xStart == xEnd && !aClockwise) {
- xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
- // that can be represented in binary
- }
-
- var p = this.getCoords_(aX, aY);
- var pStart = this.getCoords_(xStart, yStart);
- var pEnd = this.getCoords_(xEnd, yEnd);
-
- this.currentPath_.push({type: arcType,
- x: p.x,
- y: p.y,
- radius: aRadius,
- xStart: pStart.x,
- yStart: pStart.y,
- xEnd: pEnd.x,
- yEnd: pEnd.y});
-
- };
-
- contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
- this.moveTo(aX, aY);
- this.lineTo(aX + aWidth, aY);
- this.lineTo(aX + aWidth, aY + aHeight);
- this.lineTo(aX, aY + aHeight);
- this.closePath();
- };
-
- contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
- var oldPath = this.currentPath_;
- this.beginPath();
-
- this.moveTo(aX, aY);
- this.lineTo(aX + aWidth, aY);
- this.lineTo(aX + aWidth, aY + aHeight);
- this.lineTo(aX, aY + aHeight);
- this.closePath();
- this.stroke();
-
- this.currentPath_ = oldPath;
- };
-
- contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
- var oldPath = this.currentPath_;
- this.beginPath();
-
- this.moveTo(aX, aY);
- this.lineTo(aX + aWidth, aY);
- this.lineTo(aX + aWidth, aY + aHeight);
- this.lineTo(aX, aY + aHeight);
- this.closePath();
- this.fill();
-
- this.currentPath_ = oldPath;
- };
-
- contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
- var gradient = new CanvasGradient_('gradient');
- gradient.x0_ = aX0;
- gradient.y0_ = aY0;
- gradient.x1_ = aX1;
- gradient.y1_ = aY1;
- return gradient;
- };
-
- contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
- aX1, aY1, aR1) {
- var gradient = new CanvasGradient_('gradientradial');
- gradient.x0_ = aX0;
- gradient.y0_ = aY0;
- gradient.r0_ = aR0;
- gradient.x1_ = aX1;
- gradient.y1_ = aY1;
- gradient.r1_ = aR1;
- return gradient;
- };
-
- contextPrototype.drawImage = function(image, var_args) {
- var dx, dy, dw, dh, sx, sy, sw, sh;
-
- // to find the original width we overide the width and height
- var oldRuntimeWidth = image.runtimeStyle.width;
- var oldRuntimeHeight = image.runtimeStyle.height;
- image.runtimeStyle.width = 'auto';
- image.runtimeStyle.height = 'auto';
-
- // get the original size
- var w = image.width;
- var h = image.height;
-
- // and remove overides
- image.runtimeStyle.width = oldRuntimeWidth;
- image.runtimeStyle.height = oldRuntimeHeight;
-
- if (arguments.length == 3) {
- dx = arguments[1];
- dy = arguments[2];
- sx = sy = 0;
- sw = dw = w;
- sh = dh = h;
- } else if (arguments.length == 5) {
- dx = arguments[1];
- dy = arguments[2];
- dw = arguments[3];
- dh = arguments[4];
- sx = sy = 0;
- sw = w;
- sh = h;
- } else if (arguments.length == 9) {
- sx = arguments[1];
- sy = arguments[2];
- sw = arguments[3];
- sh = arguments[4];
- dx = arguments[5];
- dy = arguments[6];
- dw = arguments[7];
- dh = arguments[8];
- } else {
- throw Error('Invalid number of arguments');
- }
-
- var d = this.getCoords_(dx, dy);
-
- var w2 = sw / 2;
- var h2 = sh / 2;
-
- var vmlStr = [];
-
- var W = 10;
- var H = 10;
-
- // For some reason that I've now forgotten, using divs didn't work
- vmlStr.push(' <g_vml_:group',
- ' coordsize="', Z * W, ',', Z * H, '"',
- ' coordorigin="0,0"' ,
- ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
-
- // If filters are necessary (rotation exists), create them
- // filters are bog-slow, so only create them if abbsolutely necessary
- // The following check doesn't account for skews (which don't exist
- // in the canvas spec (yet) anyway.
-
- if (this.m_[0][0] != 1 || this.m_[0][1]) {
- var filter = [];
-
- // Note the 12/21 reversal
- filter.push('M11=', this.m_[0][0], ',',
- 'M12=', this.m_[1][0], ',',
- 'M21=', this.m_[0][1], ',',
- 'M22=', this.m_[1][1], ',',
- 'Dx=', mr(d.x / Z), ',',
- 'Dy=', mr(d.y / Z), '');
-
- // Bounding box calculation (need to minimize displayed area so that
- // filters don't waste time on unused pixels.
- var max = d;
- var c2 = this.getCoords_(dx + dw, dy);
- var c3 = this.getCoords_(dx, dy + dh);
- var c4 = this.getCoords_(dx + dw, dy + dh);
-
- max.x = m.max(max.x, c2.x, c3.x, c4.x);
- max.y = m.max(max.y, c2.y, c3.y, c4.y);
-
- vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
- 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
- filter.join(''), ", sizingmethod='clip');")
- } else {
- vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
- }
-
- vmlStr.push(' ">' ,
- '<g_vml_:image src="', image.src, '"',
- ' style="width:', Z * dw, 'px;',
- ' height:', Z * dh, 'px;"',
- ' cropleft="', sx / w, '"',
- ' croptop="', sy / h, '"',
- ' cropright="', (w - sx - sw) / w, '"',
- ' cropbottom="', (h - sy - sh) / h, '"',
- ' />',
- '</g_vml_:group>');
-
- this.element_.insertAdjacentHTML('BeforeEnd',
- vmlStr.join(''));
- };
-
- contextPrototype.stroke = function(aFill) {
- var lineStr = [];
- var lineOpen = false;
- var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
- var color = a.color;
- var opacity = a.alpha * this.globalAlpha;
-
- var W = 10;
- var H = 10;
-
- lineStr.push('<g_vml_:shape',
- ' filled="', !!aFill, '"',
- ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
- ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
- ' stroked="', !aFill, '"',
- ' path="');
-
- var newSeq = false;
- var min = {x: null, y: null};
- var max = {x: null, y: null};
-
- for (var i = 0; i < this.currentPath_.length; i++) {
- var p = this.currentPath_[i];
- var c;
-
- switch (p.type) {
- case 'moveTo':
- c = p;
- lineStr.push(' m ', mr(p.x), ',', mr(p.y));
- break;
- case 'lineTo':
- lineStr.push(' l ', mr(p.x), ',', mr(p.y));
- break;
- case 'close':
- lineStr.push(' x ');
- p = null;
- break;
- case 'bezierCurveTo':
- lineStr.push(' c ',
- mr(p.cp1x), ',', mr(p.cp1y), ',',
- mr(p.cp2x), ',', mr(p.cp2y), ',',
- mr(p.x), ',', mr(p.y));
- break;
- case 'at':
- case 'wa':
- lineStr.push(' ', p.type, ' ',
- mr(p.x - this.arcScaleX_ * p.radius), ',',
- mr(p.y - this.arcScaleY_ * p.radius), ' ',
- mr(p.x + this.arcScaleX_ * p.radius), ',',
- mr(p.y + this.arcScaleY_ * p.radius), ' ',
- mr(p.xStart), ',', mr(p.yStart), ' ',
- mr(p.xEnd), ',', mr(p.yEnd));
- break;
- }
-
-
- // TODO: Following is broken for curves due to
- // move to proper paths.
-
- // Figure out dimensions so we can do gradient fills
- // properly
- if (p) {
- if (min.x == null || p.x < min.x) {
- min.x = p.x;
- }
- if (max.x == null || p.x > max.x) {
- max.x = p.x;
- }
- if (min.y == null || p.y < min.y) {
- min.y = p.y;
- }
- if (max.y == null || p.y > max.y) {
- max.y = p.y;
- }
- }
- }
- lineStr.push(' ">');
-
- if (!aFill) {
- var lineWidth = this.lineScale_ * this.lineWidth;
-
- // VML cannot correctly render a line if the width is less than 1px.
- // In that case, we dilute the color to make the line look thinner.
- if (lineWidth < 1) {
- opacity *= lineWidth;
- }
-
- lineStr.push(
- '<g_vml_:stroke',
- ' opacity="', opacity, '"',
- ' joinstyle="', this.lineJoin, '"',
- ' miterlimit="', this.miterLimit, '"',
- ' endcap="', processLineCap(this.lineCap), '"',
- ' weight="', lineWidth, 'px"',
- ' color="', color, '" />'
- );
- } else if (typeof this.fillStyle == 'object') {
- var fillStyle = this.fillStyle;
- var angle = 0;
- var focus = {x: 0, y: 0};
-
- // additional offset
- var shift = 0;
- // scale factor for offset
- var expansion = 1;
-
- if (fillStyle.type_ == 'gradient') {
- var x0 = fillStyle.x0_ / this.arcScaleX_;
- var y0 = fillStyle.y0_ / this.arcScaleY_;
- var x1 = fillStyle.x1_ / this.arcScaleX_;
- var y1 = fillStyle.y1_ / this.arcScaleY_;
- var p0 = this.getCoords_(x0, y0);
- var p1 = this.getCoords_(x1, y1);
- var dx = p1.x - p0.x;
- var dy = p1.y - p0.y;
- angle = Math.atan2(dx, dy) * 180 / Math.PI;
-
- // The angle should be a non-negative number.
- if (angle < 0) {
- angle += 360;
- }
-
- // Very small angles produce an unexpected result because they are
- // converted to a scientific notation string.
- if (angle < 1e-6) {
- angle = 0;
- }
- } else {
- var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
- var width = max.x - min.x;
- var height = max.y - min.y;
- focus = {
- x: (p0.x - min.x) / width,
- y: (p0.y - min.y) / height
- };
-
- width /= this.arcScaleX_ * Z;
- height /= this.arcScaleY_ * Z;
- var dimension = m.max(width, height);
- shift = 2 * fillStyle.r0_ / dimension;
- expansion = 2 * fillStyle.r1_ / dimension - shift;
- }
-
- // We need to sort the color stops in ascending order by offset,
- // otherwise IE won't interpret it correctly.
- var stops = fillStyle.colors_;
- stops.sort(function(cs1, cs2) {
- return cs1.offset - cs2.offset;
- });
-
- var length = stops.length;
- var color1 = stops[0].color;
- var color2 = stops[length - 1].color;
- var opacity1 = stops[0].alpha * this.globalAlpha;
- var opacity2 = stops[length - 1].alpha * this.globalAlpha;
-
- var colors = [];
- for (var i = 0; i < length; i++) {
- var stop = stops[i];
- colors.push(stop.offset * expansion + shift + ' ' + stop.color);
- }
-
- // When colors attribute is used, the meanings of opacity and o:opacity2
- // are reversed.
- lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
- ' method="none" focus="100%"',
- ' color="', color1, '"',
- ' color2="', color2, '"',
- ' colors="', colors.join(','), '"',
- ' opacity="', opacity2, '"',
- ' g_o_:opacity2="', opacity1, '"',
- ' angle="', angle, '"',
- ' focusposition="', focus.x, ',', focus.y, '" />');
- } else {
- lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
- '" />');
- }
-
- lineStr.push('</g_vml_:shape>');
-
- this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
- };
-
- contextPrototype.fill = function() {
- this.stroke(true);
- }
-
- contextPrototype.closePath = function() {
- this.currentPath_.push({type: 'close'});
- };
-
- /**
- * @private
- */
- contextPrototype.getCoords_ = function(aX, aY) {
- var m = this.m_;
- return {
- x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
- y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
- }
- };
-
- contextPrototype.save = function() {
- var o = {};
- copyState(this, o);
- this.aStack_.push(o);
- this.mStack_.push(this.m_);
- this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
- };
-
- contextPrototype.restore = function() {
- copyState(this.aStack_.pop(), this);
- this.m_ = this.mStack_.pop();
- };
-
- contextPrototype.translate = function(aX, aY) {
- var m1 = [
- [1, 0, 0],
- [0, 1, 0],
- [aX, aY, 1]
- ];
-
- this.m_ = matrixMultiply(m1, this.m_);
- };
-
- contextPrototype.rotate = function(aRot) {
- var c = mc(aRot);
- var s = ms(aRot);
-
- var m1 = [
- [c, s, 0],
- [-s, c, 0],
- [0, 0, 1]
- ];
-
- this.m_ = matrixMultiply(m1, this.m_);
- };
-
- contextPrototype.scale = function(aX, aY) {
- this.arcScaleX_ *= aX;
- this.arcScaleY_ *= aY;
- var m1 = [
- [aX, 0, 0],
- [0, aY, 0],
- [0, 0, 1]
- ];
-
- var m = this.m_ = matrixMultiply(m1, this.m_);
-
- // Get the line scale.
- // Determinant of this.m_ means how much the area is enlarged by the
- // transformation. So its square root can be used as a scale factor
- // for width.
- var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
- this.lineScale_ = sqrt(abs(det));
- };
-
- /******** STUBS ********/
- contextPrototype.clip = function() {
- // TODO: Implement
- };
-
- contextPrototype.arcTo = function() {
- // TODO: Implement
- };
-
- contextPrototype.createPattern = function() {
- return new CanvasPattern_;
- };
-
- // Gradient / Pattern Stubs
- function CanvasGradient_(aType) {
- this.type_ = aType;
- this.x0_ = 0;
- this.y0_ = 0;
- this.r0_ = 0;
- this.x1_ = 0;
- this.y1_ = 0;
- this.r1_ = 0;
- this.colors_ = [];
- }
-
- CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
- aColor = processStyle(aColor);
- this.colors_.push({offset: aOffset,
- color: aColor.color,
- alpha: aColor.alpha});
- };
-
- function CanvasPattern_() {}
-
- // set up externs
- G_vmlCanvasManager = G_vmlCanvasManager_;
- CanvasRenderingContext2D = CanvasRenderingContext2D_;
- CanvasGradient = CanvasGradient_;
- CanvasPattern = CanvasPattern_;
-
-})();
-
-} // if
-
--- a/js/flotr/lib/prototype-1.6.0.2.js
+++ /dev/null
@@ -1,4221 +1,1 @@
-/* Prototype JavaScript framework, version 1.6.0.2
- * (c) 2005-2008 Sam Stephenson
- *
- * Prototype is freely distributable under the terms of an MIT-style license.
- * For details, see the Prototype web site: http://www.prototypejs.org/
- *
- *--------------------------------------------------------------------------*/
-
-var Prototype = {
- Version: '1.6.0.2',
-
- Browser: {
- IE: !!(window.attachEvent && !window.opera),
- Opera: !!window.opera,
- WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
- MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
- },
-
- BrowserFeatures: {
- XPath: !!document.evaluate,
- ElementExtensions: !!window.HTMLElement,
- SpecificElementExtensions:
- document.createElement('div').__proto__ &&
- document.createElement('div').__proto__ !==
- document.createElement('form').__proto__
- },
-
- ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
- JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
-
- emptyFunction: function() { },
- K: function(x) { return x }
-};
-
-if (Prototype.Browser.MobileSafari)
- Prototype.BrowserFeatures.SpecificElementExtensions = false;
-
-
-/* Based on Alex Arnell's inheritance implementation. */
-var Class = {
- create: function() {
- var parent = null, properties = $A(arguments);
- if (Object.isFunction(properties[0]))
- parent = properties.shift();
-
- function klass() {
- this.initialize.apply(this, arguments);
- }
-
- Object.extend(klass, Class.Methods);
- klass.superclass = parent;
- klass.subclasses = [];
-
- if (parent) {
- var subclass = function() { };
- subclass.prototype = parent.prototype;
- klass.prototype = new subclass;
- parent.subclasses.push(klass);
- }
-
- for (var i = 0; i < properties.length; i++)
- klass.addMethods(properties[i]);
-
- if (!klass.prototype.initialize)
- klass.prototype.initialize = Prototype.emptyFunction;
-
- klass.prototype.constructor = klass;
-
- return klass;
- }
-};
-
-Class.Methods = {
- addMethods: function(source) {
- var ancestor = this.superclass && this.superclass.prototype;
- var properties = Object.keys(source);
-
- if (!Object.keys({ toString: true }).length)
- properties.push("toString", "valueOf");
-
- for (var i = 0, length = properties.length; i < length; i++) {
- var property = properties[i], value = source[property];
- if (ancestor && Object.isFunction(value) &&
- value.argumentNames().first() == "$super") {
- var method = value, value = Object.extend((function(m) {
- return function() { return ancestor[m].apply(this, arguments) };
- })(property).wrap(method), {
- valueOf: function() { return method },
- toString: function() { return method.toString() }
- });
- }
- this.prototype[property] = value;
- }
-
- return this;
- }
-};
-
-var Abstract = { };
-
-Object.extend = function(destination, source) {
- for (var property in source)
- destination[property] = source[property];
- return destination;
-};
-
-Object.extend(Object, {
- inspect: function(object) {
- try {
- if (Object.isUndefined(object)) return 'undefined';
- if (object === null) return 'null';
- return object.inspect ? object.inspect() : String(object);
- } catch (e) {
- if (e instanceof RangeError) return '...';
- throw e;
- }
- },
-
- toJSON: function(object) {
- var type = typeof object;
- switch (type) {
- case 'undefined':
- case 'function':
- case 'unknown': return;
- case 'boolean': return object.toString();
- }
-
- if (object === null) return 'null';
- if (object.toJSON) return object.toJSON();
- if (Object.isElement(object)) return;
-
- var results = [];
- for (var property in object) {
- var value = Object.toJSON(object[property]);
- if (!Object.isUndefined(value))
- results.push(property.toJSON() + ': ' + value);
- }
-
- return '{' + results.join(', ') + '}';
- },
-
- toQueryString: function(object) {
- return $H(object).toQueryString();
- },
-
- toHTML: function(object) {
- return object && object.toHTML ? object.toHTML() : String.interpret(object);
- },
-
- keys: function(object) {
- var keys = [];
- for (var property in object)
- keys.push(property);
- return keys;
- },
-
- values: function(object) {
- var values = [];
- for (var property in object)
- values.push(object[property]);
- return values;
- },
-
- clone: function(object) {
- return Object.extend({ }, object);
- },
-
- isElement: function(object) {
- return object && object.nodeType == 1;
- },
-
- isArray: function(object) {
- return object != null && typeof object == "object" &&
- 'splice' in object && 'join' in object;
- },
-
- isHash: function(object) {
- return object instanceof Hash;
- },
-
- isFunction: function(object) {
- return typeof object == "function";
- },
-
- isString: function(object) {
- return typeof object == "string";
- },
-
- isNumber: function(object) {
- return typeof object == "number";
- },
-
- isUndefined: function(object) {
- return typeof object == "undefined";
- }
-});
-
-Object.extend(Function.prototype, {
- argumentNames: function() {
- var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
- return names.length == 1 && !names[0] ? [] : names;
- },
-
- bind: function() {
- if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
- var __method = this, args = $A(arguments), object = args.shift();
- return function() {
- return __method.apply(object, args.concat($A(arguments)));
- }
- },
-
- bindAsEventListener: function() {
- var __method = this, args = $A(arguments), object = args.shift();
- return function(event) {
- return __method.apply(object, [event || window.event].concat(args));
- }
- },
-
- curry: function() {
- if (!arguments.length) return this;
- var __method = this, args = $A(arguments);
- return function() {
- return __method.apply(this, args.concat($A(arguments)));
- }
- },
-
- delay: function() {
- var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
- return window.setTimeout(function() {
- return __method.apply(__method, args);
- }, timeout);
- },
-
- wrap: function(wrapper) {
- var __method = this;
- return function() {
- return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
- }
- },
-
- methodize: function() {
- if (this._methodized) return this._methodized;
- var __method = this;
- return this._methodized = function() {
- return __method.apply(null, [this].concat($A(arguments)));
- };
- }
-});
-
-Function.prototype.defer = Function.prototype.delay.curry(0.01);
-
-Date.prototype.toJSON = function() {
- return '"' + this.getUTCFullYear() + '-' +
- (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
- this.getUTCDate().toPaddedString(2) + 'T' +
- this.getUTCHours().toPaddedString(2) + ':' +
- this.getUTCMinutes().toPaddedString(2) + ':' +
- this.getUTCSeconds().toPaddedString(2) + 'Z"';
-};
-
-var Try = {
- these: function() {
- var returnValue;
-
- for (var i = 0, length = arguments.length; i < length; i++) {
- var lambda = arguments[i];
- try {
- returnValue = lambda();
- break;
- } catch (e) { }
- }
-
- return returnValue;
- }
-};
-
-RegExp.prototype.match = RegExp.prototype.test;
-
-RegExp.escape = function(str) {
- return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
-};
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create({
- initialize: function(callback, frequency) {
- this.callback = callback;
- this.frequency = frequency;
- this.currentlyExecuting = false;
-
- this.registerCallback();
- },
-
- registerCallback: function() {
- this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
- },
-
- execute: function() {
- this.callback(this);
- },
-
- stop: function() {
- if (!this.timer) return;
- clearInterval(this.timer);
- this.timer = null;
- },
-
- onTimerEvent: function() {
- if (!this.currentlyExecuting) {
- try {
- this.currentlyExecuting = true;
- this.execute();
- } finally {
- this.currentlyExecuting = false;
- }
- }
- }
-});
-Object.extend(String, {
- interpret: function(value) {
- return value == null ? '' : String(value);
- },
- specialChar: {
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '\\': '\\\\'
- }
-});
-
-Object.extend(String.prototype, {
- gsub: function(pattern, replacement) {
- var result = '', source = this, match;
- replacement = arguments.callee.prepareReplacement(replacement);
-
- while (source.length > 0) {
- if (match = source.match(pattern)) {
- result += source.slice(0, match.index);
- result += String.interpret(replacement(match));
- source = source.slice(match.index + match[0].length);
- } else {
- result += source, source = '';
- }
- }
- return result;
- },
-
- sub: function(pattern, replacement, count) {
- replacement = this.gsub.prepareReplacement(replacement);
- count = Object.isUndefined(count) ? 1 : count;
-
- return this.gsub(pattern, function(match) {
- if (--count < 0) return match[0];
- return replacement(match);
- });
- },
-
- scan: function(pattern, iterator) {
- this.gsub(pattern, iterator);
- return String(this);
- },
-
- truncate: function(length, truncation) {
- length = length || 30;
- truncation = Object.isUndefined(truncation) ? '...' : truncation;
- return this.length > length ?
- this.slice(0, length - truncation.length) + truncation : String(this);
- },
-
- strip: function() {
- return this.replace(/^\s+/, '').replace(/\s+$/, '');
- },
-
- stripTags: function() {
- return this.replace(/<\/?[^>]+>/gi, '');
- },
-
- stripScripts: function() {
- return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
- },
-
- extractScripts: function() {
- var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
- var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
- return (this.match(matchAll) || []).map(function(scriptTag) {
- return (scriptTag.match(matchOne) || ['', ''])[1];
- });
- },
-
- evalScripts: function() {
- return this.extractScripts().map(function(script) { return eval(script) });
- },
-
- escapeHTML: function() {
- var self = arguments.callee;
- self.text.data = this;
- return self.div.innerHTML;
- },
-
- unescapeHTML: function() {
- var div = new Element('div');
- div.innerHTML = this.stripTags();
- return div.childNodes[0] ? (div.childNodes.length > 1 ?
- $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
- div.childNodes[0].nodeValue) : '';
- },
-
- toQueryParams: function(separator) {
- var match = this.strip().match(/([^?#]*)(#.*)?$/);
- if (!match) return { };
-
- return match[1].split(separator || '&').inject({ }, function(hash, pair) {
- if ((pair = pair.split('='))[0]) {
- var key = decodeURIComponent(pair.shift());
- var value = pair.length > 1 ? pair.join('=') : pair[0];
- if (value != undefined) value = decodeURIComponent(value);
-
- if (key in hash) {
- if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
- hash[key].push(value);
- }
- else hash[key] = value;
- }
- return hash;
- });
- },
-
- toArray: function() {
- return this.split('');
- },
-
- succ: function() {
- return this.slice(0, this.length - 1) +
- String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
- },
-
- times: function(count) {
- return count < 1 ? '' : new Array(count + 1).join(this);
- },
-
- camelize: function() {
- var parts = this.split('-'), len = parts.length;
- if (len == 1) return parts[0];
-
- var camelized = this.charAt(0) == '-'
- ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
- : parts[0];
-
- for (var i = 1; i < len; i++)
- camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
-
- return camelized;
- },
-
- capitalize: function() {
- return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
- },
-
- underscore: function() {
- return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
- },
-
- dasherize: function() {
- return this.gsub(/_/,'-');
- },
-
- inspect: function(useDoubleQuotes) {
- var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
- var character = String.specialChar[match[0]];
- return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
- });
- if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
- return "'" + escapedString.replace(/'/g, '\\\'') + "'";
- },
-
- toJSON: function() {
- return this.inspect(true);
- },
-
- unfilterJSON: function(filter) {
- return this.sub(filter || Prototype.JSONFilter, '#{1}');
- },
-
- isJSON: function() {
- var str = this;
- if (str.blank()) return false;
- str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
- return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
- },
-
- evalJSON: function(sanitize) {
- var json = this.unfilterJSON();
- try {
- if (!sanitize || json.isJSON()) return eval('(' + json + ')');
- } catch (e) { }
- throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
- },
-
- include: function(pattern) {
- return this.indexOf(pattern) > -1;
- },
-
- startsWith: function(pattern) {
- return this.indexOf(pattern) === 0;
- },
-
- endsWith: function(pattern) {
- var d = this.length - pattern.length;
- return d >= 0 && this.lastIndexOf(pattern) === d;
- },
-
- empty: function() {
- return this == '';
- },
-
- blank: function() {
- return /^\s*$/.test(this);
- },
-
- interpolate: function(object, pattern) {
- return new Template(this, pattern).evaluate(object);
- }
-});
-
-if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
- escapeHTML: function() {
- return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
- },
- unescapeHTML: function() {
- return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
- }
-});
-
-String.prototype.gsub.prepareReplacement = function(replacement) {
- if (Object.isFunction(replacement)) return replacement;
- var template = new Template(replacement);
- return function(match) { return template.evaluate(match) };
-};
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-Object.extend(String.prototype.escapeHTML, {
- div: document.createElement('div'),
- text: document.createTextNode('')
-});
-
-with (String.prototype.escapeHTML) div.appendChild(text);
-
-var Template = Class.create({
- initialize: function(template, pattern) {
- this.template = template.toString();
- this.pattern = pattern || Template.Pattern;
- },
-
- evaluate: function(object) {
- if (Object.isFunction(object.toTemplateReplacements))
- object = object.toTemplateReplacements();
-
- return this.template.gsub(this.pattern, function(match) {
- if (object == null) return '';
-
- var before = match[1] || '';
- if (before == '\\') return match[2];
-
- var ctx = object, expr = match[3];
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
- match = pattern.exec(expr);
- if (match == null) return before;
-
- while (match != null) {
- var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
- ctx = ctx[comp];
- if (null == ctx || '' == match[3]) break;
- expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
- match = pattern.exec(expr);
- }
-
- return before + String.interpret(ctx);
- });
- }
-});
-Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
-
-var $break = { };
-
-var Enumerable = {
- each: function(iterator, context) {
- var index = 0;
- iterator = iterator.bind(context);
- try {
- this._each(function(value) {
- iterator(value, index++);
- });
- } catch (e) {
- if (e != $break) throw e;
- }
- return this;
- },
-
- eachSlice: function(number, iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var index = -number, slices = [], array = this.toArray();
- while ((index += number) < array.length)
- slices.push(array.slice(index, index+number));
- return slices.collect(iterator, context);
- },
-
- all: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var result = true;
- this.each(function(value, index) {
- result = result && !!iterator(value, index);
- if (!result) throw $break;
- });
- return result;
- },
-
- any: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var result = false;
- this.each(function(value, index) {
- if (result = !!iterator(value, index))
- throw $break;
- });
- return result;
- },
-
- collect: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var results = [];
- this.each(function(value, index) {
- results.push(iterator(value, index));
- });
- return results;
- },
-
- detect: function(iterator, context) {
- iterator = iterator.bind(context);
- var result;
- this.each(function(value, index) {
- if (iterator(value, index)) {
- result = value;
- throw $break;
- }
- });
- return result;
- },
-
- findAll: function(iterator, context) {
- iterator = iterator.bind(context);
- var results = [];
- this.each(function(value, index) {
- if (iterator(value, index))
- results.push(value);
- });
- return results;
- },
-
- grep: function(filter, iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var results = [];
-
- if (Object.isString(filter))
- filter = new RegExp(filter);
-
- this.each(function(value, index) {
- if (filter.match(value))
- results.push(iterator(value, index));
- });
- return results;
- },
-
- include: function(object) {
- if (Object.isFunction(this.indexOf))
- if (this.indexOf(object) != -1) return true;
-
- var found = false;
- this.each(function(value) {
- if (value == object) {
- found = true;
- throw $break;
- }
- });
- return found;
- },
-
- inGroupsOf: function(number, fillWith) {
- fillWith = Object.isUndefined(fillWith) ? null : fillWith;
- return this.eachSlice(number, function(slice) {
- while(slice.length < number) slice.push(fillWith);
- return slice;
- });
- },
-
- inject: function(memo, iterator, context) {
- iterator = iterator.bind(context);
- this.each(function(value, index) {
- memo = iterator(memo, value, index);
- });
- return memo;
- },
-
- invoke: function(method) {
- var args = $A(arguments).slice(1);
- return this.map(function(value) {
- return value[method].apply(value, args);
- });
- },
-
- max: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var result;
- this.each(function(value, index) {
- value = iterator(value, index);
- if (result == null || value >= result)
- result = value;
- });
- return result;
- },
-
- min: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var result;
- this.each(function(value, index) {
- value = iterator(value, index);
- if (result == null || value < result)
- result = value;
- });
- return result;
- },
-
- partition: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
- var trues = [], falses = [];
- this.each(function(value, index) {
- (iterator(value, index) ?
- trues : falses).push(value);
- });
- return [trues, falses];
- },
-
- pluck: function(property) {
- var results = [];
- this.each(function(value) {
- results.push(value[property]);
- });
- return results;
- },
-
- reject: function(iterator, context) {
- iterator = iterator.bind(context);
- var results = [];
- this.each(function(value, index) {
- if (!iterator(value, index))
- results.push(value);
- });
- return results;
- },
-
- sortBy: function(iterator, context) {
- iterator = iterator.bind(context);
- return this.map(function(value, index) {
- return {value: value, criteria: iterator(value, index)};
- }).sort(function(left, right) {
- var a = left.criteria, b = right.criteria;
- return a < b ? -1 : a > b ? 1 : 0;
- }).pluck('value');
- },
-
- toArray: function() {
- return this.map();
- },
-
- zip: function() {
- var iterator = Prototype.K, args = $A(arguments);
- if (Object.isFunction(args.last()))
- iterator = args.pop();
-
- var collections = [this].concat(args).map($A);
- return this.map(function(value, index) {
- return iterator(collections.pluck(index));
- });
- },
-
- size: function() {
- return this.toArray().length;
- },
-
- inspect: function() {
- return '#<Enumerable:' + this.toArray().inspect() + '>';
- }
-};
-
-Object.extend(Enumerable, {
- map: Enumerable.collect,
- find: Enumerable.detect,
- select: Enumerable.findAll,
- filter: Enumerable.findAll,
- member: Enumerable.include,
- entries: Enumerable.toArray,
- every: Enumerable.all,
- some: Enumerable.any
-});
-function $A(iterable) {
- if (!iterable) return [];
- if (iterable.toArray) return iterable.toArray();
- var length = iterable.length || 0, results = new Array(length);
- while (length--) results[length] = iterable[length];
- return results;
-}
-
-if (Prototype.Browser.WebKit) {
- $A = function(iterable) {
- if (!iterable) return [];
- if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
- iterable.toArray) return iterable.toArray();
- var length = iterable.length || 0, results = new Array(length);
- while (length--) results[length] = iterable[length];
- return results;
- };
-}
-
-Array.from = $A;
-
-Object.extend(Array.prototype, Enumerable);
-
-if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
- _each: function(iterator) {
- for (var i = 0, length = this.length; i < length; i++)
- iterator(this[i]);
- },
-
- clear: function() {
- this.length = 0;
- return this;
- },
-
- first: function() {
- return this[0];
- },
-
- last: function() {
- return this[this.length - 1];
- },
-
- compact: function() {
- return this.select(function(value) {
- return value != null;
- });
- },
-
- flatten: function() {
- return this.inject([], function(array, value) {
- return array.concat(Object.isArray(value) ?
- value.flatten() : [value]);
- });
- },
-
- without: function() {
- var values = $A(arguments);
- return this.select(function(value) {
- return !values.include(value);
- });
- },
-
- reverse: function(inline) {
- return (inline !== false ? this : this.toArray())._reverse();
- },
-
- reduce: function() {
- return this.length > 1 ? this : this[0];
- },
-
- uniq: function(sorted) {
- return this.inject([], function(array, value, index) {
- if (0 == index || (sorted ? array.last() != value : !array.include(value)))
- array.push(value);
- return array;
- });
- },
-
- intersect: function(array) {
- return this.uniq().findAll(function(item) {
- return array.detect(function(value) { return item === value });
- });
- },
-
- clone: function() {
- return [].concat(this);
- },
-
- size: function() {
- return this.length;
- },
-
- inspect: function() {
- return '[' + this.map(Object.inspect).join(', ') + ']';
- },
-
- toJSON: function() {
- var results = [];
- this.each(function(object) {
- var value = Object.toJSON(object);
- if (!Object.isUndefined(value)) results.push(value);
- });
- return '[' + results.join(', ') + ']';
- }
-});
-
-// use native browser JS 1.6 implementation if available
-if (Object.isFunction(Array.prototype.forEach))
- Array.prototype._each = Array.prototype.forEach;
-
-if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
- i || (i = 0);
- var length = this.length;
- if (i < 0) i = length + i;
- for (; i < length; i++)
- if (this[i] === item) return i;
- return -1;
-};
-
-if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
- i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
- var n = this.slice(0, i).reverse().indexOf(item);
- return (n < 0) ? n : i - n - 1;
-};
-
-Array.prototype.toArray = Array.prototype.clone;
-
-function $w(string) {
- if (!Object.isString(string)) return [];
- string = string.strip();
- return string ? string.split(/\s+/) : [];
-}
-
-if (Prototype.Browser.Opera){
- Array.prototype.concat = function() {
- var array = [];
- for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
- for (var i = 0, length = arguments.length; i < length; i++) {
- if (Object.isArray(arguments[i])) {
- for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
- array.push(arguments[i][j]);
- } else {
- array.push(arguments[i]);
- }
- }
- return array;
- };
-}
-Object.extend(Number.prototype, {
- toColorPart: function() {
- return this.toPaddedString(2, 16);
- },
-
- succ: function() {
- return this + 1;
- },
-
- times: function(iterator) {
- $R(0, this, true).each(iterator);
- return this;
- },
-
- toPaddedString: function(length, radix) {
- var string = this.toString(radix || 10);
- return '0'.times(length - string.length) + string;
- },
-
- toJSON: function() {
- return isFinite(this) ? this.toString() : 'null';
- }
-});
-
-$w('abs round ceil floor').each(function(method){
- Number.prototype[method] = Math[method].methodize();
-});
-function $H(object) {
- return new Hash(object);
-};
-
-var Hash = Class.create(Enumerable, (function() {
-
- function toQueryPair(key, value) {
- if (Object.isUndefined(value)) return key;
- return key + '=' + encodeURIComponent(String.interpret(value));
- }
-
- return {
- initialize: function(object) {
- this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
- },
-
- _each: function(iterator) {
- for (var key in this._object) {
- var value = this._object[key], pair = [key, value];
- pair.key = key;
- pair.value = value;
- iterator(pair);
- }
- },
-
- set: function(key, value) {
- return this._object[key] = value;
- },
-
- get: function(key) {
- return this._object[key];
- },
-
- unset: function(key) {
- var value = this._object[key];
- delete this._object[key];
- return value;
- },
-
- toObject: function() {
- return Object.clone(this._object);
- },
-
- keys: function() {
- return this.pluck('key');
- },
-
- values: function() {
- return this.pluck('value');
- },
-
- index: function(value) {
- var match = this.detect(function(pair) {
- return pair.value === value;
- });
- return match && match.key;
- },
-
- merge: function(object) {
- return this.clone().update(object);
- },
-
- update: function(object) {
- return new Hash(object).inject(this, function(result, pair) {
- result.set(pair.key, pair.value);
- return result;
- });
- },
-
- toQueryString: function() {
- return this.map(function(pair) {
- var key = encodeURIComponent(pair.key), values = pair.value;
-
- if (values && typeof values == 'object') {
- if (Object.isArray(values))
- return values.map(toQueryPair.curry(key)).join('&');
- }
- return toQueryPair(key, values);
- }).join('&');
- },
-
- inspect: function() {
- return '#<Hash:{' + this.map(function(pair) {
- return pair.map(Object.inspect).join(': ');
- }).join(', ') + '}>';
- },
-
- toJSON: function() {
- return Object.toJSON(this.toObject());
- },
-
- clone: function() {
- return new Hash(this);
- }
- }
-})());
-
-Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
-Hash.from = $H;
-var ObjectRange = Class.create(Enumerable, {
- initialize: function(start, end, exclusive) {
- this.start = start;
- this.end = end;
- this.exclusive = exclusive;
- },
-
- _each: function(iterator) {
- var value = this.start;
- while (this.include(value)) {
- iterator(value);
- value = value.succ();
- }
- },
-
- include: function(value) {
- if (value < this.start)
- return false;
- if (this.exclusive)
- return value < this.end;
- return value <= this.end;
- }
-});
-
-var $R = function(start, end, exclusive) {
- return new ObjectRange(start, end, exclusive);
-};
-
-var Ajax = {
- getTransport: function() {
- return Try.these(
- function() {return new XMLHttpRequest()},
- function() {return new ActiveXObject('Msxml2.XMLHTTP')},
- function() {return new ActiveXObject('Microsoft.XMLHTTP')}
- ) || false;
- },
-
- activeRequestCount: 0
-};
-
-Ajax.Responders = {
- responders: [],
-
- _each: function(iterator) {
- this.responders._each(iterator);
- },
-
- register: function(responder) {
- if (!this.include(responder))
- this.responders.push(responder);
- },
-
- unregister: function(responder) {
- this.responders = this.responders.without(responder);
- },
-
- dispatch: function(callback, request, transport, json) {
- this.each(function(responder) {
- if (Object.isFunction(responder[callback])) {
- try {
- responder[callback].apply(responder, [request, transport, json]);
- } catch (e) { }
- }
- });
- }
-};
-
-Object.extend(Ajax.Responders, Enumerable);
-
-Ajax.Responders.register({
- onCreate: function() { Ajax.activeRequestCount++ },
- onComplete: function() { Ajax.activeRequestCount-- }
-});
-
-Ajax.Base = Class.create({
- initialize: function(options) {
- this.options = {
- method: 'post',
- asynchronous: true,
- contentType: 'application/x-www-form-urlencoded',
- encoding: 'UTF-8',
- parameters: '',
- evalJSON: true,
- evalJS: true
- };
- Object.extend(this.options, options || { });
-
- this.options.method = this.options.method.toLowerCase();
-
- if (Object.isString(this.options.parameters))
- this.options.parameters = this.options.parameters.toQueryParams();
- else if (Object.isHash(this.options.parameters))
- this.options.parameters = this.options.parameters.toObject();
- }
-});
-
-Ajax.Request = Class.create(Ajax.Base, {
- _complete: false,
-
- initialize: function($super, url, options) {
- $super(options);
- this.transport = Ajax.getTransport();
- this.request(url);
- },
-
- request: function(url) {
- this.url = url;
- this.method = this.options.method;
- var params = Object.clone(this.options.parameters);
-
- if (!['get', 'post'].include(this.method)) {
- // simulate other verbs over post
- params['_method'] = this.method;
- this.method = 'post';
- }
-
- this.parameters = params;
-
- if (params = Object.toQueryString(params)) {
- // when GET, append parameters to URL
- if (this.method == 'get')
- this.url += (this.url.include('?') ? '&' : '?') + params;
- else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
- params += '&_=';
- }
-
- try {
- var response = new Ajax.Response(this);
- if (this.options.onCreate) this.options.onCreate(response);
- Ajax.Responders.dispatch('onCreate', this, response);
-
- this.transport.open(this.method.toUpperCase(), this.url,
- this.options.asynchronous);
-
- if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
-
- this.transport.onreadystatechange = this.onStateChange.bind(this);
- this.setRequestHeaders();
-
- this.body = this.method == 'post' ? (this.options.postBody || params) : null;
- this.transport.send(this.body);
-
- /* Force Firefox to handle ready state 4 for synchronous requests */
- if (!this.options.asynchronous && this.transport.overrideMimeType)
- this.onStateChange();
-
- }
- catch (e) {
- this.dispatchException(e);
- }
- },
-
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState > 1 && !((readyState == 4) && this._complete))
- this.respondToReadyState(this.transport.readyState);
- },
-
- setRequestHeaders: function() {
- var headers = {
- 'X-Requested-With': 'XMLHttpRequest',
- 'X-Prototype-Version': Prototype.Version,
- 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
- };
-
- if (this.method == 'post') {
- headers['Content-type'] = this.options.contentType +
- (this.options.encoding ? '; charset=' + this.options.encoding : '');
-
- /* Force "Connection: close" for older Mozilla browsers to work
- * around a bug where XMLHttpRequest sends an incorrect
- * Content-length header. See Mozilla Bugzilla #246651.
- */
- if (this.transport.overrideMimeType &&
- (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
- headers['Connection'] = 'close';
- }
-
- // user-defined headers
- if (typeof this.options.requestHeaders == 'object') {
- var extras = this.options.requestHeaders;
-
- if (Object.isFunction(extras.push))
- for (var i = 0, length = extras.length; i < length; i += 2)
- headers[extras[i]] = extras[i+1];
- else
- $H(extras).each(function(pair) { headers[pair.key] = pair.value });
- }
-
- for (var name in headers)
- this.transport.setRequestHeader(name, headers[name]);
- },
-
- success: function() {
- var status = this.getStatus();
- return !status || (status >= 200 && status < 300);
- },
-
- getStatus: function() {
- try {
- return this.transport.status || 0;
- } catch (e) { return 0 }
- },
-
- respondToReadyState: function(readyState) {
- var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
-
- if (state == 'Complete') {
- try {
- this._complete = true;
- (this.options['on' + response.status]
- || this.options['on' + (this.success() ? 'Success' : 'Failure')]
- || Prototype.emptyFunction)(response, response.headerJSON);
- } catch (e) {
- this.dispatchException(e);
- }
-
- var contentType = response.getHeader('Content-type');
- if (this.options.evalJS == 'force'
- || (this.options.evalJS && this.isSameOrigin() && contentType
- && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
- this.evalResponse();
- }
-
- try {
- (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
- Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
- } catch (e) {
- this.dispatchException(e);
- }
-
- if (state == 'Complete') {
- // avoid memory leak in MSIE: clean up
- this.transport.onreadystatechange = Prototype.emptyFunction;
- }
- },
-
- isSameOrigin: function() {
- var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
- return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
- protocol: location.protocol,
- domain: document.domain,
- port: location.port ? ':' + location.port : ''
- }));
- },
-
- getHeader: function(name) {
- try {
- return this.transport.getResponseHeader(name) || null;
- } catch (e) { return null }
- },
-
- evalResponse: function() {
- try {
- return eval((this.transport.responseText || '').unfilterJSON());
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- dispatchException: function(exception) {
- (this.options.onException || Prototype.emptyFunction)(this, exception);
- Ajax.Responders.dispatch('onException', this, exception);
- }
-});
-
-Ajax.Request.Events =
- ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Response = Class.create({
- initialize: function(request){
- this.request = request;
- var transport = this.transport = request.transport,
- readyState = this.readyState = transport.readyState;
-
- if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
- this.status = this.getStatus();
- this.statusText = this.getStatusText();
- this.responseText = String.interpret(transport.responseText);
- this.headerJSON = this._getHeaderJSON();
- }
-
- if(readyState == 4) {
- var xml = transport.responseXML;
- this.responseXML = Object.isUndefined(xml) ? null : xml;
- this.responseJSON = this._getResponseJSON();
- }
- },
-
- status: 0,
- statusText: '',
-
- getStatus: Ajax.Request.prototype.getStatus,
-
- getStatusText: function() {
- try {
- return this.transport.statusText || '';
- } catch (e) { return '' }
- },
-
- getHeader: Ajax.Request.prototype.getHeader,
-
- getAllHeaders: function() {
- try {
- return this.getAllResponseHeaders();
- } catch (e) { return null }
- },
-
- getResponseHeader: function(name) {
- return this.transport.getResponseHeader(name);
- },
-
- getAllResponseHeaders: function() {
- return this.transport.getAllResponseHeaders();
- },
-
- _getHeaderJSON: function() {
- var json = this.getHeader('X-JSON');
- if (!json) return null;
- json = decodeURIComponent(escape(json));
- try {
- return json.evalJSON(this.request.options.sanitizeJSON ||
- !this.request.isSameOrigin());
- } catch (e) {
- this.request.dispatchException(e);
- }
- },
-
- _getResponseJSON: function() {
- var options = this.request.options;
- if (!options.evalJSON || (options.evalJSON != 'force' &&
- !(this.getHeader('Content-type') || '').include('application/json')) ||
- this.responseText.blank())
- return null;
- try {
- return this.responseText.evalJSON(options.sanitizeJSON ||
- !this.request.isSameOrigin());
- } catch (e) {
- this.request.dispatchException(e);
- }
- }
-});
-
-Ajax.Updater = Class.create(Ajax.Request, {
- initialize: function($super, container, url, options) {
- this.container = {
- success: (container.success || container),
- failure: (container.failure || (container.success ? null : container))
- };
-
- options = Object.clone(options);
- var onComplete = options.onComplete;
- options.onComplete = (function(response, json) {
- this.updateContent(response.responseText);
- if (Object.isFunction(onComplete)) onComplete(response, json);
- }).bind(this);
-
- $super(url, options);
- },
-
- updateContent: function(responseText) {
- var receiver = this.container[this.success() ? 'success' : 'failure'],
- options = this.options;
-
- if (!options.evalScripts) responseText = responseText.stripScripts();
-
- if (receiver = $(receiver)) {
- if (options.insertion) {
- if (Object.isString(options.insertion)) {
- var insertion = { }; insertion[options.insertion] = responseText;
- receiver.insert(insertion);
- }
- else options.insertion(receiver, responseText);
- }
- else receiver.update(responseText);
- }
- }
-});
-
-Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
- initialize: function($super, container, url, options) {
- $super(options);
- this.onComplete = this.options.onComplete;
-
- this.frequency = (this.options.frequency || 2);
- this.decay = (this.options.decay || 1);
-
- this.updater = { };
- this.container = container;
- this.url = url;
-
- this.start();
- },
-
- start: function() {
- this.options.onComplete = this.updateComplete.bind(this);
- this.onTimerEvent();
- },
-
- stop: function() {
- this.updater.options.onComplete = undefined;
- clearTimeout(this.timer);
- (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
- },
-
- updateComplete: function(response) {
- if (this.options.decay) {
- this.decay = (response.responseText == this.lastText ?
- this.decay * this.options.decay : 1);
-
- this.lastText = response.responseText;
- }
- this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
- },
-
- onTimerEvent: function() {
- this.updater = new Ajax.Updater(this.container, this.url, this.options);
- }
-});
-function $(element) {
- if (arguments.length > 1) {
- for (var i = 0, elements = [], length = arguments.length; i < length; i++)
- elements.push($(arguments[i]));
- return elements;
- }
- if (Object.isString(element))
- element = document.getElementById(element);
- return Element.extend(element);
-}
-
-if (Prototype.BrowserFeatures.XPath) {
- document._getElementsByXPath = function(expression, parentElement) {
- var results = [];
- var query = document.evaluate(expression, $(parentElement) || document,
- null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- for (var i = 0, length = query.snapshotLength; i < length; i++)
- results.push(Element.extend(query.snapshotItem(i)));
- return results;
- };
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Node) var Node = { };
-
-if (!Node.ELEMENT_NODE) {
- // DOM level 2 ECMAScript Language Binding
- Object.extend(Node, {
- ELEMENT_NODE: 1,
- ATTRIBUTE_NODE: 2,
- TEXT_NODE: 3,
- CDATA_SECTION_NODE: 4,
- ENTITY_REFERENCE_NODE: 5,
- ENTITY_NODE: 6,
- PROCESSING_INSTRUCTION_NODE: 7,
- COMMENT_NODE: 8,
- DOCUMENT_NODE: 9,
- DOCUMENT_TYPE_NODE: 10,
- DOCUMENT_FRAGMENT_NODE: 11,
- NOTATION_NODE: 12
- });
-}
-
-(function() {
- var element = this.Element;
- this.Element = function(tagName, attributes) {
- attributes = attributes || { };
- tagName = tagName.toLowerCase();
- var cache = Element.cache;
- if (Prototype.Browser.IE && attributes.name) {
- tagName = '<' + tagName + ' name="' + attributes.name + '">';
- delete attributes.name;
- return Element.writeAttribute(document.createElement(tagName), attributes);
- }
- if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
- return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
- };
- Object.extend(this.Element, element || { });
-}).call(window);
-
-Element.cache = { };
-
-Element.Methods = {
- visible: function(element) {
- return $(element).style.display != 'none';
- },
-
- toggle: function(element) {
- element = $(element);
- Element[Element.visible(element) ? 'hide' : 'show'](element);
- return element;
- },
-
- hide: function(element) {
- $(element).style.display = 'none';
- return element;
- },
-
- show: function(element) {
- $(element).style.display = '';
- return element;
- },
-
- remove: function(element) {
- element = $(element);
- element.parentNode.removeChild(element);
- return element;
- },
-
- update: function(element, content) {
- element = $(element);
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) return element.update().insert(content);
- content = Object.toHTML(content);
- element.innerHTML = content.stripScripts();
- content.evalScripts.bind(content).defer();
- return element;
- },
-
- replace: function(element, content) {
- element = $(element);
- if (content && content.toElement) content = content.toElement();
- else if (!Object.isElement(content)) {
- content = Object.toHTML(content);
- var range = element.ownerDocument.createRange();
- range.selectNode(element);
- content.evalScripts.bind(content).defer();
- content = range.createContextualFragment(content.stripScripts());
- }
- element.parentNode.replaceChild(content, element);
- return element;
- },
-
- insert: function(element, insertions) {
- element = $(element);
-
- if (Object.isString(insertions) || Object.isNumber(insertions) ||
- Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
- insertions = {bottom:insertions};
-
- var content, insert, tagName, childNodes;
-
- for (var position in insertions) {
- content = insertions[position];
- position = position.toLowerCase();
- insert = Element._insertionTranslations[position];
-
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) {
- insert(element, content);
- continue;
- }
-
- content = Object.toHTML(content);
-
- tagName = ((position == 'before' || position == 'after')
- ? element.parentNode : element).tagName.toUpperCase();
-
- childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
-
- if (position == 'top' || position == 'after') childNodes.reverse();
- childNodes.each(insert.curry(element));
-
- content.evalScripts.bind(content).defer();
- }
-
- return element;
- },
-
- wrap: function(element, wrapper, attributes) {
- element = $(element);
- if (Object.isElement(wrapper))
- $(wrapper).writeAttribute(attributes || { });
- else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
- else wrapper = new Element('div', wrapper);
- if (element.parentNode)
- element.parentNode.replaceChild(wrapper, element);
- wrapper.appendChild(element);
- return wrapper;
- },
-
- inspect: function(element) {
- element = $(element);
- var result = '<' + element.tagName.toLowerCase();
- $H({'id': 'id', 'className': 'class'}).each(function(pair) {
- var property = pair.first(), attribute = pair.last();
- var value = (element[property] || '').toString();
- if (value) result += ' ' + attribute + '=' + value.inspect(true);
- });
- return result + '>';
- },
-
- recursivelyCollect: function(element, property) {
- element = $(element);
- var elements = [];
- while (element = element[property])
- if (element.nodeType == 1)
- elements.push(Element.extend(element));
- return elements;
- },
-
- ancestors: function(element) {
- return $(element).recursivelyCollect('parentNode');
- },
-
- descendants: function(element) {
- return $(element).select("*");
- },
-
- firstDescendant: function(element) {
- element = $(element).firstChild;
- while (element && element.nodeType != 1) element = element.nextSibling;
- return $(element);
- },
-
- immediateDescendants: function(element) {
- if (!(element = $(element).firstChild)) return [];
- while (element && element.nodeType != 1) element = element.nextSibling;
- if (element) return [element].concat($(element).nextSiblings());
- return [];
- },
-
- previousSiblings: function(element) {
- return $(element).recursivelyCollect('previousSibling');
- },
-
- nextSiblings: function(element) {
- return $(element).recursivelyCollect('nextSibling');
- },
-
- siblings: function(element) {
- element = $(element);
- return element.previousSiblings().reverse().concat(element.nextSiblings());
- },
-
- match: function(element, selector) {
- if (Object.isString(selector))
- selector = new Selector(selector);
- return selector.match($(element));
- },
-
- up: function(element, expression, index) {
- element = $(element);
- if (arguments.length == 1) return $(element.parentNode);
- var ancestors = element.ancestors();
- return Object.isNumber(expression) ? ancestors[expression] :
- Selector.findElement(ancestors, expression, index);
- },
-
- down: function(element, expression, index) {
- element = $(element);
- if (arguments.length == 1) return element.firstDescendant();
- return Object.isNumber(expression) ? element.descendants()[expression] :
- element.select(expression)[index || 0];
- },
-
- previous: function(element, expression, index) {
- element = $(element);
- if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
- var previousSiblings = element.previousSiblings();
- return Object.isNumber(expression) ? previousSiblings[expression] :
- Selector.findElement(previousSiblings, expression, index);
- },
-
- next: function(element, expression, index) {
- element = $(element);
- if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
- var nextSiblings = element.nextSiblings();
- return Object.isNumber(expression) ? nextSiblings[expression] :
- Selector.findElement(nextSiblings, expression, index);
- },
-
- select: function() {
- var args = $A(arguments), element = $(args.shift());
- return Selector.findChildElements(element, args);
- },
-
- adjacent: function() {
- var args = $A(arguments), element = $(args.shift());
- return Selector.findChildElements(element.parentNode, args).without(element);
- },
-
- identify: function(element) {
- element = $(element);
- var id = element.readAttribute('id'), self = arguments.callee;
- if (id) return id;
- do { id = 'anonymous_element_' + self.counter++ } while ($(id));
- element.writeAttribute('id', id);
- return id;
- },
-
- readAttribute: function(element, name) {
- element = $(element);
- if (Prototype.Browser.IE) {
- var t = Element._attributeTranslations.read;
- if (t.values[name]) return t.values[name](element, name);
- if (t.names[name]) name = t.names[name];
- if (name.include(':')) {
- return (!element.attributes || !element.attributes[name]) ? null :
- element.attributes[name].value;
- }
- }
- return element.getAttribute(name);
- },
-
- writeAttribute: function(element, name, value) {
- element = $(element);
- var attributes = { }, t = Element._attributeTranslations.write;
-
- if (typeof name == 'object') attributes = name;
- else attributes[name] = Object.isUndefined(value) ? true : value;
-
- for (var attr in attributes) {
- name = t.names[attr] || attr;
- value = attributes[attr];
- if (t.values[attr]) name = t.values[attr](element, value);
- if (value === false || value === null)
- element.removeAttribute(name);
- else if (value === true)
- element.setAttribute(name, name);
- else element.setAttribute(name, value);
- }
- return element;
- },
-
- getHeight: function(element) {
- return $(element).getDimensions().height;
- },
-
- getWidth: function(element) {
- return $(element).getDimensions().width;
- },
-
- classNames: function(element) {
- return new Element.ClassNames(element);
- },
-
- hasClassName: function(element, className) {
- if (!(element = $(element))) return;
- var elementClassName = element.className;
- return (elementClassName.length > 0 && (elementClassName == className ||
- new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
- },
-
- addClassName: function(element, className) {
- if (!(element = $(element))) return;
- if (!element.hasClassName(className))
- element.className += (element.className ? ' ' : '') + className;
- return element;
- },
-
- removeClassName: function(element, className) {
- if (!(element = $(element))) return;
- element.className = element.className.replace(
- new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
- return element;
- },
-
- toggleClassName: function(element, className) {
- if (!(element = $(element))) return;
- return element[element.hasClassName(className) ?
- 'removeClassName' : 'addClassName'](className);
- },
-
- // removes whitespace-only text node children
- cleanWhitespace: function(element) {
- element = $(element);
- var node = element.firstChild;
- while (node) {
- var nextNode = node.nextSibling;
- if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
- element.removeChild(node);
- node = nextNode;
- }
- return element;
- },
-
- empty: function(element) {
- return $(element).innerHTML.blank();
- },
-
- descendantOf: function(element, ancestor) {
- element = $(element), ancestor = $(ancestor);
- var originalAncestor = ancestor;
-
- if (element.compareDocumentPosition)
- return (element.compareDocumentPosition(ancestor) & 8) === 8;
-
- if (element.sourceIndex && !Prototype.Browser.Opera) {
- var e = element.sourceIndex, a = ancestor.sourceIndex,
- nextAncestor = ancestor.nextSibling;
- if (!nextAncestor) {
- do { ancestor = ancestor.parentNode; }
- while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
- }
- if (nextAncestor && nextAncestor.sourceIndex)
- return (e > a && e < nextAncestor.sourceIndex);
- }
-
- while (element = element.parentNode)
- if (element == originalAncestor) return true;
- return false;
- },
-
- scrollTo: function(element) {
- element = $(element);
- var pos = element.cumulativeOffset();
- window.scrollTo(pos[0], pos[1]);
- return element;
- },
-
- getStyle: function(element, style) {
- element = $(element);
- style = style == 'float' ? 'cssFloat' : style.camelize();
- var value = element.style[style];
- if (!value) {
- var css = document.defaultView.getComputedStyle(element, null);
- value = css ? css[style] : null;
- }
- if (style == 'opacity') return value ? parseFloat(value) : 1.0;
- return value == 'auto' ? null : value;
- },
-
- getOpacity: function(element) {
- return $(element).getStyle('opacity');
- },
-
- setStyle: function(element, styles) {
- element = $(element);
- var elementStyle = element.style, match;
- if (Object.isString(styles)) {
- element.style.cssText += ';' + styles;
- return styles.include('opacity') ?
- element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
- }
- for (var property in styles)
- if (property == 'opacity') element.setOpacity(styles[property]);
- else
- elementStyle[(property == 'float' || property == 'cssFloat') ?
- (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
- property] = styles[property];
-
- return element;
- },
-
- setOpacity: function(element, value) {
- element = $(element);
- element.style.opacity = (value == 1 || value === '') ? '' :
- (value < 0.00001) ? 0 : value;
- return element;
- },
-
- getDimensions: function(element) {
- element = $(element);
- var display = $(element).getStyle('display');
- if (display != 'none' && display != null) // Safari bug
- return {width: element.offsetWidth, height: element.offsetHeight};
-
- // All *Width and *Height properties give 0 on elements with display none,
- // so enable the element temporarily
- var els = element.style;
- var originalVisibility = els.visibility;
- var originalPosition = els.position;
- var originalDisplay = els.display;
- els.visibility = 'hidden';
- els.position = 'absolute';
- els.display = 'block';
- var originalWidth = element.clientWidth;
- var originalHeight = element.clientHeight;
- els.display = originalDisplay;
- els.position = originalPosition;
- els.visibility = originalVisibility;
- return {width: originalWidth, height: originalHeight};
- },
-
- makePositioned: function(element) {
- element = $(element);
- var pos = Element.getStyle(element, 'position');
- if (pos == 'static' || !pos) {
- element._madePositioned = true;
- element.style.position = 'relative';
- // Opera returns the offset relative to the positioning context, when an
- // element is position relative but top and left have not been defined
- if (window.opera) {
- element.style.top = 0;
- element.style.left = 0;
- }
- }
- return element;
- },
-
- undoPositioned: function(element) {
- element = $(element);
- if (element._madePositioned) {
- element._madePositioned = undefined;
- element.style.position =
- element.style.top =
- element.style.left =
- element.style.bottom =
- element.style.right = '';
- }
- return element;
- },
-
- makeClipping: function(element) {
- element = $(element);
- if (element._overflow) return element;
- element._overflow = Element.getStyle(element, 'overflow') || 'auto';
- if (element._overflow !== 'hidden')
- element.style.overflow = 'hidden';
- return element;
- },
-
- undoClipping: function(element) {
- element = $(element);
- if (!element._overflow) return element;
- element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
- element._overflow = null;
- return element;
- },
-
- cumulativeOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- positionedOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- if (element) {
- if (element.tagName == 'BODY') break;
- var p = Element.getStyle(element, 'position');
- if (p !== 'static') break;
- }
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- absolutize: function(element) {
- element = $(element);
- if (element.getStyle('position') == 'absolute') return;
- // Position.prepare(); // To be done manually by Scripty when it needs it.
-
- var offsets = element.positionedOffset();
- var top = offsets[1];
- var left = offsets[0];
- var width = element.clientWidth;
- var height = element.clientHeight;
-
- element._originalLeft = left - parseFloat(element.style.left || 0);
- element._originalTop = top - parseFloat(element.style.top || 0);
- element._originalWidth = element.style.width;
- element._originalHeight = element.style.height;
-
- element.style.position = 'absolute';
- element.style.top = top + 'px';
- element.style.left = left + 'px';
- element.style.width = width + 'px';
- element.style.height = height + 'px';
- return element;
- },
-
- relativize: function(element) {
- element = $(element);
- if (element.getStyle('position') == 'relative') return;
- // Position.prepare(); // To be done manually by Scripty when it needs it.
-
- element.style.position = 'relative';
- var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
- var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
- element.style.top = top + 'px';
- element.style.left = left + 'px';
- element.style.height = element._originalHeight;
- element.style.width = element._originalWidth;
- return element;
- },
-
- cumulativeScrollOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.scrollTop || 0;
- valueL += element.scrollLeft || 0;
- element = element.parentNode;
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- getOffsetParent: function(element) {
- if (element.offsetParent) return $(element.offsetParent);
- if (element == document.body) return $(element);
-
- while ((element = element.parentNode) && element != document.body)
- if (Element.getStyle(element, 'position') != 'static')
- return $(element);
-
- return $(document.body);
- },
-
- viewportOffset: function(forElement) {
- var valueT = 0, valueL = 0;
-
- var element = forElement;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
-
- // Safari fix
- if (element.offsetParent == document.body &&
- Element.getStyle(element, 'position') == 'absolute') break;
-
- } while (element = element.offsetParent);
-
- element = forElement;
- do {
- if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
- valueT -= element.scrollTop || 0;
- valueL -= element.scrollLeft || 0;
- }
- } while (element = element.parentNode);
-
- return Element._returnOffset(valueL, valueT);
- },
-
- clonePosition: function(element, source) {
- var options = Object.extend({
- setLeft: true,
- setTop: true,
- setWidth: true,
- setHeight: true,
- offsetTop: 0,
- offsetLeft: 0
- }, arguments[2] || { });
-
- // find page position of source
- source = $(source);
- var p = source.viewportOffset();
-
- // find coordinate system to use
- element = $(element);
- var delta = [0, 0];
- var parent = null;
- // delta [0,0] will do fine with position: fixed elements,
- // position:absolute needs offsetParent deltas
- if (Element.getStyle(element, 'position') == 'absolute') {
- parent = element.getOffsetParent();
- delta = parent.viewportOffset();
- }
-
- // correct by body offsets (fixes Safari)
- if (parent == document.body) {
- delta[0] -= document.body.offsetLeft;
- delta[1] -= document.body.offsetTop;
- }
-
- // set position
- if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
- if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
- if (options.setWidth) element.style.width = source.offsetWidth + 'px';
- if (options.setHeight) element.style.height = source.offsetHeight + 'px';
- return element;
- }
-};
-
-Element.Methods.identify.counter = 1;
-
-Object.extend(Element.Methods, {
- getElementsBySelector: Element.Methods.select,
- childElements: Element.Methods.immediateDescendants
-});
-
-Element._attributeTranslations = {
- write: {
- names: {
- className: 'class',
- htmlFor: 'for'
- },
- values: { }
- }
-};
-
-if (Prototype.Browser.Opera) {
- Element.Methods.getStyle = Element.Methods.getStyle.wrap(
- function(proceed, element, style) {
- switch (style) {
- case 'left': case 'top': case 'right': case 'bottom':
- if (proceed(element, 'position') === 'static') return null;
- case 'height': case 'width':
- // returns '0px' for hidden elements; we want it to return null
- if (!Element.visible(element)) return null;
-
- // returns the border-box dimensions rather than the content-box
- // dimensions, so we subtract padding and borders from the value
- var dim = parseInt(proceed(element, style), 10);
-
- if (dim !== element['offset' + style.capitalize()])
- return dim + 'px';
-
- var properties;
- if (style === 'height') {
- properties = ['border-top-width', 'padding-top',
- 'padding-bottom', 'border-bottom-width'];
- }
- else {
- properties = ['border-left-width', 'padding-left',
- 'padding-right', 'border-right-width'];
- }
- return properties.inject(dim, function(memo, property) {
- var val = proceed(element, property);
- return val === null ? memo : memo - parseInt(val, 10);
- }) + 'px';
- default: return proceed(element, style);
- }
- }
- );
-
- Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
- function(proceed, element, attribute) {
- if (attribute === 'title') return element.title;
- return proceed(element, attribute);
- }
- );
-}
-
-else if (Prototype.Browser.IE) {
- // IE doesn't report offsets correctly for static elements, so we change them
- // to "relative" to get the values, then change them back.
- Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
- function(proceed, element) {
- element = $(element);
- var position = element.getStyle('position');
- if (position !== 'static') return proceed(element);
- element.setStyle({ position: 'relative' });
- var value = proceed(element);
- element.setStyle({ position: position });
- return value;
- }
- );
-
- $w('positionedOffset viewportOffset').each(function(method) {
- Element.Methods[method] = Element.Methods[method].wrap(
- function(proceed, element) {
- element = $(element);
- var position = element.getStyle('position');
- if (position !== 'static') return proceed(element);
- // Trigger hasLayout on the offset parent so that IE6 reports
- // accurate offsetTop and offsetLeft values for position: fixed.
- var offsetParent = element.getOffsetParent();
- if (offsetParent && offsetParent.getStyle('position') === 'fixed')
- offsetParent.setStyle({ zoom: 1 });
- element.setStyle({ position: 'relative' });
- var value = proceed(element);
- element.setStyle({ position: position });
- return value;
- }
- );
- });
-
- Element.Methods.getStyle = function(element, style) {
- element = $(element);
- style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
- var value = element.style[style];
- if (!value && element.currentStyle) value = element.currentStyle[style];
-
- if (style == 'opacity') {
- if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
- if (value[1]) return parseFloat(value[1]) / 100;
- return 1.0;
- }
-
- if (value == 'auto') {
- if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
- return element['offset' + style.capitalize()] + 'px';
- return null;
- }
- return value;
- };
-
- Element.Methods.setOpacity = function(element, value) {
- function stripAlpha(filter){
- return filter.replace(/alpha\([^\)]*\)/gi,'');
- }
- element = $(element);
- var currentStyle = element.currentStyle;
- if ((currentStyle && !currentStyle.hasLayout) ||
- (!currentStyle && element.style.zoom == 'normal'))
- element.style.zoom = 1;
-
- var filter = element.getStyle('filter'), style = element.style;
- if (value == 1 || value === '') {
- (filter = stripAlpha(filter)) ?
- style.filter = filter : style.removeAttribute('filter');
- return element;
- } else if (value < 0.00001) value = 0;
- style.filter = stripAlpha(filter) +
- 'alpha(opacity=' + (value * 100) + ')';
- return element;
- };
-
- Element._attributeTranslations = {
- read: {
- names: {
- 'class': 'className',
- 'for': 'htmlFor'
- },
- values: {
- _getAttr: function(element, attribute) {
- return element.getAttribute(attribute, 2);
- },
- _getAttrNode: function(element, attribute) {
- var node = element.getAttributeNode(attribute);
- return node ? node.value : "";
- },
- _getEv: function(element, attribute) {
- attribute = element.getAttribute(attribute);
- return attribute ? attribute.toString().slice(23, -2) : null;
- },
- _flag: function(element, attribute) {
- return $(element).hasAttribute(attribute) ? attribute : null;
- },
- style: function(element) {
- return element.style.cssText.toLowerCase();
- },
- title: function(element) {
- return element.title;
- }
- }
- }
- };
-
- Element._attributeTranslations.write = {
- names: Object.extend({
- cellpadding: 'cellPadding',
- cellspacing: 'cellSpacing'
- }, Element._attributeTranslations.read.names),
- values: {
- checked: function(element, value) {
- element.checked = !!value;
- },
-
- style: function(element, value) {
- element.style.cssText = value ? value : '';
- }
- }
- };
-
- Element._attributeTranslations.has = {};
-
- $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
- 'encType maxLength readOnly longDesc').each(function(attr) {
- Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
- Element._attributeTranslations.has[attr.toLowerCase()] = attr;
- });
-
- (function(v) {
- Object.extend(v, {
- href: v._getAttr,
- src: v._getAttr,
- type: v._getAttr,
- action: v._getAttrNode,
- disabled: v._flag,
- checked: v._flag,
- readonly: v._flag,
- multiple: v._flag,
- onload: v._getEv,
- onunload: v._getEv,
- onclick: v._getEv,
- ondblclick: v._getEv,
- onmousedown: v._getEv,
- onmouseup: v._getEv,
- onmouseover: v._getEv,
- onmousemove: v._getEv,
- onmouseout: v._getEv,
- onfocus: v._getEv,
- onblur: v._getEv,
- onkeypress: v._getEv,
- onkeydown: v._getEv,
- onkeyup: v._getEv,
- onsubmit: v._getEv,
- onreset: v._getEv,
- onselect: v._getEv,
- onchange: v._getEv
- });
- })(Element._attributeTranslations.read.values);
-}
-
-else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
- Element.Methods.setOpacity = function(element, value) {
- element = $(element);
- element.style.opacity = (value == 1) ? 0.999999 :
- (value === '') ? '' : (value < 0.00001) ? 0 : value;
- return element;
- };
-}
-
-else if (Prototype.Browser.WebKit) {
- Element.Methods.setOpacity = function(element, value) {
- element = $(element);
- element.style.opacity = (value == 1 || value === '') ? '' :
- (value < 0.00001) ? 0 : value;
-
- if (value == 1)
- if(element.tagName == 'IMG' && element.width) {
- element.width++; element.width--;
- } else try {
- var n = document.createTextNode(' ');
- element.appendChild(n);
- element.removeChild(n);
- } catch (e) { }
-
- return element;
- };
-
- // Safari returns margins on body which is incorrect if the child is absolutely
- // positioned. For performance reasons, redefine Element#cumulativeOffset for
- // KHTML/WebKit only.
- Element.Methods.cumulativeOffset = function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- if (element.offsetParent == document.body)
- if (Element.getStyle(element, 'position') == 'absolute') break;
-
- element = element.offsetParent;
- } while (element);
-
- return Element._returnOffset(valueL, valueT);
- };
-}
-
-if (Prototype.Browser.IE || Prototype.Browser.Opera) {
- // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
- Element.Methods.update = function(element, content) {
- element = $(element);
-
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) return element.update().insert(content);
-
- content = Object.toHTML(content);
- var tagName = element.tagName.toUpperCase();
-
- if (tagName in Element._insertionTranslations.tags) {
- $A(element.childNodes).each(function(node) { element.removeChild(node) });
- Element._getContentFromAnonymousElement(tagName, content.stripScripts())
- .each(function(node) { element.appendChild(node) });
- }
- else element.innerHTML = content.stripScripts();
-
- content.evalScripts.bind(content).defer();
- return element;
- };
-}
-
-if ('outerHTML' in document.createElement('div')) {
- Element.Methods.replace = function(element, content) {
- element = $(element);
-
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) {
- element.parentNode.replaceChild(content, element);
- return element;
- }
-
- content = Object.toHTML(content);
- var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
-
- if (Element._insertionTranslations.tags[tagName]) {
- var nextSibling = element.next();
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
- parent.removeChild(element);
- if (nextSibling)
- fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
- else
- fragments.each(function(node) { parent.appendChild(node) });
- }
- else element.outerHTML = content.stripScripts();
-
- content.evalScripts.bind(content).defer();
- return element;
- };
-}
-
-Element._returnOffset = function(l, t) {
- var result = [l, t];
- result.left = l;
- result.top = t;
- return result;
-};
-
-Element._getContentFromAnonymousElement = function(tagName, html) {
- var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
- if (t) {
- div.innerHTML = t[0] + html + t[1];
- t[2].times(function() { div = div.firstChild });
- } else div.innerHTML = html;
- return $A(div.childNodes);
-};
-
-Element._insertionTranslations = {
- before: function(element, node) {
- element.parentNode.insertBefore(node, element);
- },
- top: function(element, node) {
- element.insertBefore(node, element.firstChild);
- },
- bottom: function(element, node) {
- element.appendChild(node);
- },
- after: function(element, node) {
- element.parentNode.insertBefore(node, element.nextSibling);
- },
- tags: {
- TABLE: ['<table>', '</table>', 1],
- TBODY: ['<table><tbody>', '</tbody></table>', 2],
- TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
- TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
- SELECT: ['<select>', '</select>', 1]
- }
-};
-
-(function() {
- Object.extend(this.tags, {
- THEAD: this.tags.TBODY,
- TFOOT: this.tags.TBODY,
- TH: this.tags.TD
- });
-}).call(Element._insertionTranslations);
-
-Element.Methods.Simulated = {
- hasAttribute: function(element, attribute) {
- attribute = Element._attributeTranslations.has[attribute] || attribute;
- var node = $(element).getAttributeNode(attribute);
- return node && node.specified;
- }
-};
-
-Element.Methods.ByTag = { };
-
-Object.extend(Element, Element.Methods);
-
-if (!Prototype.BrowserFeatures.ElementExtensions &&
- document.createElement('div').__proto__) {
- window.HTMLElement = { };
- window.HTMLElement.prototype = document.createElement('div').__proto__;
- Prototype.BrowserFeatures.ElementExtensions = true;
-}
-
-Element.extend = (function() {
- if (Prototype.BrowserFeatures.SpecificElementExtensions)
- return Prototype.K;
-
- var Methods = { }, ByTag = Element.Methods.ByTag;
-
- var extend = Object.extend(function(element) {
- if (!element || element._extendedByPrototype ||
- element.nodeType != 1 || element == window) return element;
-
- var methods = Object.clone(Methods),
- tagName = element.tagName, property, value;
-
- // extend methods for specific tags
- if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
-
- for (property in methods) {
- value = methods[property];
- if (Object.isFunction(value) && !(property in element))
- element[property] = value.methodize();
- }
-
- element._extendedByPrototype = Prototype.emptyFunction;
- return element;
-
- }, {
- refresh: function() {
- // extend methods for all tags (Safari doesn't need this)
- if (!Prototype.BrowserFeatures.ElementExtensions) {
- Object.extend(Methods, Element.Methods);
- Object.extend(Methods, Element.Methods.Simulated);
- }
- }
- });
-
- extend.refresh();
- return extend;
-})();
-
-Element.hasAttribute = function(element, attribute) {
- if (element.hasAttribute) return element.hasAttribute(attribute);
- return Element.Methods.Simulated.hasAttribute(element, attribute);
-};
-
-Element.addMethods = function(methods) {
- var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
-
- if (!methods) {
- Object.extend(Form, Form.Methods);
- Object.extend(Form.Element, Form.Element.Methods);
- Object.extend(Element.Methods.ByTag, {
- "FORM": Object.clone(Form.Methods),
- "INPUT": Object.clone(Form.Element.Methods),
- "SELECT": Object.clone(Form.Element.Methods),
- "TEXTAREA": Object.clone(Form.Element.Methods)
- });
- }
-
- if (arguments.length == 2) {
- var tagName = methods;
- methods = arguments[1];
- }
-
- if (!tagName) Object.extend(Element.Methods, methods || { });
- else {
- if (Object.isArray(tagName)) tagName.each(extend);
- else extend(tagName);
- }
-
- function extend(tagName) {
- tagName = tagName.toUpperCase();
- if (!Element.Methods.ByTag[tagName])
- Element.Methods.ByTag[tagName] = { };
- Object.extend(Element.Methods.ByTag[tagName], methods);
- }
-
- function copy(methods, destination, onlyIfAbsent) {
- onlyIfAbsent = onlyIfAbsent || false;
- for (var property in methods) {
- var value = methods[property];
- if (!Object.isFunction(value)) continue;
- if (!onlyIfAbsent || !(property in destination))
- destination[property] = value.methodize();
- }
- }
-
- function findDOMClass(tagName) {
- var klass;
- var trans = {
- "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
- "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
- "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
- "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
- "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
- "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
- "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
- "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
- "FrameSet", "IFRAME": "IFrame"
- };
- if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
- if (window[klass]) return window[klass];
- klass = 'HTML' + tagName + 'Element';
- if (window[klass]) return window[klass];
- klass = 'HTML' + tagName.capitalize() + 'Element';
- if (window[klass]) return window[klass];
-
- window[klass] = { };
- window[klass].prototype = document.createElement(tagName).__proto__;
- return window[klass];
- }
-
- if (F.ElementExtensions) {
- copy(Element.Methods, HTMLElement.prototype);
- copy(Element.Methods.Simulated, HTMLElement.prototype, true);
- }
-
- if (F.SpecificElementExtensions) {
- for (var tag in Element.Methods.ByTag) {
- var klass = findDOMClass(tag);
- if (Object.isUndefined(klass)) continue;
- copy(T[tag], klass.prototype);
- }
- }
-
- Object.extend(Element, Element.Methods);
- delete Element.ByTag;
-
- if (Element.extend.refresh) Element.extend.refresh();
- Element.cache = { };
-};
-
-document.viewport = {
- getDimensions: function() {
- var dimensions = { };
- var B = Prototype.Browser;
- $w('width height').each(function(d) {
- var D = d.capitalize();
- dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
- (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
- });
- return dimensions;
- },
-
- getWidth: function() {
- return this.getDimensions().width;
- },
-
- getHeight: function() {
- return this.getDimensions().height;
- },
-
- getScrollOffsets: function() {
- return Element._returnOffset(
- window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
- window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
- }
-};
-/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
- * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
- * license. Please see http://www.yui-ext.com/ for more information. */
-
-var Selector = Class.create({
- initialize: function(expression) {
- this.expression = expression.strip();
- this.compileMatcher();
- },
-
- shouldUseXPath: function() {
- if (!Prototype.BrowserFeatures.XPath) return false;
-
- var e = this.expression;
-
- // Safari 3 chokes on :*-of-type and :empty
- if (Prototype.Browser.WebKit &&
- (e.include("-of-type") || e.include(":empty")))
- return false;
-
- // XPath can't do namespaced attributes, nor can it read
- // the "checked" property from DOM nodes
- if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
- return false;
-
- return true;
- },
-
- compileMatcher: function() {
- if (this.shouldUseXPath())
- return this.compileXPathMatcher();
-
- var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
- c = Selector.criteria, le, p, m;
-
- if (Selector._cache[e]) {
- this.matcher = Selector._cache[e];
- return;
- }
-
- this.matcher = ["this.matcher = function(root) {",
- "var r = root, h = Selector.handlers, c = false, n;"];
-
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i in ps) {
- p = ps[i];
- if (m = e.match(p)) {
- this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
- new Template(c[i]).evaluate(m));
- e = e.replace(m[0], '');
- break;
- }
- }
- }
-
- this.matcher.push("return h.unique(n);\n}");
- eval(this.matcher.join('\n'));
- Selector._cache[this.expression] = this.matcher;
- },
-
- compileXPathMatcher: function() {
- var e = this.expression, ps = Selector.patterns,
- x = Selector.xpath, le, m;
-
- if (Selector._cache[e]) {
- this.xpath = Selector._cache[e]; return;
- }
-
- this.matcher = ['.//*'];
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i in ps) {
- if (m = e.match(ps[i])) {
- this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
- new Template(x[i]).evaluate(m));
- e = e.replace(m[0], '');
- break;
- }
- }
- }
-
- this.xpath = this.matcher.join('');
- Selector._cache[this.expression] = this.xpath;
- },
-
- findElements: function(root) {
- root = root || document;
- if (this.xpath) return document._getElementsByXPath(this.xpath, root);
- return this.matcher(root);
- },
-
- match: function(element) {
- this.tokens = [];
-
- var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
- var le, p, m;
-
- while (e && le !== e && (/\S/).test(e)) {
- le = e;
- for (var i in ps) {
- p = ps[i];
- if (m = e.match(p)) {
- // use the Selector.assertions methods unless the selector
- // is too complex.
- if (as[i]) {
- this.tokens.push([i, Object.clone(m)]);
- e = e.replace(m[0], '');
- } else {
- // reluctantly do a document-wide search
- // and look for a match in the array
- return this.findElements(document).include(element);
- }
- }
- }
- }
-
- var match = true, name, matches;
- for (var i = 0, token; token = this.tokens[i]; i++) {
- name = token[0], matches = token[1];
- if (!Selector.assertions[name](element, matches)) {
- match = false; break;
- }
- }
-
- return match;
- },
-
- toString: function() {
- return this.expression;
- },
-
- inspect: function() {
- return "#<Selector:" + this.expression.inspect() + ">";
- }
-});
-
-Object.extend(Selector, {
- _cache: { },
-
- xpath: {
- descendant: "//*",
- child: "/*",
- adjacent: "/following-sibling::*[1]",
- laterSibling: '/following-sibling::*',
- tagName: function(m) {
- if (m[1] == '*') return '';
- return "[local-name()='" + m[1].toLowerCase() +
- "' or local-name()='" + m[1].toUpperCase() + "']";
- },
- className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
- id: "[@id='#{1}']",
- attrPresence: function(m) {
- m[1] = m[1].toLowerCase();
- return new Template("[@#{1}]").evaluate(m);
- },
- attr: function(m) {
- m[1] = m[1].toLowerCase();
- m[3] = m[5] || m[6];
- return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
- },
- pseudo: function(m) {
- var h = Selector.xpath.pseudos[m[1]];
- if (!h) return '';
- if (Object.isFunction(h)) return h(m);
- return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
- },
- operators: {
- '=': "[@#{1}='#{3}']",
- '!=': "[@#{1}!='#{3}']",
- '^=': "[starts-with(@#{1}, '#{3}')]",
- '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
- '*=': "[contains(@#{1}, '#{3}')]",
- '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
- '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
- },
- pseudos: {
- 'first-child': '[not(preceding-sibling::*)]',
- 'last-child': '[not(following-sibling::*)]',
- 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
- 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
- 'checked': "[@checked]",
- 'disabled': "[@disabled]",
- 'enabled': "[not(@disabled)]",
- 'not': function(m) {
- var e = m[6], p = Selector.patterns,
- x = Selector.xpath, le, v;
-
- var exclusion = [];
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i in p) {
- if (m = e.match(p[i])) {
- v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
- exclusion.push("(" + v.substring(1, v.length - 1) + ")");
- e = e.replace(m[0], '');
- break;
- }
- }
- }
- return "[not(" + exclusion.join(" and ") + ")]";
- },
- 'nth-child': function(m) {
- return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
- },
- 'nth-last-child': function(m) {
- return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
- },
- 'nth-of-type': function(m) {
- return Selector.xpath.pseudos.nth("position() ", m);
- },
- 'nth-last-of-type': function(m) {
- return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
- },
- 'first-of-type': function(m) {
- m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
- },
- 'last-of-type': function(m) {
- m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
- },
- 'only-of-type': function(m) {
- var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
- },
- nth: function(fragment, m) {
- var mm, formula = m[6], predicate;
- if (formula == 'even') formula = '2n+0';
- if (formula == 'odd') formula = '2n+1';
- if (mm = formula.match(/^(\d+)$/)) // digit only
- return '[' + fragment + "= " + mm[1] + ']';
- if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
- if (mm[1] == "-") mm[1] = -1;
- var a = mm[1] ? Number(mm[1]) : 1;
- var b = mm[2] ? Number(mm[2]) : 0;
- predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
- "((#{fragment} - #{b}) div #{a} >= 0)]";
- return new Template(predicate).evaluate({
- fragment: fragment, a: a, b: b });
- }
- }
- }
- },
-
- criteria: {
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
- className: 'n = h.className(n, r, "#{1}", c); c = false;',
- id: 'n = h.id(n, r, "#{1}", c); c = false;',
- attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
- attr: function(m) {
- m[3] = (m[5] || m[6]);
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
- },
- pseudo: function(m) {
- if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
- return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
- },
- descendant: 'c = "descendant";',
- child: 'c = "child";',
- adjacent: 'c = "adjacent";',
- laterSibling: 'c = "laterSibling";'
- },
-
- patterns: {
- // combinators must be listed first
- // (and descendant needs to be last combinator)
- laterSibling: /^\s*~\s*/,
- child: /^\s*>\s*/,
- adjacent: /^\s*\+\s*/,
- descendant: /^\s/,
-
- // selectors follow
- tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
- id: /^#([\w\-\*]+)(\b|$)/,
- className: /^\.([\w\-\*]+)(\b|$)/,
- pseudo:
-/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
- attrPresence: /^\[([\w]+)\]/,
- attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
- },
-
- // for Selector.match and Element#match
- assertions: {
- tagName: function(element, matches) {
- return matches[1].toUpperCase() == element.tagName.toUpperCase();
- },
-
- className: function(element, matches) {
- return Element.hasClassName(element, matches[1]);
- },
-
- id: function(element, matches) {
- return element.id === matches[1];
- },
-
- attrPresence: function(element, matches) {
- return Element.hasAttribute(element, matches[1]);
- },
-
- attr: function(element, matches) {
- var nodeValue = Element.readAttribute(element, matches[1]);
- return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
- }
- },
-
- handlers: {
- // UTILITY FUNCTIONS
- // joins two collections
- concat: function(a, b) {
- for (var i = 0, node; node = b[i]; i++)
- a.push(node);
- return a;
- },
-
- // marks an array of nodes for counting
- mark: function(nodes) {
- var _true = Prototype.emptyFunction;
- for (var i = 0, node; node = nodes[i]; i++)
- node._countedByPrototype = _true;
- return nodes;
- },
-
- unmark: function(nodes) {
- for (var i = 0, node; node = nodes[i]; i++)
- node._countedByPrototype = undefined;
- return nodes;
- },
-
- // mark each child node with its position (for nth calls)
- // "ofType" flag indicates whether we're indexing for nth-of-type
- // rather than nth-child
- index: function(parentNode, reverse, ofType) {
- parentNode._countedByPrototype = Prototype.emptyFunction;
- if (reverse) {
- for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
- var node = nodes[i];
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
- }
- } else {
- for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
- }
- },
-
- // filters out duplicates and extends all nodes
- unique: function(nodes) {
- if (nodes.length == 0) return nodes;
- var results = [], n;
- for (var i = 0, l = nodes.length; i < l; i++)
- if (!(n = nodes[i])._countedByPrototype) {
- n._countedByPrototype = Prototype.emptyFunction;
- results.push(Element.extend(n));
- }
- return Selector.handlers.unmark(results);
- },
-
- // COMBINATOR FUNCTIONS
- descendant: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- h.concat(results, node.getElementsByTagName('*'));
- return results;
- },
-
- child: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- for (var j = 0, child; child = node.childNodes[j]; j++)
- if (child.nodeType == 1 && child.tagName != '!') results.push(child);
- }
- return results;
- },
-
- adjacent: function(nodes) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- var next = this.nextElementSibling(node);
- if (next) results.push(next);
- }
- return results;
- },
-
- laterSibling: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- h.concat(results, Element.nextSiblings(node));
- return results;
- },
-
- nextElementSibling: function(node) {
- while (node = node.nextSibling)
- if (node.nodeType == 1) return node;
- return null;
- },
-
- previousElementSibling: function(node) {
- while (node = node.previousSibling)
- if (node.nodeType == 1) return node;
- return null;
- },
-
- // TOKEN FUNCTIONS
- tagName: function(nodes, root, tagName, combinator) {
- var uTagName = tagName.toUpperCase();
- var results = [], h = Selector.handlers;
- if (nodes) {
- if (combinator) {
- // fastlane for ordinary descendant combinators
- if (combinator == "descendant") {
- for (var i = 0, node; node = nodes[i]; i++)
- h.concat(results, node.getElementsByTagName(tagName));
- return results;
- } else nodes = this[combinator](nodes);
- if (tagName == "*") return nodes;
- }
- for (var i = 0, node; node = nodes[i]; i++)
- if (node.tagName.toUpperCase() === uTagName) results.push(node);
- return results;
- } else return root.getElementsByTagName(tagName);
- },
-
- id: function(nodes, root, id, combinator) {
- var targetNode = $(id), h = Selector.handlers;
- if (!targetNode) return [];
- if (!nodes && root == document) return [targetNode];
- if (nodes) {
- if (combinator) {
- if (combinator == 'child') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (targetNode.parentNode == node) return [targetNode];
- } else if (combinator == 'descendant') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (Element.descendantOf(targetNode, node)) return [targetNode];
- } else if (combinator == 'adjacent') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (Selector.handlers.previousElementSibling(targetNode) == node)
- return [targetNode];
- } else nodes = h[combinator](nodes);
- }
- for (var i = 0, node; node = nodes[i]; i++)
- if (node == targetNode) return [targetNode];
- return [];
- }
- return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
- },
-
- className: function(nodes, root, className, combinator) {
- if (nodes && combinator) nodes = this[combinator](nodes);
- return Selector.handlers.byClassName(nodes, root, className);
- },
-
- byClassName: function(nodes, root, className) {
- if (!nodes) nodes = Selector.handlers.descendant([root]);
- var needle = ' ' + className + ' ';
- for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
- nodeClassName = node.className;
- if (nodeClassName.length == 0) continue;
- if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
- results.push(node);
- }
- return results;
- },
-
- attrPresence: function(nodes, root, attr, combinator) {
- if (!nodes) nodes = root.getElementsByTagName("*");
- if (nodes && combinator) nodes = this[combinator](nodes);
- var results = [];
- for (var i = 0, node; node = nodes[i]; i++)
- if (Element.hasAttribute(node, attr)) results.push(node);
- return results;
- },
-
- attr: function(nodes, root, attr, value, operator, combinator) {
- if (!nodes) nodes = root.getElementsByTagName("*");
- if (nodes && combinator) nodes = this[combinator](nodes);
- var handler = Selector.operators[operator], results = [];
- for (var i = 0, node; node = nodes[i]; i++) {
- var nodeValue = Element.readAttribute(node, attr);
- if (nodeValue === null) continue;
- if (handler(nodeValue, value)) results.push(node);
- }
- return results;
- },
-
- pseudo: function(nodes, name, value, root, combinator) {
- if (nodes && combinator) nodes = this[combinator](nodes);
- if (!nodes) nodes = root.getElementsByTagName("*");
- return Selector.pseudos[name](nodes, value, root);
- }
- },
-
- pseudos: {
- 'first-child': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- if (Selector.handlers.previousElementSibling(node)) continue;
- results.push(node);
- }
- return results;
- },
- 'last-child': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- if (Selector.handlers.nextElementSibling(node)) continue;
- results.push(node);
- }
- return results;
- },
- 'only-child': function(nodes, value, root) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
- results.push(node);
- return results;
- },
- 'nth-child': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root);
- },
- 'nth-last-child': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, true);
- },
- 'nth-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, false, true);
- },
- 'nth-last-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, true, true);
- },
- 'first-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, "1", root, false, true);
- },
- 'last-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, "1", root, true, true);
- },
- 'only-of-type': function(nodes, formula, root) {
- var p = Selector.pseudos;
- return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
- },
-
- // handles the an+b logic
- getIndices: function(a, b, total) {
- if (a == 0) return b > 0 ? [b] : [];
- return $R(1, total).inject([], function(memo, i) {
- if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
- return memo;
- });
- },
-
- // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
- nth: function(nodes, formula, root, reverse, ofType) {
- if (nodes.length == 0) return [];
- if (formula == 'even') formula = '2n+0';
- if (formula == 'odd') formula = '2n+1';
- var h = Selector.handlers, results = [], indexed = [], m;
- h.mark(nodes);
- for (var i = 0, node; node = nodes[i]; i++) {
- if (!node.parentNode._countedByPrototype) {
- h.index(node.parentNode, reverse, ofType);
- indexed.push(node.parentNode);
- }
- }
- if (formula.match(/^\d+$/)) { // just a number
- formula = Number(formula);
- for (var i = 0, node; node = nodes[i]; i++)
- if (node.nodeIndex == formula) results.push(node);
- } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
- if (m[1] == "-") m[1] = -1;
- var a = m[1] ? Number(m[1]) : 1;
- var b = m[2] ? Number(m[2]) : 0;
- var indices = Selector.pseudos.getIndices(a, b, nodes.length);
- for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
- for (var j = 0; j < l; j++)
- if (node.nodeIndex == indices[j]) results.push(node);
- }
- }
- h.unmark(nodes);
- h.unmark(indexed);
- return results;
- },
-
- 'empty': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- // IE treats comments as element nodes
- if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
- results.push(node);
- }
- return results;
- },
-
- 'not': function(nodes, selector, root) {
- var h = Selector.handlers, selectorType, m;
- var exclusions = new Selector(selector).findElements(root);
- h.mark(exclusions);
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node._countedByPrototype) results.push(node);
- h.unmark(exclusions);
- return results;
- },
-
- 'enabled': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node.disabled) results.push(node);
- return results;
- },
-
- 'disabled': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (node.disabled) results.push(node);
- return results;
- },
-
- 'checked': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (node.checked) results.push(node);
- return results;
- }
- },
-
- operators: {
- '=': function(nv, v) { return nv == v; },
- '!=': function(nv, v) { return nv != v; },
- '^=': function(nv, v) { return nv.startsWith(v); },
- '$=': function(nv, v) { return nv.endsWith(v); },
- '*=': function(nv, v) { return nv.include(v); },
- '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
- '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
- },
-
- split: function(expression) {
- var expressions = [];
- expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
- expressions.push(m[1].strip());
- });
- return expressions;
- },
-
- matchElements: function(elements, expression) {
- var matches = $$(expression), h = Selector.handlers;
- h.mark(matches);
- for (var i = 0, results = [], element; element = elements[i]; i++)
- if (element._countedByPrototype) results.push(element);
- h.unmark(matches);
- return results;
- },
-
- findElement: function(elements, expression, index) {
- if (Object.isNumber(expression)) {
- index = expression; expression = false;
- }
- return Selector.matchElements(elements, expression || '*')[index || 0];
- },
-
- findChildElements: function(element, expressions) {
- expressions = Selector.split(expressions.join(','));
- var results = [], h = Selector.handlers;
- for (var i = 0, l = expressions.length, selector; i < l; i++) {
- selector = new Selector(expressions[i].strip());
- h.concat(results, selector.findElements(element));
- }
- return (l > 1) ? h.unique(results) : results;
- }
-});
-
-if (Prototype.Browser.IE) {
- Object.extend(Selector.handlers, {
- // IE returns comment nodes on getElementsByTagName("*").
- // Filter them out.
- concat: function(a, b) {
- for (var i = 0, node; node = b[i]; i++)
- if (node.tagName !== "!") a.push(node);
- return a;
- },
-
- // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
- unmark: function(nodes) {
- for (var i = 0, node; node = nodes[i]; i++)
- node.removeAttribute('_countedByPrototype');
- return nodes;
- }
- });
-}
-
-function $$() {
- return Selector.findChildElements(document, $A(arguments));
-}
-var Form = {
- reset: function(form) {
- $(form).reset();
- return form;
- },
-
- serializeElements: function(elements, options) {
- if (typeof options != 'object') options = { hash: !!options };
- else if (Object.isUndefined(options.hash)) options.hash = true;
- var key, value, submitted = false, submit = options.submit;
-
- var data = elements.inject({ }, function(result, element) {
- if (!element.disabled && element.name) {
- key = element.name; value = $(element).getValue();
- if (value != null && (element.type != 'submit' || (!submitted &&
- submit !== false && (!submit || key == submit) && (submitted = true)))) {
- if (key in result) {
- // a key is already present; construct an array of values
- if (!Object.isArray(result[key])) result[key] = [result[key]];
- result[key].push(value);
- }
- else result[key] = value;
- }
- }
- return result;
- });
-
- return options.hash ? data : Object.toQueryString(data);
- }
-};
-
-Form.Methods = {
- serialize: function(form, options) {
- return Form.serializeElements(Form.getElements(form), options);
- },
-
- getElements: function(form) {
- return $A($(form).getElementsByTagName('*')).inject([],
- function(elements, child) {
- if (Form.Element.Serializers[child.tagName.toLowerCase()])
- elements.push(Element.extend(child));
- return elements;
- }
- );
- },
-
- getInputs: function(form, typeName, name) {
- form = $(form);
- var inputs = form.getElementsByTagName('input');
-
- if (!typeName && !name) return $A(inputs).map(Element.extend);
-
- for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
- var input = inputs[i];
- if ((typeName && input.type != typeName) || (name && input.name != name))
- continue;
- matchingInputs.push(Element.extend(input));
- }
-
- return matchingInputs;
- },
-
- disable: function(form) {
- form = $(form);
- Form.getElements(form).invoke('disable');
- return form;
- },
-
- enable: function(form) {
- form = $(form);
- Form.getElements(form).invoke('enable');
- return form;
- },
-
- findFirstElement: function(form) {
- var elements = $(form).getElements().findAll(function(element) {
- return 'hidden' != element.type && !element.disabled;
- });
- var firstByIndex = elements.findAll(function(element) {
- return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
- }).sortBy(function(element) { return element.tabIndex }).first();
-
- return firstByIndex ? firstByIndex : elements.find(function(element) {
- return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
- });
- },
-
- focusFirstElement: function(form) {
- form = $(form);
- form.findFirstElement().activate();
- return form;
- },
-
- request: function(form, options) {
- form = $(form), options = Object.clone(options || { });
-
- var params = options.parameters, action = form.readAttribute('action') || '';
- if (action.blank()) action = window.location.href;
- options.parameters = form.serialize(true);
-
- if (params) {
- if (Object.isString(params)) params = params.toQueryParams();
- Object.extend(options.parameters, params);
- }
-
- if (form.hasAttribute('method') && !options.method)
- options.method = form.method;
-
- return new Ajax.Request(action, options);
- }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element = {
- focus: function(element) {
- $(element).focus();
- return element;
- },
-
- select: function(element) {
- $(element).select();
- return element;
- }
-};
-
-Form.Element.Methods = {
- serialize: function(element) {
- element = $(element);
- if (!element.disabled && element.name) {
- var value = element.getValue();
- if (value != undefined) {
- var pair = { };
- pair[element.name] = value;
- return Object.toQueryString(pair);
- }
- }
- return '';
- },
-
- getValue: function(element) {
- element = $(element);
- var method = element.tagName.toLowerCase();
- return Form.Element.Serializers[method](element);
- },
-
- setValue: function(element, value) {
- element = $(element);
- var method = element.tagName.toLowerCase();
- Form.Element.Serializers[method](element, value);
- return element;
- },
-
- clear: function(element) {
- $(element).value = '';
- return element;
- },
-
- present: function(element) {
- return $(element).value != '';
- },
-
- activate: function(element) {
- element = $(element);
- try {
- element.focus();
- if (element.select && (element.tagName.toLowerCase() != 'input' ||
- !['button', 'reset', 'submit'].include(element.type)))
- element.select();
- } catch (e) { }
- return element;
- },
-
- disable: function(element) {
- element = $(element);
- element.blur();
- element.disabled = true;
- return element;
- },
-
- enable: function(element) {
- element = $(element);
- element.disabled = false;
- return element;
- }
-};
-
-/*--------------------------------------------------------------------------*/
-
-var Field = Form.Element;
-var $F = Form.Element.Methods.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element.Serializers = {
- input: function(element, value) {
- switch (element.type.toLowerCase()) {
- case 'checkbox':
- case 'radio':
- return Form.Element.Serializers.inputSelector(element, value);
- default:
- return Form.Element.Serializers.textarea(element, value);
- }
- },
-
- inputSelector: function(element, value) {
- if (Object.isUndefined(value)) return element.checked ? element.value : null;
- else element.checked = !!value;
- },
-
- textarea: function(element, value) {
- if (Object.isUndefined(value)) return element.value;
- else element.value = value;
- },
-
- select: function(element, index) {
- if (Object.isUndefined(index))
- return this[element.type == 'select-one' ?
- 'selectOne' : 'selectMany'](element);
- else {
- var opt, value, single = !Object.isArray(index);
- for (var i = 0, length = element.length; i < length; i++) {
- opt = element.options[i];
- value = this.optionValue(opt);
- if (single) {
- if (value == index) {
- opt.selected = true;
- return;
- }
- }
- else opt.selected = index.include(value);
- }
- }
- },
-
- selectOne: function(element) {
- var index = element.selectedIndex;
- return index >= 0 ? this.optionValue(element.options[index]) : null;
- },
-
- selectMany: function(element) {
- var values, length = element.length;
- if (!length) return null;
-
- for (var i = 0, values = []; i < length; i++) {
- var opt = element.options[i];
- if (opt.selected) values.push(this.optionValue(opt));
- }
- return values;
- },
-
- optionValue: function(opt) {
- // extend element because hasAttribute may not be native
- return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
- }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
- initialize: function($super, element, frequency, callback) {
- $super(callback, frequency);
- this.element = $(element);
- this.lastValue = this.getValue();
- },
-
- execute: function() {
- var value = this.getValue();
- if (Object.isString(this.lastValue) && Object.isString(value) ?
- this.lastValue != value : String(this.lastValue) != String(value)) {
- this.callback(this.element, value);
- this.lastValue = value;
- }
- }
-});
-
-Form.Element.Observer = Class.create(Abstract.TimedObserver, {
- getValue: function() {
- return Form.Element.getValue(this.element);
- }
-});
-
-Form.Observer = Class.create(Abstract.TimedObserver, {
- getValue: function() {
- return Form.serialize(this.element);
- }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = Class.create({
- initialize: function(element, callback) {
- this.element = $(element);
- this.callback = callback;
-
- this.lastValue = this.getValue();
- if (this.element.tagName.toLowerCase() == 'form')
- this.registerFormCallbacks();
- else
- this.registerCallback(this.element);
- },
-
- onElementEvent: function() {
- var value = this.getValue();
- if (this.lastValue != value) {
- this.callback(this.element, value);
- this.lastValue = value;
- }
- },
-
- registerFormCallbacks: function() {
- Form.getElements(this.element).each(this.registerCallback, this);
- },
-
- registerCallback: function(element) {
- if (element.type) {
- switch (element.type.toLowerCase()) {
- case 'checkbox':
- case 'radio':
- Event.observe(element, 'click', this.onElementEvent.bind(this));
- break;
- default:
- Event.observe(element, 'change', this.onElementEvent.bind(this));
- break;
- }
- }
- }
-});
-
-Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
- getValue: function() {
- return Form.Element.getValue(this.element);
- }
-});
-
-Form.EventObserver = Class.create(Abstract.EventObserver, {
- getValue: function() {
- return Form.serialize(this.element);
- }
-});
-if (!window.Event) var Event = { };
-
-Object.extend(Event, {
- KEY_BACKSPACE: 8,
- KEY_TAB: 9,
- KEY_RETURN: 13,
- KEY_ESC: 27,
- KEY_LEFT: 37,
- KEY_UP: 38,
- KEY_RIGHT: 39,
- KEY_DOWN: 40,
- KEY_DELETE: 46,
- KEY_HOME: 36,
- KEY_END: 35,
- KEY_PAGEUP: 33,
- KEY_PAGEDOWN: 34,
- KEY_INSERT: 45,
-
- cache: { },
-
- relatedTarget: function(event) {
- var element;
- switch(event.type) {
- case 'mouseover': element = event.fromElement; break;
- case 'mouseout': element = event.toElement; break;
- default: return null;
- }
- return Element.extend(element);
- }
-});
-
-Event.Methods = (function() {
- var isButton;
-
- if (Prototype.Browser.IE) {
- var buttonMap = { 0: 1, 1: 4, 2: 2 };
- isButton = function(event, code) {
- return event.button == buttonMap[code];
- };
-
- } else if (Prototype.Browser.WebKit) {
- isButton = function(event, code) {
- switch (code) {
- case 0: return event.which == 1 && !event.metaKey;
- case 1: return event.which == 1 && event.metaKey;
- default: return false;
- }
- };
-
- } else {
- isButton = function(event, code) {
- return event.which ? (event.which === code + 1) : (event.button === code);
- };
- }
-
- return {
- isLeftClick: function(event) { return isButton(event, 0) },
- isMiddleClick: function(event) { return isButton(event, 1) },
- isRightClick: function(event) { return isButton(event, 2) },
-
- element: function(event) {
- var node = Event.extend(event).target;
- return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
- },
-
- findElement: function(event, expression) {
- var element = Event.element(event);
- if (!expression) return element;
- var elements = [element].concat(element.ancestors());
- return Selector.findElement(elements, expression, 0);
- },
-
- pointer: function(event) {
- return {
- x: event.pageX || (event.clientX +
- (document.documentElement.scrollLeft || document.body.scrollLeft)),
- y: event.pageY || (event.clientY +
- (document.documentElement.scrollTop || document.body.scrollTop))
- };
- },
-
- pointerX: function(event) { return Event.pointer(event).x },
- pointerY: function(event) { return Event.pointer(event).y },
-
- stop: function(event) {
- Event.extend(event);
- event.preventDefault();
- event.stopPropagation();
- event.stopped = true;
- }
- };
-})();
-
-Event.extend = (function() {
- var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
- m[name] = Event.Methods[name].methodize();
- return m;
- });
-
- if (Prototype.Browser.IE) {
- Object.extend(methods, {
- stopPropagation: function() { this.cancelBubble = true },
- preventDefault: function() { this.returnValue = false },
- inspect: function() { return "[object Event]" }
- });
-
- return function(event) {
- if (!event) return false;
- if (event._extendedByPrototype) return event;
-
- event._extendedByPrototype = Prototype.emptyFunction;
- var pointer = Event.pointer(event);
- Object.extend(event, {
- target: event.srcElement,
- relatedTarget: Event.relatedTarget(event),
- pageX: pointer.x,
- pageY: pointer.y
- });
- return Object.extend(event, methods);
- };
-
- } else {
- Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
- Object.extend(Event.prototype, methods);
- return Prototype.K;
- }
-})();
-
-Object.extend(Event, (function() {
- var cache = Event.cache;
-
- function getEventID(element) {
- if (element._prototypeEventID) return element._prototypeEventID[0];
- arguments.callee.id = arguments.callee.id || 1;
- return element._prototypeEventID = [++arguments.callee.id];
- }
-
- function getDOMEventName(eventName) {
- if (eventName && eventName.include(':')) return "dataavailable";
- return eventName;
- }
-
- function getCacheForID(id) {
- return cache[id] = cache[id] || { };
- }
-
- function getWrappersForEventName(id, eventName) {
- var c = getCacheForID(id);
- return c[eventName] = c[eventName] || [];
- }
-
- function createWrapper(element, eventName, handler) {
- var id = getEventID(element);
- var c = getWrappersForEventName(id, eventName);
- if (c.pluck("handler").include(handler)) return false;
-
- var wrapper = function(event) {
- if (!Event || !Event.extend ||
- (event.eventName && event.eventName != eventName))
- return false;
-
- Event.extend(event);
- handler.call(element, event);
- };
-
- wrapper.handler = handler;
- c.push(wrapper);
- return wrapper;
- }
-
- function findWrapper(id, eventName, handler) {
- var c = getWrappersForEventName(id, eventName);
- return c.find(function(wrapper) { return wrapper.handler == handler });
- }
-
- function destroyWrapper(id, eventName, handler) {
- var c = getCacheForID(id);
- if (!c[eventName]) return false;
- c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
- }
-
- function destroyCache() {
- for (var id in cache)
- for (var eventName in cache[id])
- cache[id][eventName] = null;
- }
-
- if (window.attachEvent) {
- window.attachEvent("onunload", destroyCache);
- }
-
- return {
- observe: function(element, eventName, handler) {
- element = $(element);
- var name = getDOMEventName(eventName);
-
- var wrapper = createWrapper(element, eventName, handler);
- if (!wrapper) return element;
-
- if (element.addEventListener) {
- element.addEventListener(name, wrapper, false);
- } else {
- element.attachEvent("on" + name, wrapper);
- }
-
- return element;
- },
-
- stopObserving: function(element, eventName, handler) {
- element = $(element);
- var id = getEventID(element), name = getDOMEventName(eventName);
-
- if (!handler && eventName) {
- getWrappersForEventName(id, eventName).each(function(wrapper) {
- element.stopObserving(eventName, wrapper.handler);
- });
- return element;
-
- } else if (!eventName) {
- Object.keys(getCacheForID(id)).each(function(eventName) {
- element.stopObserving(eventName);
- });
- return element;
- }
-
- var wrapper = findWrapper(id, eventName, handler);
- if (!wrapper) return element;
-
- if (element.removeEventListener) {
- element.removeEventListener(name, wrapper, false);
- } else {
- element.detachEvent("on" + name, wrapper);
- }
-
- destroyWrapper(id, eventName, handler);
-
- return element;
- },
-
- fire: function(element, eventName, memo) {
- element = $(element);
- if (element == document && document.createEvent && !element.dispatchEvent)
- element = document.documentElement;
-
- var event;
- if (document.createEvent) {
- event = document.createEvent("HTMLEvents");
- event.initEvent("dataavailable", true, true);
- } else {
- event = document.createEventObject();
- event.eventType = "ondataavailable";
- }
-
- event.eventName = eventName;
- event.memo = memo || { };
-
- if (document.createEvent) {
- element.dispatchEvent(event);
- } else {
- element.fireEvent(event.eventType, event);
- }
-
- return Event.extend(event);
- }
- };
-})());
-
-Object.extend(Event, Event.Methods);
-
-Element.addMethods({
- fire: Event.fire,
- observe: Event.observe,
- stopObserving: Event.stopObserving
-});
-
-Object.extend(document, {
- fire: Element.Methods.fire.methodize(),
- observe: Element.Methods.observe.methodize(),
- stopObserving: Element.Methods.stopObserving.methodize(),
- loaded: false
-});
-
-(function() {
- /* Support for the DOMContentLoaded event is based on work by Dan Webb,
- Matthias Miller, Dean Edwards and John Resig. */
-
- var timer;
-
- function fireContentLoadedEvent() {
- if (document.loaded) return;
- if (timer) window.clearInterval(timer);
- document.fire("dom:loaded");
- document.loaded = true;
- }
-
- if (document.addEventListener) {
- if (Prototype.Browser.WebKit) {
- timer = window.setInterval(function() {
- if (/loaded|complete/.test(document.readyState))
- fireContentLoadedEvent();
- }, 0);
-
- Event.observe(window, "load", fireContentLoadedEvent);
-
- } else {
- document.addEventListener("DOMContentLoaded",
- fireContentLoadedEvent, false);
- }
-
- } else {
- document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
- $("__onDOMContentLoaded").onreadystatechange = function() {
- if (this.readyState == "complete") {
- this.onreadystatechange = null;
- fireContentLoadedEvent();
- }
- };
- }
-})();
-/*------------------------------- DEPRECATED -------------------------------*/
-
-Hash.toQueryString = Object.toQueryString;
-
-var Toggle = { display: Element.toggle };
-
-Element.Methods.childOf = Element.Methods.descendantOf;
-
-var Insertion = {
- Before: function(element, content) {
- return Element.insert(element, {before:content});
- },
-
- Top: function(element, content) {
- return Element.insert(element, {top:content});
- },
-
- Bottom: function(element, content) {
- return Element.insert(element, {bottom:content});
- },
-
- After: function(element, content) {
- return Element.insert(element, {after:content});
- }
-};
-
-var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
-
-// This should be moved to script.aculo.us; notice the deprecated methods
-// further below, that map to the newer Element methods.
-var Position = {
- // set to true if needed, warning: firefox performance problems
- // NOT neeeded for page scrolling, only if draggable contained in
- // scrollable elements
- includeScrollOffsets: false,
-
- // must be called before calling withinIncludingScrolloffset, every time the
- // page is scrolled
- prepare: function() {
- this.deltaX = window.pageXOffset
- || document.documentElement.scrollLeft
- || document.body.scrollLeft
- || 0;
- this.deltaY = window.pageYOffset
- || document.documentElement.scrollTop
- || document.body.scrollTop
- || 0;
- },
-
- // caches x/y coordinate pair to use with overlap
- within: function(element, x, y) {
- if (this.includeScrollOffsets)
- return this.withinIncludingScrolloffsets(element, x, y);
- this.xcomp = x;
- this.ycomp = y;
- this.offset = Element.cumulativeOffset(element);
-
- return (y >= this.offset[1] &&
- y < this.offset[1] + element.offsetHeight &&
- x >= this.offset[0] &&
- x < this.offset[0] + element.offsetWidth);
- },
-
- withinIncludingScrolloffsets: function(element, x, y) {
- var offsetcache = Element.cumulativeScrollOffset(element);
-
- this.xcomp = x + offsetcache[0] - this.deltaX;
- this.ycomp = y + offsetcache[1] - this.deltaY;
- this.offset = Element.cumulativeOffset(element);
-
- return (this.ycomp >= this.offset[1] &&
- this.ycomp < this.offset[1] + element.offsetHeight &&
- this.xcomp >= this.offset[0] &&
- this.xcomp < this.offset[0] + element.offsetWidth);
- },
-
- // within must be called directly before
- overlap: function(mode, element) {
- if (!mode) return 0;
- if (mode == 'vertical')
- return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
- element.offsetHeight;
- if (mode == 'horizontal')
- return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
- element.offsetWidth;
- },
-
- // Deprecation layer -- use newer Element methods now (1.5.2).
-
- cumulativeOffset: Element.Methods.cumulativeOffset,
-
- positionedOffset: Element.Methods.positionedOffset,
-
- absolutize: function(element) {
- Position.prepare();
- return Element.absolutize(element);
- },
-
- relativize: function(element) {
- Position.prepare();
- return Element.relativize(element);
- },
-
- realOffset: Element.Methods.cumulativeScrollOffset,
-
- offsetParent: Element.Methods.getOffsetParent,
-
- page: Element.Methods.viewportOffset,
-
- clone: function(source, target, options) {
- options = options || { };
- return Element.clonePosition(target, source, options);
- }
-};
-
-/*--------------------------------------------------------------------------*/
-
-if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
- function iter(name) {
- return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
- }
-
- instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
- function(element, className) {
- className = className.toString().strip();
- var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
- return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
- } : function(element, className) {
- className = className.toString().strip();
- var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
- if (!classNames && !className) return elements;
-
- var nodes = $(element).getElementsByTagName('*');
- className = ' ' + className + ' ';
-
- for (var i = 0, child, cn; child = nodes[i]; i++) {
- if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
- (classNames && classNames.all(function(name) {
- return !name.toString().blank() && cn.include(' ' + name + ' ');
- }))))
- elements.push(Element.extend(child));
- }
- return elements;
- };
-
- return function(className, parentElement) {
- return $(parentElement || document.body).getElementsByClassName(className);
- };
-}(Element.Methods);
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
- initialize: function(element) {
- this.element = $(element);
- },
-
- _each: function(iterator) {
- this.element.className.split(/\s+/).select(function(name) {
- return name.length > 0;
- })._each(iterator);
- },
-
- set: function(className) {
- this.element.className = className;
- },
-
- add: function(classNameToAdd) {
- if (this.include(classNameToAdd)) return;
- this.set($A(this).concat(classNameToAdd).join(' '));
- },
-
- remove: function(classNameToRemove) {
- if (!this.include(classNameToRemove)) return;
- this.set($A(this).without(classNameToRemove).join(' '));
- },
-
- toString: function() {
- return $A(this).join(' ');
- }
-};
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-
-/*--------------------------------------------------------------------------*/
-
-Element.addMethods();
+
--- a/labs/index.php
+++ b/labs/index.php
@@ -6,13 +6,22 @@
<li data-role="list-divider" > Experimental Features </li>
<li><a href="mywaybalance.php"><h3>MyWay Balance for mobile</h3>
<p>Mobile viewer for MyWay balance. Warning! No HTTPS security.</p></a></li>
- <li><a href="networkstats.php"><h3>Route Statistics</h3>
- <p>Analysis of route timing points</p></a></li>
<li><a href="busstopdensity.php"><h3>Bus Stop Density Map</h3>
<p>Analysis of bus stop coverage</p></a></li>
<li><a href="stopBrowser.php"><h3>Bus Stop Browser Map</h3>
<p>Bus stop location/route browser</p></a></li>
- <li>More coming soon!</li>
+ </ul>
+ <ul data-role="listview" data-theme="e" data-groupingtheme="e">
+
+ <li data-role="list-divider" > MyWay Timeliness Graphs </li>
+ <li><a href="myway_timeliness.php"><h3>Timeliness over Day</h3>
+ <p>Displays the deviation from the timetable over the day</p></a></li>
+ <li><a href="myway_timeliness_freqdist.php"><h3>Frequency Distribution of Time Deviation</h3>
+ <p>Displays spread of time deviations</p></a></li>
+ <li><a href="myway_timeliness_route.php"><h3>Timeliness over Route</h3>
+ <p>Displays the deviation from timetable as a specific route progresses</p></a></li>
+ <li><a href="myway_timeliness_stop.php"><h3>Timeliness at Stop</h3>
+ <p>Displays the deviation from the timetable at a specific stop</p></a></li>
</ul>
</div>
<?php
--- a/labs/myway_timeliness.php
+++ b/labs/myway_timeliness.php
@@ -6,17 +6,16 @@
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
- <div id="placeholder" style="width:800px;height:600px"></div>
+ <center><div id="placeholder" style="width:900px;height:550px"></div></center>
<script type="text/javascript">
$(function () {
var d = new Date();
d.setUTCMinutes(0);
d.setUTCHours(0);
var midnight = d.getTime();
- var d1 = [];
+
<?php
-//$query = "select * from myway_timingdeltas order by time";
-$query = "select * from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by time;";
+$query = "select * from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by route_full_name;";
$query = $conn->prepare($query);
$query->execute();
if (!$query) {
@@ -24,39 +23,34 @@
return Array();
}
$i = 0;
+$labels = Array();
+$lastRoute = "";
foreach ($query->fetchAll() as $delta) {
- echo "d1.push([ midnight+ (1000*" . midnight_seconds(strtotime($delta['time'])) . "), {$delta['timing_delta']}]); \n";
- $i++;
+ $routeName = $delta['route_full_name'];
+ if (strstr($routeName, " 3")) $routeName = "312-319";
+ else $routeName = preg_replace('/\D/', '', $routeName);
+ if ($routeName != $lastRoute) {
+ $i++;
+ echo " var d$i = [];";
+ $lastRoute = $routeName;
+ $labels[$i] = $routeName;
+ }
+ echo "d$i.push([ midnight+ (1000*" . midnight_seconds(strtotime($delta['time'])) . "), ".intval($delta['timing_delta'])."]); \n";
};
?>
- var d2 = [];
-<?php
-//$query = "select * from myway_timingdeltas order by route_full_name";
-$query = "select * from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by route_full_name";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-$i = 0;
-foreach ($query->fetchAll() as $delta) {
- // echo "d2.push([$i, {$delta['timing_delta']}]); \n";
- $i++;
-};
-?>
var placeholder = $("#placeholder");
var plot = $.plot(placeholder, [
- {
- data: d1,
- points: { show: true }
- },
- {
- data: d2,
- points: { show: true }
- },
+<?php
+foreach ($labels as $key => $label) {
+ echo " {
+ data: d$key,
+ points: { show: true },
+ label: '$label'
+ },";
+}
+?>
],
{
xaxis: {
@@ -67,17 +61,18 @@
yaxis: {
tickFormatter: yformatter
},
- grid: { hoverable: true, clickable: true },
+ grid: { hoverable: true, clickable: true, labelMargin: 32 },
});
var o;
o = plot.pointOffset({ x: midnight+ (9*60*60*1000), y: -1.2});
placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">9am</div>');
- o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
+ o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">4pm</div>');
});
function yformatter(v) {
- return Math.floor(v/60) + " minutes " + (v == 0 ? "" : (v >0 ? "early":"late"))
+ if (Math.floor(v/60) < -9) return "";
+ return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
}
function showTooltip(x, y, contents) {
$('<div id="tooltip">' + contents + '</div>').css( {
@@ -111,7 +106,7 @@
showTooltip(item.pageX, item.pageY,
- item.series.label + " of " + x + " "+ time +" = " + y +" ( "+ y/60+" minutes )");
+ item.series.label + " at "+ time +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
}
}
else {
--- a/labs/myway_timeliness_calculate.php
+++ b/labs/myway_timeliness_calculate.php
@@ -1,6 +1,8 @@
<?php
include ('../include/common.inc.php');
include_header("MyWay Delta Calculate", "mywayDeltaCalc");
+flush();
+ob_flush();
function abssort($a, $b)
{
if ($a['timeDiff'] == $b['timeDiff']) {
@@ -40,8 +42,10 @@
echo "error, route '{$obsv['myway_route']}' unknown";
continue;
}
- // :convert timestamp into time of day and date
+ // convert timestamp into time of day and date
+// timezones from http://www.postgresql.org/docs/8.0/static/datetime-keywords.html
$time = date("H:i:s", strtotime($obsv['time']));
+ $time_tz = date("H:i:s", strtotime($obsv['time']))." AESST";
$search_time = date("H:i:s", strtotime($obsv['time'])-(30*60)); // 30 minutes margin
$date = date("c", strtotime($obsv['time']));
$timing_period = service_period(strtotime($date));
@@ -87,7 +91,8 @@
//work out time delta, put into array with index of delta
$timeDeltas[] = Array(
"timeDiff" => $timeDiff,
- "stop_code" => $potentialStop['stop_code']
+ "stop_code" => $potentialStop['stop_code'],
+ "stop_sequence" => $timedTrip['stop_sequence']
);
echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_code']} (#{$potentialStop['stop_id']}, sequence #{$trip['stop_sequence']})<br>";
echo "Arriving at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>";
@@ -101,6 +106,8 @@
//print out that stops/does not stop
echo "No matching routes found at {$potentialStop['stop_code']}<br>";
var_dump($stopRoutes);
+ flush();
+
}
}
// lowest delta is recorded delta
@@ -110,24 +117,25 @@
echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>";
$observation_id = $obsv['observation_id'];
$route_full_name = $obsv['route_full_name'];
- $myway_route = $obsv['myway_stop'];
$stop_code = $timeDeltas[0]["stop_code"];
- $stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, myway_route, stop_code, timing_delta, time, date, timing_period)
- values (:observation_id, :route_full_name, :myway_route, :stop_code, :timing_delta, :time, :date, :timing_period)");
+ $stop_sequence = $timeDeltas[0]["stop_sequence"];
+ $stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, stop_code, timing_delta, time, date, timing_period, stop_sequence)
+ values (:observation_id, :route_full_name, :stop_code, :timing_delta, :time, :date, :timing_period, :stop_sequence)");
$stmt->bindParam(':observation_id', $observation_id);
$stmt->bindParam(':route_full_name', $route_full_name);
- $stmt->bindParam(':myway_route', $myway_route);
$stmt->bindParam(':stop_code', $stop_code);
$stmt->bindParam(':timing_delta', $lowestDelta);
- $stmt->bindParam(':time', $time);
+ $stmt->bindParam(':time', $time_tz);
$stmt->bindParam(':date', $date);
$stmt->bindParam(':timing_period', $timing_period);
+ $stmt->bindParam(':stop_sequence', $stop_sequence);
// insert a record
$stmt->execute();
if ($stmt->rowCount() > 0) {
echo "Recorded.<br>";
}
var_dump($conn->errorInfo());
+ flush();
}
flush();
}
--- /dev/null
+++ b/labs/myway_timeliness_freqdist.php
@@ -1,1 +1,45 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
+ <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
+
+ <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
+ <center><div id="placeholder" style="width:900px;height:550px"></div></center>
+<script type="text/javascript">
+$(function () {
+
+ var d1 = [];
+<?php
+$query = "select td, count(*) from (select (timing_delta - MOD(timing_delta,10)) as td from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)) as a group by td order by td";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+
+foreach ($query->fetchAll() as $delta) {
+
+ echo "d1.push([ ".intval($delta['td']).", ".intval($delta['count'])."]); \n";
+};
+?>
+
+ var placeholder = $("#placeholder");
+
+ var plot = $.plot(placeholder, [
+ {
+ data: d1,
+ bars: { show: true }
+ },
+ ],
+ {
+
+ grid: { hoverable: true, clickable: true, labelMargin: 17 },
+ });
+
+ });
+
+
+</script>
--- /dev/null
+++ b/labs/myway_timeliness_overview.php
@@ -1,1 +1,97 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
+<table>
+ <tr><td></td><td>Mean</td><td>Standard<br>Deviation</td><td>Sample Size</td></tr>
+<th> Overall </th>
+<?php
+$query = "select '', avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas ";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+
+<th> Hour of Day </th>
+<?php
+$query = "select extract(hour from time), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by extract(hour from time) order by extract(hour from time)";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+
+<th> Day of Week </th>
+<?php
+$query = "select to_char(date, 'Day'), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by to_char(date, 'Day') order by to_char(date, 'Day')";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+<th>Month </th>
+<?php
+$query = "select to_char(date, 'Month'), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by to_char(date, 'Month') order by to_char(date, 'Month')";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+
+<th>Stop </th>
+<?php
+$query = "select myway_stop, avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas INNER JOIN myway_observations
+ON myway_observations.observation_id=myway_timingdeltas.observation_id group by myway_stop having count(*) > 1 order by myway_stop";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+<th>Route </th>
+<?php
+$query = "select route_full_name, avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by route_full_name having count(*) > 1 order by route_full_name";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $row) {
+ echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
+};
+?>
+
+
+</table>
+
+<?php
+include_footer();
+?>
+
--- a/labs/myway_timeliness_reconcile.php
+++ b/labs/myway_timeliness_reconcile.php
@@ -7,8 +7,8 @@
$query = "update myway_routes set route_full_name = :route_full_name where myway_route = :myway_route";
debug($query, "database");
$query = $conn->prepare($query);
- $query->bindParam(":myway_route", $myway_route);
- $query->bindParam(":route_full_name", $route_full_name);
+ $query->bindParam(":myway_route", $myway_route,PDO::PARAM_STR, 5);
+ $query->bindParam(":route_full_name", $route_full_name,PDO::PARAM_STR, 42);
$query->execute();
die(print_r($conn->errorInfo() , true));
}
@@ -19,8 +19,8 @@
$query = "update myway_stops set stop_code = :stop_code, stop_street = :stop_street where myway_stop = :myway_stop";
debug($query, "database");
$query = $conn->prepare($query);
- $query->bindParam(":myway_stop", $myway_stop);
- $query->bindParam(":stop_code", $stop_code);
+ $query->bindParam(":myway_stop", $myway_stop, PDO::PARAM_STR, 25);
+ $query->bindParam(":stop_code", $stop_code, PDO::PARAM_STR, 32);
$query->bindParam(":stop_street", $stop_street);
$query->execute();
die(print_r($conn->errorInfo() , true));
--- /dev/null
+++ b/labs/myway_timeliness_route.json.php
@@ -1,1 +1,25 @@
-
+<?php
+include ('../include/common.inc.php');
+header('Content-Type: text/javascript; charset=utf8');
+// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
+header('Access-Control-Max-Age: 3628800');
+header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
+?>
+{
+ "label": "<?php echo $_REQUEST['routeid']; ?>",
+ "data": <?php
+ $query = "select * from myway_timingdeltas where route_full_name = :route_full_name AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by stop_sequence;";
+$query = $conn->prepare($query);
+$query->bindParam(':route_full_name', $_REQUEST['routeid'],PDO::PARAM_STR, 42);
+
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $delta) {
+ $points[] = "[{$delta['stop_sequence']}, {$delta['timing_delta']}]";
+};
+echo "[".implode(",",$points)."]";
+?>
+}
--- /dev/null
+++ b/labs/myway_timeliness_route.php
@@ -1,1 +1,125 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
+ <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
+
+ <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
+ <form method="get" action="">
+ <select id="routeid" name="routeid">
+<?php
+$query = "select distinct route_full_name from myway_routes where myway_route != '' order by route_full_name";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $route) {
+ echo "<option value=\"{$route['route_full_name']}\">{$route['route_full_name']}</option>";
+
+};
+?> </select>
+ <center><div id="placeholder" style="width:900px;height:550px"></div></center>
+<script type="text/javascript">
+$(function () {
+
+ var placeholder = $("#placeholder");
+ var data = [];
+ var options = {
+ xaxis: {
+ },
+ yaxis: {
+ tickFormatter: yformatter
+ },
+ grid: { hoverable: true, clickable: true, labelMargin: 32 },
+series: {
+ lines: { show: false },
+ points: { show: true }
+ }
+ };
+
+ var plot = $.plot(placeholder, data, options);
+
+// fetch one series, adding to what we got
+ var alreadyFetched = {};
+
+ $("#routeid").change(function () {
+ var select = $(this);
+
+ // find the URL in the link right next to us
+ // var dataurl = button.siblings('a').attr('href');
+ var dataurl = "myway_timeliness_route.json.php?routeid=" + select.val();
+ // then fetch the data with jQuery
+ function onDataReceived(series) {
+ // extract the first coordinate pair so you can see that
+ // data is now an ordinary Javascript object
+ var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
+
+
+ // let's add it to our current data
+ if (!alreadyFetched[series.label]) {
+ alreadyFetched[series.label] = true;
+ data.push(series);
+ }
+
+ // and plot all we got
+ $.plot(placeholder, data, options);
+ }
+
+ $.ajax({
+ url: dataurl,
+ method: 'GET',
+ dataType: 'json',
+ success: onDataReceived
+ });
+ });
+
+
+ });
+
+
+
+function yformatter(v) {
+ if (Math.floor(v/60) < -9) return "";
+ return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
+}
+ function showTooltip(x, y, contents) {
+ $('<div id="tooltip">' + contents + '</div>').css( {
+ position: 'absolute',
+ display: 'none',
+ top: y + 5,
+ left: x + 5,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.80
+ }).appendTo("body").fadeIn(200);
+ }
+
+ var previousPoint = null;
+ $("#placeholder").bind("plothover", function (event, pos, item) {
+ $("#x").text(pos.x.toFixed(2));
+ $("#y").text(pos.y.toFixed(2));
+
+ if (item) {
+ if (previousPoint != item.dataIndex) {
+ previousPoint = item.dataIndex;
+
+ $("#tooltip").remove();
+ var x = item.datapoint[0],
+ y = item.datapoint[1].toFixed(2);
+
+ showTooltip(item.pageX, item.pageY,
+ item.series.label + " at stop_sequence "+ x +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
+ }
+ }
+ else {
+ $("#tooltip").remove();
+ previousPoint = null;
+ }
+ });
+
+</script>
+
--- /dev/null
+++ b/labs/myway_timeliness_stop.json.php
@@ -1,1 +1,32 @@
+<?php
+include ('../include/common.inc.php');
+header('Content-Type: text/javascript; charset=utf8');
+// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
+header('Access-Control-Max-Age: 3628800');
+header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
+?>
+{
+ "label": "<?php echo $_REQUEST['stopid']; ?>",
+ "data": <?php
+ $query = "select * from myway_timingdeltas INNER JOIN myway_observations
+ON myway_observations.observation_id=myway_timingdeltas.observation_id
+ where myway_stop = :myway_stop
+ AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)
+ order by myway_timingdeltas.time;";
+$query = $conn->prepare($query);
+$query->bindParam(':myway_stop', $_REQUEST['stopid'],PDO::PARAM_STR, 42);
+
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $delta) {
+ $points[] = "[".((strtotime("00:00Z") + midnight_seconds(strtotime($delta['time'])))*1000).", {$delta['timing_delta']}]";
+};
+if (count($points) == 0) {
+ echo "[]"; }
+ else echo "[".implode(",",$points)."]";
+?>
+}
--- /dev/null
+++ b/labs/myway_timeliness_stop.php
@@ -1,1 +1,136 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
+ <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
+
+ <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
+ <form method="get" action="">
+ <select id="stopid" name="stopid">
+<?php
+$query = "select distinct myway_stop from myway_stops where myway_stop != '' order by myway_stop";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+}
+foreach ($query->fetchAll() as $stop) {
+ echo "<option value=\"{$stop['myway_stop']}\">{$stop['myway_stop']}</option>";
+
+};
+?> </select> <center><div id="placeholder" style="width:900px;height:550px"></div></center>
+<script type="text/javascript">
+$(function () {
+ var d = new Date();
+ d.setUTCMinutes(0);
+ d.setUTCHours(0);
+ var midnight = d.getTime();
+
+ var placeholder = $("#placeholder");
+ var data = [];
+ var options = {
+ xaxis: {
+ mode: "time",
+ min: midnight + (1000*60*60*8),
+ max: midnight + (1000*60*60*23.5)
+ },
+ yaxis: {
+ tickFormatter: yformatter
+ },
+ grid: { hoverable: true, clickable: true, labelMargin: 32 },
+ series: {
+ lines: { show: false },
+ points: { show: true }
+ }
+ };
+
+ var plot = $.plot(placeholder, data, options);
+ var o;
+ o = plot.pointOffset({ x: midnight+ (9*60*60*1000), y: -1.2});
+ placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">9am</div>');
+ o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
+ placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">4pm</div>');
+// fetch one series, adding to what we got
+ var alreadyFetched = {};
+
+ $("#stopid").change(function () {
+ var select = $(this);
+
+ // find the URL in the link right next to us
+ // var dataurl = button.siblings('a').attr('href');
+ var dataurl = "myway_timeliness_stop.json.php?stopid=" + select.val();
+ // then fetch the data with jQuery
+ function onDataReceived(series) {
+ // extract the first coordinate pair so you can see that
+ // data is now an ordinary Javascript object
+ var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
+
+
+ // let's add it to our current data
+ if (!alreadyFetched[series.label]) {
+ alreadyFetched[series.label] = true;
+ data.push(series);
+ }
+
+ // and plot all we got
+ $.plot(placeholder, data, options);
+ }
+
+ $.ajax({
+ url: dataurl,
+ method: 'GET',
+ dataType: 'json',
+ success: onDataReceived
+ });
+ });
+
+ });
+function yformatter(v) {
+ if (Math.floor(v/60) < -9) return "";
+ return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
+}
+ function showTooltip(x, y, contents) {
+ $('<div id="tooltip">' + contents + '</div>').css( {
+ position: 'absolute',
+ display: 'none',
+ top: y + 5,
+ left: x + 5,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.80
+ }).appendTo("body").fadeIn(200);
+ }
+
+ var previousPoint = null;
+ $("#placeholder").bind("plothover", function (event, pos, item) {
+ $("#x").text(pos.x.toFixed(2));
+ $("#y").text(pos.y.toFixed(2));
+
+ if (item) {
+ if (previousPoint != item.dataIndex) {
+ previousPoint = item.dataIndex;
+
+ $("#tooltip").remove();
+ var x = item.datapoint[0].toFixed(2),
+ y = item.datapoint[1].toFixed(2);
+
+ var d = new Date();
+d.setTime(x);
+var time = d.getUTCHours() +':'+ (d.getUTCMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getUTCMinutes())
+
+
+ showTooltip(item.pageX, item.pageY,
+ item.series.label + " at "+ time +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
+ }
+ }
+ else {
+ $("#tooltip").remove();
+ previousPoint = null;
+ }
+ });
+
+</script>
+
--- a/labs/mywaybalance.php
+++ b/labs/mywaybalance.php
@@ -111,7 +111,11 @@
</div>
<div data-role="fieldcontain">
<label for="contribute_myway">Contribute MyWay records to timeliness study? </label>
- <input type="checkbox" name="contribute_myway" id="contribute_myway" checked="no" />
+ <input type="checkbox" name="contribute_myway" id="contribute_myway" defaultChecked="no" />
+ </div>
+ <div data-role="fieldcontain">
+ <label for="accept_warning">I accept that Transport for Canberra <a href="http://transport.act.gov.au/myway/protect.html">advise against the use of third party MyWay applications</a> </label>
+ <input type="checkbox" name="accept_warning" id="accept_warning" defaultChecked="no" />
</div>
<input type="submit" value="Go!"></form>';
}
--- a/labs/networkstats.php
+++ /dev/null
@@ -1,147 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("Route Statistics", "networkstats")
-?>
-<script type="text/javascript" src="../js/flotr/lib/prototype-1.6.0.2.js"></script>
- <!--[if IE]>
-
- <script type="text/javascript" src="../js/flotr/lib/excanvas.js"></script>
-
- <script type="text/javascript" src="../js/flotr/lib/base64.js"></script>
-
- <![endif]-->
-
- <script type="text/javascript" src="../js/flotr/lib/canvas2image.js"></script>
-
- <script type="text/javascript" src="../js/flotr/lib/canvastext.js"></script>
-
- <script type="text/javascript" src="../js/flotr/flotr.debug-0.2.0-alpha_radar1.js"></script>
- <form method="get" action="networkstats.php">
- <select id="routeid" name="routeid">
- <?php
- foreach (getRoutes() as $route) {
- echo "<option value=\"{$route['route_id']}\">{$route['route_short_name']} {$route['route_long_name']}</option>";
- }
- ?>
- </select>
- <input type="submit" value="View"/>
- </form>
-
-<?php
-// middle of graph = 6am
-$adjustFactor = 0;
-$route = getRoute($routeid);
-echo "<h1>{$route['route_short_name']} {$route['route_long_name']}</h1>";
-foreach (getRouteTrips($routeid) as $key => $trip) {
- $dLabel[$key] = $trip['arrival_time'];
- if ($key == 0) {
- $time = strtotime($trip['arrival_time']);
- $adjustFactor = (date("G", $time) * 3600);
- }
- $tripStops = viaPoints($trip['trip_id']);
- foreach ($tripStops as $i => $stop) {
- if ($key == 0) {
- $dTicks[$i] = $stop['stop_name'];
- }
- $time = strtotime($stop['arrival_time']);
- $d[$key][$i] = (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time) - $adjustFactor;
-
- }
-}
-
-?>
-<div id="container" style="width:100%;height:900px;"></div>
-<script type="text/javascript">
-
- /**
-
- * Wait till dom's finished loading.
-
- */
-
- document.observe('dom:loaded', function(){
-
- /**
-
- * Fill series d1 and d2.
-
- */
-<?php
-foreach ($d as $key => $dataseries) {
-
- echo "var d$key =[";
- foreach ($dataseries as $i => $datapoint) {
- echo "[$i, $datapoint],";
- }
- echo "];\n";
-}
-
-?>
-
-
-
- var f = Flotr.draw($('container'),
-
- [
- <?php
-foreach ($d as $key => $dataseries) {
-
- echo '{data:d'.$key.", label:'{$dLabel[$key]}'".', radar:{fill:false}},'."\n";
-
-}
-
-?>
- ],
-
- {defaultType: 'radar',
-
- radarChartMode: true,
-
- HtmlText: false,
-
- fontSize: 9,
-
- xaxis:{
-
- ticks: [
- <?php
-foreach ($dTicks as $key => $tickName) {
- echo '['.$key.', "'.$tickName.'"],';
-}
-
-?>
-
- ]},
-
- mouse:{ // Setup point tracking
-
- track: true,
-
- lineColor: 'black',
-
- relative: true,
-
- sensibility: 70,
-
- trackFormatter: function(obj){
- var d = new Date();
- d.setMinutes(0);
- d.setHours(0);
-d.setTime(d.getTime() + Math.floor(obj.radarData*1000) + <?php echo $adjustFactor*1000 ?>);
-return d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getMinutes());
-}}});
-
- });
-
- </script>
-
- </div>
-
-
-
-<?php
-include_footer()
-?>
-
-
--- /dev/null
+++ b/labs/travelAllRoutes.php
@@ -1,1 +1,23 @@
+<?php
+include ('../include/common.inc.php');
+ $query = "Select route_short_name,max(route_id) as route_id from routes where route_short_name NOT LIKE '7__' AND route_short_name != '170' AND route_short_name NOT LIKE '9__' group by route_short_name order by route_short_name ;";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->execute();
+echo "<table><tr><th>Route Number</th><th>First Trip Start</th><th>First Trip End</th><th>Length</th>";
+$total = 0;
+$count = 0;
+foreach($query->fetchAll() as $r) {
+ $trips = getRouteTrips($r['route_id']);
+ $startTime = $trips[0]['arrival_time'];
+ $endTime = getTripEndTime($trips[0]['trip_id']);
+ $timeDiff = strtotime($endTime) - strtotime($startTime);
+ $total += $timeDiff;
+ $count ++;
+ echo "<tr><td>{$r['route_short_name']}</td><td>$startTime</td><td>$endTime</td><td>$timeDiff seconds ie. ". ($timeDiff/60). " minutes</td></tr>";
+}
+echo "</table>";
+echo "Total time: $total seconds ie. " .($total/60/60). " hours<br>";
+echo "$count Routes";
+?>
--- a/routeList.php
+++ b/routeList.php
@@ -44,7 +44,7 @@
include_header("Routes Nearby", "routeList", true, true);
trackEvent("Route Lists", "Routes Nearby", $_SESSION['lat'] . "," . $_SESSION['lon']);
navbar();
- timePlaceSettings(true);
+ placeSettings();
if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
include_footer();
die();
--- a/servicealerts_api.php
+++ b/servicealerts_api.php
@@ -17,7 +17,7 @@
$return['header']['timestamp'] = time();
$return['entities'] = Array();
foreach(getCurrentAlerts() as $alert) {
- $informedEntities = getInformedAlerts($alert['id'],$filter_class,$filter_id);
+ $informedEntities = getInformedAlerts($alert['id'],$_REQUEST['filter_class'],$_REQUEST['filter_id']);
if (sizeof($informedEntities) >0) {
$entity = Array();
$entity['id'] = $alert['id'];
@@ -36,7 +36,7 @@
$return['entities'][] = $entity;
}
}
-//header('Content-Type: text/javascript; charset=utf8');
+header('Content-Type: text/javascript; charset=utf8');
// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
header('Access-Control-Max-Age: 3628800');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
--- a/sitemap.xml.php
+++ b/sitemap.xml.php
@@ -3,10 +3,13 @@
$last_updated = date('Y-m-d',@filemtime('cbrfeed.zip'));
header("Content-Type: text/xml");
echo "<?xml version='1.0' encoding='UTF-8'?>";
- echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
+ echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:geo="http://www.google.com/geo/schemas/sitemap/1.0">' . "\n";
echo " <url><loc>".curPageURL()."index.php</loc><priority>1.0</priority></url>\n";
foreach (scandir("./") as $file) {
if (strpos($file,".php") !== false && $file != "index.php" && $file != "sitemap.xml.php") echo " <url><loc>".curPageURL()."$file</loc><priority>0.3</priority></url>\n";
+}
+foreach (scandir("./labs") as $file) {
+ if (strpos($file,".php") !== false) echo " <url><loc>".curPageURL()."/labs/$file</loc><priority>0.3</priority></url>\n";
}
foreach (getStops() as $stop) {
echo " <url><loc>".curPageURL()."stop.php?stopid=".htmlspecialchars ($stop["stop_id"])."</loc>";
--- a/stop.php
+++ b/stop.php
@@ -12,6 +12,7 @@
// expand out to all platforms
}*/
+
$stops = Array();
$stopPositions = Array();
$stopNames = Array();
@@ -60,8 +61,14 @@
}
}
include_header($stop['stop_name'], "stop");
+
+/*$serviceAlerts = json_decode(getPage(curPageURL() . "/servicealerts_api.php?filter_class=stop&filter_id=".$stopid) , true);
+
+foreach($serviceAlerts['entities'] as $serviceAlert) {
+ echo '<div id="servicewarning">'.$serviceAlert['alert']['description']['translation'].'</div>';
+}*/
+
echo '<span class="content-secondary">';
-timePlaceSettings();
echo $stopLinks;
if (sizeof($stops) > 0) {
trackEvent("View Stops", "View Combined Stops", $stop["stop_name"], $stop["stop_id"]);
@@ -76,6 +83,31 @@
)
)) ;
}
+
+// time settings
+echo '<div id="settings" data-role="collapsible" data-collapsed="true">
+<h3>Change Time (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
+ <form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post">
+ <div class="ui-body">
+ <div data-role="fieldcontain">
+ <label for="time"> Time: </label>
+ <input type="time" name="time" id="time" value="' . (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:i")) . '"/>
+ <a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getMinutes()));" . '">Current Time?</a>
+ </div>
+ <div data-role="fieldcontain">
+ <label for="service_period"> Service Period: </label>
+ <select name="service_period" id="service_period">';
+ foreach ($service_periods as $service_period) {
+ echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';
+ }
+ echo '</select>
+ <a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>
+ </div>
+
+ <input type="submit" value="Update"/>
+ </div></form>
+ </div>';
+
echo '</span><span class="content-primary">';
echo ' <ul data-role="listview" data-inset="true">';
if (sizeof($allStopsTrips) > 0) {
--- a/stopList.php
+++ b/stopList.php
@@ -40,7 +40,6 @@
$stops = getStops();
include_header("All Stops", "stopList");
navbar();
- timePlaceSettings();
}
else if (isset($nearby)) {
$listType = 'nearby=yes';
@@ -48,7 +47,7 @@
trackEvent("Stop Lists", "Stops Nearby", $_SESSION['lat'] . "," . $_SESSION['lon']);
navbar();
if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
- timePlaceSettings(true);
+ placeSettings();
include_footer();
die();
}
@@ -65,7 +64,7 @@
);
}
echo staticmap($stopPositions, 0, "iconb", true, true);
- timePlaceSettings(true);
+ placeSettings();
echo '</span><span class="content-primary">';
}
else if (isset($suburb)) {
@@ -78,7 +77,6 @@
$stops = getStops(true, $firstLetter);
include_header("Timing Points / Major Stops", "stopList");
navbar();
- timePlaceSettings();
}
echo ' <ul data-role="listview" data-filter="true" data-inset="true" >';
if (!isset($firstLetter) && !isset($suburb) && !isset($nearby)) {
--- a/updatedb.php
+++ b/updatedb.php
@@ -1,6 +1,10 @@
<?php
+if ( php_sapi_name() == "cli") {
include ('include/common.inc.php');
$conn = pg_connect("dbname=transitdata user=postgres password=snmc host=localhost") or die('connection failed');
+$pdconn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost");
+
+
// Unzip cbrfeed.zip, import all csv files to database
$unzip = true;
$zip = zip_open(dirname(__FILE__) . "/cbrfeed.zip");
@@ -30,8 +34,18 @@
echo "Opening $file \n";
$line = 0;
$handle = fopen($tmpdir . $file, "r");
+ if ($tablename =="stop_times") {
+ $stmt = $pdconn->prepare("insert into stop_times (trip_id,stop_id,stop_sequence) values(:trip_id, :stop_id, :stop_sequence);");
+ $stmt->bindParam(':trip_id',$trip_id);
+ $stmt->bindParam(':stop_id',$stop_id);
+ $stmt->bindParam(':stop_sequence',$stop_sequence);
+ }
+
+
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
- if ($line > 0) {
+ if ($line == 0) {
+
+ } else {
$query = "insert into $tablename values(";
$valueCount = 0;
foreach ($data as $value) {
@@ -43,19 +57,28 @@
} else {
$query.= "');";
}
- if ($tablename =="stop_times" && $data[1] == "") {
- $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
- }
+ if ($tablename =="stop_times" && $data[1] == "") {
+ // $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
+ $trip_id=$data[0];
+ $stop_id=$data[3];
+ $stop_sequence=$data[4];
+ }
}
- $result = pg_query($conn, $query);
+ if ($tablename =="stop_times") {
+ $stmt->execute();
+ }
+ else {
+ $result = pg_query($conn, $query);
+ }
$line++;
- if ($line % 10000 == 0) echo "$line records... \n";
+ if ($line % 10000 == 0) echo "$line records... ".date('c')."\n";
}
fclose($handle);
echo "Found a total of $line records in $file.\n";
}
}
+}
?>