commit a7d9b0886554f93ee5be12a77e7a9ca98b528599 Author: Russ Date: Mon Mar 30 16:59:19 2015 -0400 Initial Github commit diff --git a/README b/README new file mode 100644 index 0000000..b54d84a --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +This was created with the purpose of parsing raw traffic data from an Arbor Peakflow device on a secondary server. + +The "webdata" directory contents should be somewhere publicly accessible via a browser. + +The "backgroundscripts" directory contents can be anywhere, and the "backgroundscripts/cronscript.sh" should be set to run at a 10 minute interval via cron. + +Obviously, proper API keys and passwords should be substituted in wherever needed in the various files, as well as proper IP addresses. diff --git a/backgroundscripts/cronscript.sh b/backgroundscripts/cronscript.sh new file mode 100644 index 0000000..ac166de --- /dev/null +++ b/backgroundscripts/cronscript.sh @@ -0,0 +1,21 @@ +#!/bin/bash +#set variable for script location +scriptloc=/home/arborscripts +#Check for stop file +if [ -e /home/arborscripts/stop ]; then + +#Send admin an email if stopped +SUBJECT="Arbor Cron Stopped" +EMAIL="dev@null.com" +EMAILMESSAGE="/home/arborscripts/email.txt" +/bin/mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE + +else + +#pull data +curl -k https://127.0.0.1/arborws/traffic -d api_key=APIKEY --data-urlencode query@$scriptloc/pullreq.xml > $scriptloc/report.xml + +mysql -u USER --password="PASSWORD" -e "LOAD XML LOCAL INFILE '$scriptloc/report.xml' INTO TABLE DATABASE.rawdata ROWS IDENTIFIED BY '';" + +mysql -u USER --password="PASSWORD" -e "DELETE FROM DATABASE.rawdata WHERE time < (UNIX_TIMESTAMP() - 604800);" +fi diff --git a/backgroundscripts/email.txt b/backgroundscripts/email.txt new file mode 100644 index 0000000..a2f5222 --- /dev/null +++ b/backgroundscripts/email.txt @@ -0,0 +1 @@ +Someone has stopped the cron. diff --git a/backgroundscripts/geodbdownload.sh b/backgroundscripts/geodbdownload.sh new file mode 100644 index 0000000..9166af7 --- /dev/null +++ b/backgroundscripts/geodbdownload.sh @@ -0,0 +1,11 @@ +#!/bin/bash +if [ `date +%d` -gt 7 ] ; then + exit +else +wget -P /home/srv/html/netdata/mapping/ http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz + +gunzip -c /home/srv/html/netdata/mapping/GeoLiteCity.dat.gz > /home/srv/html/netdata/mapping/GeoLiteCity.dat + +rm -f /home/srv/html/netdata/mapping/GeoLiteCity.dat.gz + +fi diff --git a/backgroundscripts/pullreq.xml b/backgroundscripts/pullreq.xml new file mode 100644 index 0000000..c74a409 --- /dev/null +++ b/backgroundscripts/pullreq.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/backgroundscripts/stats/stat15.sh b/backgroundscripts/stats/stat15.sh new file mode 100755 index 0000000..9560418 --- /dev/null +++ b/backgroundscripts/stats/stat15.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for each in $(mysql -u USERNAME --password='PASSWORD' --skip-column-names -se "select port from DATABASE.commonports;") + +do + +quantity=$(mysql -u USERNAME --password='PASSWORD' -se "SELECT COUNT(*) FROM DATABASE.rawdata WHERE dst_port = $each AND time > (UNIX_TIMESTAMP() - 900);"|tail -n1) + +mysql -u USERNAME --password="PASSWORD" -e "INSERT INTO DATABASE.stats (type, amount, service) VALUES('15min', $quantity, $each);" + +done diff --git a/backgroundscripts/stats/stat30.sh b/backgroundscripts/stats/stat30.sh new file mode 100755 index 0000000..70d9c55 --- /dev/null +++ b/backgroundscripts/stats/stat30.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for each in $(mysql -u USERNAME --password='PASSWORD' --skip-column-names -se "select port from DATABASE.commonports;") + +do + +quantity=$(mysql -u USERNAME --password='PASSWORD' -se "SELECT COUNT(*) FROM DATABASE.rawdata WHERE dst_port = $each AND time > (UNIX_TIMESTAMP() - 1800);"|tail -n1) + +mysql -u USERNAME --password="PASSWORD" -e "INSERT INTO DATABASE.stats (type, amount, service) VALUES('30min', $quantity, $each);" + +done diff --git a/backgroundscripts/stats/statdaily.sh b/backgroundscripts/stats/statdaily.sh new file mode 100755 index 0000000..831c648 --- /dev/null +++ b/backgroundscripts/stats/statdaily.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for each in $(mysql -u USERNAME --password='PASSWORD' --skip-column-names -se "select port from DATABASE.commonports;") + +do + +quantity=$(mysql -u USERNAME --password='PASSWORD' -se "SELECT COUNT(*) FROM DATABASE.rawdata WHERE dst_port = $each;"|tail -n1) + +mysql -u USERNAME --password="PASSWORD" -e "INSERT INTO DATABASE.stats (type, amount, service) VALUES('daily', $quantity, $each);" + +done diff --git a/backgroundscripts/stats/stathourly.sh b/backgroundscripts/stats/stathourly.sh new file mode 100755 index 0000000..e264075 --- /dev/null +++ b/backgroundscripts/stats/stathourly.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for each in $(mysql -u USERNAME --password='PASSWORD' --skip-column-names -se "select port from DATABASE.commonports;") + +do + +quantity=$(mysql -u USERNAME --password='PASSWORD' -se "SELECT COUNT(*) FROM DATABASE.rawdata WHERE dst_port = $each AND time > (UNIX_TIMESTAMP() - 3600);"|tail -n1) + +mysql -u USERNAME --password="PASSWORD" -e "INSERT INTO DATABASE.stats (type, amount, service) VALUES('hourly', $quantity, $each);" + +done diff --git a/webdata/css/menu.css b/webdata/css/menu.css new file mode 100644 index 0000000..6b10ac4 --- /dev/null +++ b/webdata/css/menu.css @@ -0,0 +1,61 @@ +nav ul ul { + display: none; +} + +nav ul li:hover > ul { + display: block; +} +nav ul { + color: #000000; + background: #808080; + background: linear-gradient(top, #808080 0%, #404040 100%); + background: -moz-linear-gradient(top, #808080 0%, #404040 100%); + background: -webkit-linear-gradient(top, #808080 0%,#404040 100%); + box-shadow: 0px 0px 9px rgba(0,0,0,0.15); + padding: 0 10px; + border-radius: 10px; + list-style: none; + position: relative; + display: inline-table; +/* margin: 0.5em;*/ +} +nav ul:after { + content: ""; clear: both; display: block; +} +nav ul li { + float: left; +} +nav ul li:hover { + background: #505050; + background: linear-gradient(top, #505050 0%, #585858 40%); + background: -moz-linear-gradient(top, #505050 0%, #585858 40%); + background: -webkit-linear-gradient(top, #505050 0%, #585858 40%); +} +nav ul li:hover a { + color: #fff; +} + +nav ul li a { + display: block; padding: 10px 10px; + color: #FFFFFF; text-decoration: none; +} +nav ul ul { + background: #505050; border-radius: 0px; padding: 0; + position: absolute; top: 100%; +} +nav ul ul li { + float: none; + border-top: 1px solid #000000; + border-bottom: 1px solid #000000; + position: relative; +} +nav ul ul li a { + padding: 5px 20px; + color: #fff; +} +nav ul ul li a:hover { + background: #585858; +} +nav ul ul ul { + position: absolute; left: 100%; top:0; +} diff --git a/webdata/css/style.css b/webdata/css/style.css new file mode 100644 index 0000000..7ed7f5b --- /dev/null +++ b/webdata/css/style.css @@ -0,0 +1,116 @@ +body { + background-color: #E0E0E0; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; + text-align: center; +} + +.header { + background-color: #313338; + color: white; + width: 100%; +} +.header h1 { + color: #F8F8F8; + text-align: center; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; + margin: 0.2em; +} +.header h2, .header h3 { + color: #F8F8F8; +} +.whois { + text-align: left; + margin: 0 auto; + width: 50em; + background: white; + word-wrap: break-word; +} +.footer { + text-align: center; + font-weight:normal; + color:black; + background: none; + width: auto; + text-transform: none; + margin: 0px; + padding: 3px; + font-size: 50%; +} +#map_canvas { + height: 100%; + z-index: 0; + text-align: center; + margin: 0 auto; + width: 95%; + } +#map_canvas_sm { + height: 50%; + z-index: 0; + text-align: center; + margin: 0 auto; + width: 50%; + } + +.footer a, .footer a:link, .footer a:visited { + text-align: center; + font-weight:normal; + color:black; + background: none; + width: auto; + text-decoration: underline; + text-transform: none; + margin: 0px; + padding: 3px; + font-size: 50%; +} +h3, h4, h5 { + color: black; + text-align: center; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; +} +table, th, td { + border: 1px solid black; + text-align: center; + border-collapse: collapse; + padding: 3px; + width: auto; +} +th { + background-color: #3366CC; + color: #F8F8F8; + font-weight: normal; +} +tr:nth-child(odd) { + background-color: white; +} +tr:nth-child(even) { + background-color: lightgray; +} +td a, td a:link, td a:visited { + font-weight:normal; + color:black; + background: none; + width: auto; + text-decoration: underline; + text-transform: none; + margin: 0px; + padding: 3px; +} +th a, th a:link, th a:visited { + font-weight:normal; + color:white; + background: none; + width: auto; + text-decoration: underline; + text-transform: none; + margin: 0px; + padding: 3px; +} +#col1 { + width: 40%; + float: left; +} +#col2 { + width: 60%; + float: left; +} diff --git a/webdata/css/wallboardstyle.css b/webdata/css/wallboardstyle.css new file mode 100644 index 0000000..c6734bd --- /dev/null +++ b/webdata/css/wallboardstyle.css @@ -0,0 +1,86 @@ +body { + background-color: #282828; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; + text-align: center; + color: white; +} + +.header { + background-color: #313338; + color: white; + width: 100%; +} +.header h1 { + color: #F8F8F8; + text-align: center; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; +} +.footer { + text-align: center; + font-weight:normal; + color:black; + background: none; + width: auto; + text-transform: none; + margin: 0px; + padding: 3px; + font-size: 50%; +} +#map_canvas { + height: 90%; + z-index: 0; + text-align: center; + margin: 0 auto; + width: 65%; + } + +.footer a, .footer a:link, .footer a:visited { + text-align: center; + font-weight:normal; + color:black; + background: none; + width: auto; + text-decoration: underline; + text-transform: none; + margin: 0px; + padding: 3px; + font-size: 50%; +} +h3, h4, h5 { + color: black; + text-align: center; + font-family: 'Source Sans Pro', 'Segoe UI', 'Droid Sans', Tahoma, Arial, sans-serif; +} +ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + display: inline-block; +} +li { + display: inline; + float: left; +} +a:link, a:visited { + display: block; + font-weight: normal; + color: white; + background-color: #606060; + text-align: center; + padding: 4px; + margin: 4px; + text-decoration: none; +} + +a:hover, a:active { + background-color: #989898; +} +#col1 { + width: 50%; + float: left; +} +#col2 { + width: 50%; + float: left; +} diff --git a/webdata/destinationips.php b/webdata/destinationips.php new file mode 100644 index 0000000..996e5fb --- /dev/null +++ b/webdata/destinationips.php @@ -0,0 +1,98 @@ + + + + + Traffic Destinations + + +
+

LiquidWeb Traffic Monitoring

+

Destination IPs by Source

+ +
+
+

Data displayed here is from the last 7 days, and is updated every 5 minutes.

+ + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +
+

+ + Please enter the IP address for which you wish to search: +
+ +
+ For which service would you like to see data? +
+ +
+ +

+
+ + connect_error) { + die("Connection Failed: " . $conn2->connect_error); + } + + //Query + + $sql = "SELECT src_ip, dst_ip FROM `rawdata` WHERE `src_ip` = '".$varIP."' AND `dst_port` = '".$varPort."' GROUP BY dst_ip ORDER BY dst_ip;"; + + $result = $conn2->query($sql); + //If there are results of the query, display them. + if ($result->num_rows >0) { + echo "Now viewing data for Destination Port: $varPort"; + echo ""; + + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
Source IP: $varIP Whois
Destination IPsNetblock
".$row["dst_ip"]."Netblock
"; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
+ + diff --git a/webdata/favicon.ico b/webdata/favicon.ico new file mode 100644 index 0000000..602488b Binary files /dev/null and b/webdata/favicon.ico differ diff --git a/webdata/graph/15min12hr.php b/webdata/graph/15min12hr.php new file mode 100644 index 0000000..178c91c --- /dev/null +++ b/webdata/graph/15min12hr.php @@ -0,0 +1,72 @@ + DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 12 HOUR) ORDER BY time"; //table name +$Result = mysql_query($Requete, $db); + +/*This fetches the data from the mysql database, and adds it to pchart as points*/ +while($row = mysql_fetch_array($Result)) +{ + //$Sample_Number = $row["Sample_Number"]; //Not using this data + //$myData->addPoints($Sample_Number,"Sample_Number"); + + $Time = $row["time"]; + $myData->addPoints($Time,"time"); + + $Amt = $row["amount"]; + $myData->addPoints($Amt,"amount"); + + // $Type = $row["type"]; + // $myData->addPoints($Type,"type"); +} + +$myData-> setSerieOnAxis("amount", 0); //assigns the data to the frist axis +$myData-> setAxisName(0, "# of Connections"); //adds the label to the first axis + +//$myData-> setSerieOnAxis("type", 1); +//$myData-> setAxisName(1, "Service"); + +$myData-> setAxisPosition(1,AXIS_POSITION_LEFT); //moves the second axis to the far left + +$myData->setAbscissa("time"); //sets the time data set as the x axis label + +$myPicture = new pImage(950,320,$myData); /* Create a pChart object and associate your dataset */ +$rectsettings = array("R"=>224, "G"=>224, "B"=>224, "Dash"=>1, "DashR"=>200, "DashG"=>200, "DashB"=>200); +$myPicture->drawFilledRectangle(0,0,950,320,$rectsettings); +$myPicture->setFontProperties(array("FontName"=>"pchart/fonts/verdana.ttf","FontSize"=>8)); /* Choose a nice font */ + +$myPicture->setGraphArea(75,20,850,200); /* Define the boundaries of the graph area */ + +$Settings = array("R"=>250, "G"=>250, "B"=>250, "Dash"=>1, "DashR"=>0, "DashG"=>0, "DashB"=>0); + +$myPicture->drawScale(array("LabelRotation"=>300)); /* Draw the scale, keep everything automatic */ +$myPicture->drawFilledRectangle(75,20,850,200,array("R"=>46,"G"=>46,"B"=>46, "Surrounding"=>-200,"Alpha"=>10)); + +/*The combination makes a cool looking graph*/ +$myPicture->drawPlotChart(); +$myPicture->drawLineChart(); + + +//$myPicture->drawLegend(90,20); //adds the legend + +$myPicture->autoOutput(); /* Build the PNG file and send it to the web browser */ + +?> diff --git a/webdata/graph/30min24hr.php b/webdata/graph/30min24hr.php new file mode 100644 index 0000000..4374de4 --- /dev/null +++ b/webdata/graph/30min24hr.php @@ -0,0 +1,71 @@ + DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 24 HOUR) ORDER BY time"; //table name +$Result = mysql_query($Requete, $db); + +/*This fetches the data from the mysql database, and adds it to pchart as points*/ +while($row = mysql_fetch_array($Result)) +{ + //$Sample_Number = $row["Sample_Number"]; //Not using this data + //$myData->addPoints($Sample_Number,"Sample_Number"); + + $Time = $row["time"]; + $myData->addPoints($Time,"time"); + + $Amt = $row["amount"]; + $myData->addPoints($Amt,"amount"); + + // $Type = $row["type"]; + // $myData->addPoints($Type,"type"); +} + +$myData-> setSerieOnAxis("amount", 0); //assigns the data to the frist axis +$myData-> setAxisName(0, "# of Connections"); //adds the label to the first axis + +//$myData-> setSerieOnAxis("type", 1); +//$myData-> setAxisName(1, "Service"); + +$myData-> setAxisPosition(1,AXIS_POSITION_LEFT); //moves the second axis to the far left + +$myData->setAbscissa("time"); //sets the time data set as the x axis label + + +$myPicture = new pImage(950,320,$myData); /* Create a pChart object and associate your dataset */ +$rectsettings = array("R"=>224, "G"=>224, "B"=>224, "Dash"=>1, "DashR"=>200, "DashG"=>200, "DashB"=>200); +$myPicture->drawFilledRectangle(0,0,950,320,$rectsettings); +$myPicture->setFontProperties(array("FontName"=>"pchart/fonts/verdana.ttf","FontSize"=>8)); /* Choose a nice font */ + +$myPicture->setGraphArea(75,20,850,200); /* Define the boundaries of the graph area */ + +$Settings = array("R"=>250, "G"=>250, "B"=>250, "Dash"=>1, "DashR"=>0, "DashG"=>0, "DashB"=>0); + +$myPicture->drawScale(array("LabelRotation"=>300)); /* Draw the scale, keep everything automatic */ +$myPicture->drawFilledRectangle(75,20,850,200,array("R"=>46,"G"=>46,"B"=>46,"Surrounding"=>-200,"Alpha"=>10)); +/*The combination makes a cool looking graph*/ +$myPicture->drawPlotChart(); +$myPicture->drawLineChart(); + + +//$myPicture->drawLegend(90,20); //adds the legend + +$myPicture->autoOutput(); /* Build the PNG file and send it to the web browser */ + +?> diff --git a/webdata/graph/60min48hr.php b/webdata/graph/60min48hr.php new file mode 100644 index 0000000..149ab60 --- /dev/null +++ b/webdata/graph/60min48hr.php @@ -0,0 +1,71 @@ + DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 48 HOUR) ORDER BY time"; //table name +$Result = mysql_query($Requete, $db); + +/*This fetches the data from the mysql database, and adds it to pchart as points*/ +while($row = mysql_fetch_array($Result)) +{ + //$Sample_Number = $row["Sample_Number"]; //Not using this data + //$myData->addPoints($Sample_Number,"Sample_Number"); + + $Time = $row["time"]; + $myData->addPoints($Time,"time"); + + $Amt = $row["amount"]; + $myData->addPoints($Amt,"amount"); + + // $Type = $row["type"]; + // $myData->addPoints($Type,"type"); +} + +$myData-> setSerieOnAxis("amount", 0); //assigns the data to the frist axis +$myData-> setAxisName(0, "# of Connections"); //adds the label to the first axis + +//$myData-> setSerieOnAxis("type", 1); +//$myData-> setAxisName(1, "Service"); + +$myData-> setAxisPosition(1,AXIS_POSITION_LEFT); //moves the second axis to the far left + +$myData->setAbscissa("time"); //sets the time data set as the x axis label + + +$myPicture = new pImage(950,320,$myData); /* Create a pChart object and associate your dataset */ +$rectsettings = array("R"=>224, "G"=>224, "B"=>224, "Dash"=>1, "DashR"=>200, "DashG"=>200, "DashB"=>200); +$myPicture->drawFilledRectangle(0,0,950,320,$rectsettings); +$myPicture->setFontProperties(array("FontName"=>"pchart/fonts/verdana.ttf","FontSize"=>8)); /* Choose a nice font */ + +$myPicture->setGraphArea(75,20,850,200); /* Define the boundaries of the graph area */ + +$Settings = array("R"=>250, "G"=>250, "B"=>250, "Dash"=>1, "DashR"=>0, "DashG"=>0, "DashB"=>0); + +$myPicture->drawScale(array("LabelRotation"=>300)); /* Draw the scale, keep everything automatic */ +$myPicture->drawFilledRectangle(75,20,850,200,array("R"=>46,"G"=>46,"B"=>46,"Surrounding"=>-200,"Alpha"=>10)); +/*The combination makes a cool looking graph*/ +$myPicture->drawPlotChart(); +$myPicture->drawLineChart(); + + +//$myPicture->drawLegend(90,20); //adds the legend + +$myPicture->autoOutput(); /* Build the PNG file and send it to the web browser */ + +?> diff --git a/webdata/graph/daily30day.php b/webdata/graph/daily30day.php new file mode 100644 index 0000000..c88b5f6 --- /dev/null +++ b/webdata/graph/daily30day.php @@ -0,0 +1,72 @@ + DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 710 HOUR) ORDER BY time"; //table name +$Result = mysql_query($Requete, $db); + +/*This fetches the data from the mysql database, and adds it to pchart as points*/ +while($row = mysql_fetch_array($Result)) +{ + //$Sample_Number = $row["Sample_Number"]; //Not using this data + //$myData->addPoints($Sample_Number,"Sample_Number"); + + $Time = $row["time"]; + $myData->addPoints($Time,"time"); + + $Amt = $row["amount"]; + $myData->addPoints($Amt,"amount"); + + // $Type = $row["type"]; + // $myData->addPoints($Type,"type"); +} + +$myData-> setSerieOnAxis("amount", 0); //assigns the data to the frist axis +$myData-> setAxisName(0, "# of Connections"); //adds the label to the first axis + +//$myData-> setSerieOnAxis("type", 1); +//$myData-> setAxisName(1, "Service"); + +$myData-> setAxisPosition(1,AXIS_POSITION_LEFT); //moves the second axis to the far left + +$myData->setAbscissa("time"); //sets the time data set as the x axis label + + +$myPicture = new pImage(950,320,$myData); /* Create a pChart object and associate your dataset */ +$rectsettings = array("R"=>224, "G"=>224, "B"=>224, "Dash"=>1, "DashR"=>200, "DashG"=>200, "DashB"=>200); +$myPicture->drawFilledRectangle(0,0,950,320,$rectsettings); +$myPicture->setFontProperties(array("FontName"=>"pchart/fonts/verdana.ttf","FontSize"=>8)); /* Choose a nice font */ + +$myPicture->setGraphArea(75,20,850,200); /* Define the boundaries of the graph area */ + +$Settings = array("R"=>250, "G"=>250, "B"=>250, "Dash"=>1, "DashR"=>0, "DashG"=>0, "DashB"=>0); + +$myPicture->drawScale(array("LabelRotation"=>300)); /* Draw the scale, keep everything automatic */ +$myPicture->drawFilledRectangle(75,20,850,200,array("R"=>46,"G"=>46,"B"=>46,"Surrounding"=>-200,"Alpha"=>10)); +/*The combination makes a cool looking graph*/ +$myPicture->drawPlotChart(); +$myPicture->drawLineChart(); + + +//$myPicture->drawLegend(90,20); //adds the legend + +$myPicture->autoOutput(); /* Build the PNG file and send it to the web browser */ + +?> diff --git a/webdata/graph/pchart/GPLv3.txt b/webdata/graph/pchart/GPLv3.txt new file mode 100644 index 0000000..f2d137d --- /dev/null +++ b/webdata/graph/pchart/GPLv3.txt @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/webdata/graph/pchart/change.log b/webdata/graph/pchart/change.log new file mode 100644 index 0000000..5fa1f2b Binary files /dev/null and b/webdata/graph/pchart/change.log differ diff --git a/webdata/graph/pchart/class/pBarcode128.class.php b/webdata/graph/pchart/class/pBarcode128.class.php new file mode 100644 index 0000000..d1c29cc --- /dev/null +++ b/webdata/graph/pchart/class/pBarcode128.class.php @@ -0,0 +1,184 @@ +Codes = ""; + $this->Reverse = ""; + + $FileHandle = @fopen($BasePath."data/128B.db", "r"); + + if (!$FileHandle) { die("Cannot find barcode database (".$BasePath."128B.db)."); } + + while (!feof($FileHandle)) + { + $Buffer = fgets($FileHandle,4096); + $Buffer = str_replace(chr(10),"",$Buffer); + $Buffer = str_replace(chr(13),"",$Buffer); + $Values = preg_split("/;/",$Buffer); + + $this->Codes[$Values[1]]["ID"] = $Values[0]; + $this->Codes[$Values[1]]["Code"] = $Values[2]; + $this->Reverse[$Values[0]]["Code"] = $Values[2]; + $this->Reverse[$Values[0]]["Asc"] = $Values[1]; + } + fclose($FileHandle); + } + + /* Return the projected size of a barcode */ + function getSize($TextString,$Format="") + { + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : FALSE; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : FALSE; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : 12; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + + $TextString = $this->encode128($TextString); + $BarcodeLength = strlen($this->Result); + + if ( $DrawArea ) { $WOffset = 20; } else { $WOffset = 0; } + if ( $ShowLegend ) { $HOffset = $FontSize+$LegendOffset+$WOffset; } else { $HOffset = 0; } + + $X1 = cos($Angle * PI / 180) * ($WOffset+$BarcodeLength); + $Y1 = sin($Angle * PI / 180) * ($WOffset+$BarcodeLength); + + $X2 = $X1 + cos(($Angle+90) * PI / 180) * ($HOffset+$Height); + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * ($HOffset+$Height); + + + $AreaWidth = max(abs($X1),abs($X2)); + $AreaHeight = max(abs($Y1),abs($Y2)); + + return(array("Width"=>$AreaWidth,"Height"=>$AreaHeight)); + } + + function encode128($Value,$Format="") + { + $this->Result = "11010010000"; + $this->CRC = 104; + $TextString = ""; + + for($i=1;$i<=strlen($Value);$i++) + { + $CharCode = ord($this->mid($Value,$i,1)); + if ( isset($this->Codes[$CharCode]) ) + { + $this->Result = $this->Result.$this->Codes[$CharCode]["Code"]; + $this->CRC = $this->CRC + $i*$this->Codes[$CharCode]["ID"]; + $TextString = $TextString.chr($CharCode); + } + } + $this->CRC = $this->CRC - floor($this->CRC/103)*103; + + $this->Result = $this->Result.$this->Reverse[$this->CRC]["Code"]; + $this->Result = $this->Result."1100011101011"; + + return($TextString); + } + + /* Create the encoded string */ + function draw($Object,$Value,$X,$Y,$Format="") + { + $this->pChartObject = $Object; + + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : FALSE; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : FALSE; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 255; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 255; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 255; + $AreaBorderR = isset($Format["AreaBorderR"]) ? $Format["AreaBorderR"] : $AreaR; + $AreaBorderG = isset($Format["AreaBorderG"]) ? $Format["AreaBorderG"] : $AreaG; + $AreaBorderB = isset($Format["AreaBorderB"]) ? $Format["AreaBorderB"] : $AreaB; + + $TextString = $this->encode128($Value); + + if ( $DrawArea ) + { + $X1 = $X + cos(($Angle-135) * PI / 180) * 10; + $Y1 = $Y + sin(($Angle-135) * PI / 180) * 10; + + $X2 = $X1 + cos($Angle * PI / 180) * (strlen($this->Result)+20); + $Y2 = $Y1 + sin($Angle * PI / 180) * (strlen($this->Result)+20); + + if ( $ShowLegend ) + { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + } + else + { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+20); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+20); + } + + $X4 = $X3 + cos(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + $Y4 = $Y3 + sin(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + + $Polygon = array($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4); + $Settings = array("R"=>$AreaR,"G"=>$AreaG,"B"=>$AreaB,"BorderR"=>$AreaBorderR,"BorderG"=>$AreaBorderG,"BorderB"=>$AreaBorderB); + $this->pChartObject->drawPolygon($Polygon,$Settings); + } + + for($i=1;$i<=strlen($this->Result);$i++) + { + if ( $this->mid($this->Result,$i,1) == 1 ) + { + $X1 = $X + cos($Angle * PI / 180) * $i; + $Y1 = $Y + sin($Angle * PI / 180) * $i; + $X2 = $X1 + cos(($Angle+90) * PI / 180) * $Height; + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * $Height; + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y2,$Settings); + } + } + + if ( $ShowLegend ) + { + $X1 = $X + cos($Angle * PI / 180) * (strlen($this->Result)/2); + $Y1 = $Y + sin($Angle * PI / 180) * (strlen($this->Result)/2); + + $LegendX = $X1 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + $LegendY = $Y1 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Angle"=>-$Angle,"Align"=>TEXT_ALIGN_TOPMIDDLE); + $this->pChartObject->drawText($LegendX,$LegendY,$TextString,$Settings); + } + } + + function left($value,$NbChar) { return substr($value,0,$NbChar); } + function right($value,$NbChar) { return substr($value,strlen($value)-$NbChar,$NbChar); } + function mid($value,$Depart,$NbChar) { return substr($value,$Depart-1,$NbChar); } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pBarcode39.class.php b/webdata/graph/pchart/class/pBarcode39.class.php new file mode 100644 index 0000000..fd73c0e --- /dev/null +++ b/webdata/graph/pchart/class/pBarcode39.class.php @@ -0,0 +1,200 @@ +MOD43 = $EnableMOD43; + $this->Codes = ""; + $this->Reverse = ""; + + $FileHandle = @fopen($BasePath."data/39.db", "r"); + + if (!$FileHandle) { die("Cannot find barcode database (".$BasePath."data/39.db)."); } + + while (!feof($FileHandle)) + { + $Buffer = fgets($FileHandle,4096); + $Buffer = str_replace(chr(10),"",$Buffer); + $Buffer = str_replace(chr(13),"",$Buffer); + $Values = preg_split("/;/",$Buffer); + + $this->Codes[$Values[0]] = $Values[1]; + } + fclose($FileHandle); + } + + /* Return the projected size of a barcode */ + function getSize($TextString,$Format="") + { + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : FALSE; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : FALSE; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : 12; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + + $TextString = $this->encode39($TextString); + $BarcodeLength = strlen($this->Result); + + if ( $DrawArea ) { $WOffset = 20; } else { $WOffset = 0; } + if ( $ShowLegend ) { $HOffset = $FontSize+$LegendOffset+$WOffset; } else { $HOffset = 0; } + + $X1 = cos($Angle * PI / 180) * ($WOffset+$BarcodeLength); + $Y1 = sin($Angle * PI / 180) * ($WOffset+$BarcodeLength); + + $X2 = $X1 + cos(($Angle+90) * PI / 180) * ($HOffset+$Height); + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * ($HOffset+$Height); + + + $AreaWidth = max(abs($X1),abs($X2)); + $AreaHeight = max(abs($Y1),abs($Y2)); + + return(array("Width"=>$AreaWidth,"Height"=>$AreaHeight)); + } + + /* Create the encoded string */ + function encode39($Value) + { + $this->Result = "100101101101"."0"; + $TextString = ""; + for($i=1;$i<=strlen($Value);$i++) + { + $CharCode = ord($this->mid($Value,$i,1)); + if ( $CharCode >= 97 && $CharCode <= 122 ) { $CharCode = $CharCode - 32; } + + if ( isset($this->Codes[chr($CharCode)]) ) + { + $this->Result = $this->Result.$this->Codes[chr($CharCode)]."0"; + $TextString = $TextString.chr($CharCode); + } + } + + if ( $this->MOD43 ) + { + $Checksum = $this->checksum($TextString); + $this->Result = $this->Result.$this->Codes[$Checksum]."0"; + } + + $this->Result = $this->Result."100101101101"; + $TextString = "*".$TextString."*"; + + return($TextString); + } + + /* Create the encoded string */ + function draw($Object,$Value,$X,$Y,$Format="") + { + $this->pChartObject = $Object; + + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : FALSE; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : FALSE; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 255; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 255; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 255; + $AreaBorderR = isset($Format["AreaBorderR"]) ? $Format["AreaBorderR"] : $AreaR; + $AreaBorderG = isset($Format["AreaBorderG"]) ? $Format["AreaBorderG"] : $AreaG; + $AreaBorderB = isset($Format["AreaBorderB"]) ? $Format["AreaBorderB"] : $AreaB; + + $TextString = $this->encode39($Value); + + if ( $DrawArea ) + { + $X1 = $X + cos(($Angle-135) * PI / 180) * 10; + $Y1 = $Y + sin(($Angle-135) * PI / 180) * 10; + + $X2 = $X1 + cos($Angle * PI / 180) * (strlen($this->Result)+20); + $Y2 = $Y1 + sin($Angle * PI / 180) * (strlen($this->Result)+20); + + if ( $ShowLegend ) + { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + } + else + { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+20); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+20); + } + + $X4 = $X3 + cos(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + $Y4 = $Y3 + sin(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + + $Polygon = array($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4); + $Settings = array("R"=>$AreaR,"G"=>$AreaG,"B"=>$AreaB,"BorderR"=>$AreaBorderR,"BorderG"=>$AreaBorderG,"BorderB"=>$AreaBorderB); + $this->pChartObject->drawPolygon($Polygon,$Settings); + } + + for($i=1;$i<=strlen($this->Result);$i++) + { + if ( $this->mid($this->Result,$i,1) == 1 ) + { + $X1 = $X + cos($Angle * PI / 180) * $i; + $Y1 = $Y + sin($Angle * PI / 180) * $i; + $X2 = $X1 + cos(($Angle+90) * PI / 180) * $Height; + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * $Height; + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y2,$Settings); + } + } + + if ( $ShowLegend ) + { + $X1 = $X + cos($Angle * PI / 180) * (strlen($this->Result)/2); + $Y1 = $Y + sin($Angle * PI / 180) * (strlen($this->Result)/2); + + $LegendX = $X1 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + $LegendY = $Y1 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Angle"=>-$Angle,"Align"=>TEXT_ALIGN_TOPMIDDLE); + $this->pChartObject->drawText($LegendX,$LegendY,$TextString,$Settings); + } + } + + function checksum( $string ) + { + $checksum = 0; + $length = strlen( $string ); + $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%'; + + for( $i=0; $i < $length; ++$i ) + $checksum += strpos( $charset, $string[$i] ); + + return substr( $charset, ($checksum % 43), 1 ); + } + + function left($value,$NbChar) { return substr($value,0,$NbChar); } + function right($value,$NbChar) { return substr($value,strlen($value)-$NbChar,$NbChar); } + function mid($value,$Depart,$NbChar) { return substr($value,$Depart-1,$NbChar); } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pBubble.class.php b/webdata/graph/pchart/class/pBubble.class.php new file mode 100644 index 0000000..06aaca0 --- /dev/null +++ b/webdata/graph/pchart/class/pBubble.class.php @@ -0,0 +1,326 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /* Prepare the scale */ + function bubbleScale($DataSeries,$WeightSeries) + { + if ( !is_array($DataSeries) ) { $DataSeries = array($DataSeries); } + if ( !is_array($WeightSeries) ) { $WeightSeries = array($WeightSeries); } + + /* Parse each data series to find the new min & max boundaries to scale */ + $NewPositiveSerie = ""; $NewNegativeSerie = ""; $MaxValues = 0; $LastPositive = 0; $LastNegative = 0; + foreach($DataSeries as $Key => $SerieName) + { + $SerieWeightName = $WeightSeries[$Key]; + + $this->pDataObject->setSerieDrawable($SerieWeightName,FALSE); + + if ( count($this->pDataObject->Data["Series"][$SerieName]["Data"]) > $MaxValues ) { $MaxValues = count($this->pDataObject->Data["Series"][$SerieName]["Data"]); } + + foreach($this->pDataObject->Data["Series"][$SerieName]["Data"] as $Key => $Value) + { + if ( $Value >= 0 ) + { + $BubbleBounds = $Value + $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; + + if ( !isset($NewPositiveSerie[$Key]) ) + { $NewPositiveSerie[$Key] = $BubbleBounds; } + elseif ( $NewPositiveSerie[$Key] < $BubbleBounds ) + { $NewPositiveSerie[$Key] = $BubbleBounds; } + + $LastPositive = $BubbleBounds; + } + else + { + $BubbleBounds = $Value - $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; + + if ( !isset($NewNegativeSerie[$Key]) ) + { $NewNegativeSerie[$Key] = $BubbleBounds; } + elseif ( $NewNegativeSerie[$Key] > $BubbleBounds ) + { $NewNegativeSerie[$Key] = $BubbleBounds; } + + $LastNegative = $BubbleBounds; + } + } + } + + /* Check for missing values and all the fake positive serie */ + if ( $NewPositiveSerie != "" ) + { + for ($i=0; $i<$MaxValues; $i++) { if (!isset($NewPositiveSerie[$i])) { $NewPositiveSerie[$i] = $LastPositive; } } + + $this->pDataObject->addPoints($NewPositiveSerie,"BubbleFakePositiveSerie"); + } + + /* Check for missing values and all the fake negative serie */ + if ( $NewNegativeSerie != "" ) + { + for ($i=0; $i<$MaxValues; $i++) { if (!isset($NewNegativeSerie[$i])) { $NewNegativeSerie[$i] = $LastNegative; } } + + $this->pDataObject->addPoints($NewNegativeSerie,"BubbleFakeNegativeSerie"); + } + } + + function resetSeriesColors() + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + $ID = 0; + foreach($Data["Series"] as $SerieName => $SeriesParameters) + { + if ( $SeriesParameters["isDrawable"] ) + { + $this->pDataObject->Data["Series"][$SerieName]["Color"]["R"] = $Palette[$ID]["R"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["G"] = $Palette[$ID]["G"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["B"] = $Palette[$ID]["B"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["Alpha"] = $Palette[$ID]["Alpha"]; + $ID++; + } + } + } + + /* Prepare the scale */ + function drawBubbleChart($DataSeries,$WeightSeries,$Format="") + { + $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : VOID; + $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : TRUE; + $BorderWidth = isset($Format["BorderWidth"]) ? $Format["BorderWidth"] : 1; + $Shape = isset($Format["Shape"]) ? $Format["Shape"] : BUBBLE_SHAPE_ROUND; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + if ( !is_array($DataSeries) ) { $DataSeries = array($DataSeries); } + if ( !is_array($WeightSeries) ) { $WeightSeries = array($WeightSeries); } + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( isset($Data["Series"]["BubbleFakePositiveSerie"] ) ) { $this->pDataObject->setSerieDrawable("BubbleFakePositiveSerie",FALSE); } + if ( isset($Data["Series"]["BubbleFakeNegativeSerie"] ) ) { $this->pDataObject->setSerieDrawable("BubbleFakeNegativeSerie",FALSE); } + + $this->resetSeriesColors(); + + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + foreach($DataSeries as $Key => $SerieName) + { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Data["Series"][$SerieName]["Description"])) { $SerieDescription = $Data["Series"][$SerieName]["Description"]; } else { $SerieDescription = $SerieName; } + + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $Color = array("R"=>$Palette[$Key]["R"],"G"=>$Palette[$Key]["G"],"B"=>$Palette[$Key]["B"],"Alpha"=>$Palette[$Key]["Alpha"]); + + if ( $ForceAlpha != VOID ) { $Color["Alpha"]=$ForceAlpha; } + + if ( $DrawBorder ) + { + if ( $BorderWidth != 1 ) + { + if ( $Surrounding != NULL ) + { $BorderR = $Palette[$Key]["R"]+$Surrounding; $BorderG = $Palette[$Key]["G"]+$Surrounding; $BorderB = $Palette[$Key]["B"]+$Surrounding; } + else + { $BorderR = $BorderR; $BorderG = $BorderG; $BorderB = $BorderB; } + if ( $ForceAlpha != VOID ) { $BorderAlpha = $ForceAlpha/2; } + $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + } + else + { + $Color["BorderAlpha"] = $BorderAlpha; + + if ( $Surrounding != NULL ) + { $Color["BorderR"] = $Palette[$Key]["R"]+$Surrounding; $Color["BorderG"] = $Palette[$Key]["G"]+$Surrounding; $Color["BorderB"] = $Palette[$Key]["B"]+$Surrounding; } + else + { $Color["BorderR"] = $BorderR; $Color["BorderG"] = $BorderG; $Color["BorderB"] = $BorderB; } + if ( $ForceAlpha != VOID ) { $Color["BorderAlpha"] = $ForceAlpha/2; } + } + } + + foreach($Data["Series"][$SerieName]["Data"] as $iKey => $Point) + { + $Weight = $Point + $Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]; + + $PosArray = $this->pChartObject->scaleComputeY($Point,array("AxisID"=>$AxisID)); + $WeightArray = $this->pChartObject->scaleComputeY($Weight,array("AxisID"=>$AxisID)); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; } + $Y = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); + + if ( $Shape == BUBBLE_SHAPE_SQUARE ) + { + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$CircleRadius).",".floor($Y-$CircleRadius).",".floor($X+$CircleRadius).",".floor($Y+$CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } + + if ( $BorderWidth != 1 ) + { + $this->pChartObject->drawFilledRectangle($X-$CircleRadius-$BorderWidth,$Y-$CircleRadius-$BorderWidth,$X+$CircleRadius+$BorderWidth,$Y+$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } + else + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } + elseif ( $Shape == BUBBLE_SHAPE_ROUND ) + { + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } + + if ( $BorderWidth != 1 ) + { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + else + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + + $X = $X + $XStep; + } + elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; } + $X = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); + + if ( $Shape == BUBBLE_SHAPE_SQUARE ) + { + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$CircleRadius).",".floor($Y-$CircleRadius).",".floor($X+$CircleRadius).",".floor($Y+$CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } + + if ( $BorderWidth != 1 ) + { + $this->pChartObject->drawFilledRectangle($X-$CircleRadius-$BorderWidth,$Y-$CircleRadius-$BorderWidth,$X+$CircleRadius+$BorderWidth,$Y+$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } + else + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } + elseif ( $Shape == BUBBLE_SHAPE_ROUND ) + { + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } + + if ( $BorderWidth != 1 ) + { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + else + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + + $Y = $Y + $XStep; + } + } + } + } + + function writeBubbleLabel($SerieName,$SerieWeightName,$Points,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : NULL; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + + if ( !is_array($Points) ) { $Point = $Points; $Points = ""; $Points[] = $Point; } + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( !isset($Data["Series"][$SerieName]) || !isset($Data["Series"][$SerieWeightName]) ) + return(0); + + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $Color = array("R"=>$Data["Series"][$SerieName]["Color"]["R"],"G"=>$Data["Series"][$SerieName]["Color"]["G"],"B"=>$Data["Series"][$SerieName]["Color"]["B"],"Alpha"=>$Data["Series"][$SerieName]["Color"]["Alpha"]); + + foreach($Points as $Key => $Point) + { + $Value = $Data["Series"][$SerieName]["Data"][$Point]; + $PosArray = $this->pChartObject->scaleComputeY($Value,array("AxisID"=>$AxisID)); + + if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Point]) ) + $Abscissa = $Data["Series"][$Data["Abscissa"]]["Data"][$Point]." : "; + else + $Abscissa = ""; + + $Value = $this->pChartObject->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + $Weight = $Data["Series"][$SerieWeightName]["Data"][$Point]; + $Caption = $Abscissa.$Value." / ".$Weight; + + if ( isset($Data["Series"][$SerieName]["Description"]) ) + $Description = $Data["Series"][$SerieName]["Description"]; + else + $Description = "No description"; + + $Series = ""; + $Series[] = array("Format"=>$Color,"Caption"=>$Caption); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; } + + $X = floor($X + $Point * $XStep); + $Y = floor($PosArray); + } + else + { + if ( $XDivs == 0 ) { $YStep = 0; } else { $YStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; } + + $X = floor($PosArray); + $Y = floor($Y + $Point * $YStep); + } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) + $this->pChartObject->drawFilledCircle($X,$Y,3,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + elseif ( $DrawPoint == LABEL_POINT_BOX ) + $this->pChartObject->drawFilledRectangle($X-2,$Y-2,$X+2,$Y+2,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + + $this->pChartObject->drawLabelBox($X,$Y-3,$Description,$Series,$Format); + } + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pCache.class.php b/webdata/graph/pchart/class/pCache.class.php new file mode 100644 index 0000000..722e51b --- /dev/null +++ b/webdata/graph/pchart/class/pCache.class.php @@ -0,0 +1,280 @@ +CacheFolder = $CacheFolder; + $this->CacheIndex = $CacheIndex; + $this->CacheDB = $CacheDB; + + if (!file_exists($this->CacheFolder."/".$this->CacheIndex)) { touch($this->CacheFolder."/".$this->CacheIndex); } + if (!file_exists($this->CacheFolder."/".$this->CacheDB)) { touch($this->CacheFolder."/".$this->CacheDB); } + } + + /* Flush the cache contents */ + function flush() + { + if (file_exists($this->CacheFolder."/".$this->CacheIndex)) { unlink($this->CacheFolder."/".$this->CacheIndex); touch($this->CacheFolder."/".$this->CacheIndex); } + if (file_exists($this->CacheFolder."/".$this->CacheDB)) { unlink($this->CacheFolder."/".$this->CacheDB); touch($this->CacheFolder."/".$this->CacheDB); } + } + + /* Return the MD5 of the data array to clearly identify the chart */ + function getHash($Data,$Marker="") + { return(md5($Marker.serialize($Data->Data))); } + + /* Write the generated picture to the cache */ + function writeToCache($ID,$pChartObject) + { + /* Compute the paths */ + $TemporaryFile = $this->CacheFolder."/tmp_".rand(0,1000).".png"; + $Database = $this->CacheFolder."/".$this->CacheDB; + $Index = $this->CacheFolder."/".$this->CacheIndex; + + /* Flush the picture to a temporary file */ + imagepng($pChartObject->Picture ,$TemporaryFile); + + /* Retrieve the files size */ + $PictureSize = filesize($TemporaryFile); + $DBSize = filesize($Database); + + /* Save the index */ + $Handle = fopen($Index,"a"); + fwrite($Handle, $ID.",".$DBSize.",".$PictureSize.",".time().",0 \r\n"); + fclose($Handle); + + /* Get the picture raw contents */ + $Handle = fopen($TemporaryFile,"r"); + $Raw = fread($Handle,$PictureSize); + fclose($Handle); + + /* Save the picture in the solid database file */ + $Handle = fopen($Database,"a"); + fwrite($Handle, $Raw); + fclose($Handle); + + /* Remove temporary file */ + unlink($TemporaryFile); + } + + /* Remove object older than the specified TS */ + function removeOlderThan($Expiry) + { $this->dbRemoval(array("Expiry"=>$Expiry)); } + + /* Remove an object from the cache */ + function remove($ID) + { $this->dbRemoval(array("Name"=>$ID)); } + + /* Remove with specified criterias */ + function dbRemoval($Settings) + { + $ID = isset($Settings["Name"]) ? $Settings["Name"] : NULL; + $Expiry = isset($Settings["Expiry"]) ? $Settings["Expiry"] : -(24*60*60); + $TS = time()-$Expiry; + + /* Compute the paths */ + $Database = $this->CacheFolder."/".$this->CacheDB; + $Index = $this->CacheFolder."/".$this->CacheIndex; + $DatabaseTemp = $this->CacheFolder."/".$this->CacheDB.".tmp"; + $IndexTemp = $this->CacheFolder."/".$this->CacheIndex.".tmp"; + + /* Single file removal */ + if ( $ID != NULL ) + { + /* Retrieve object informations */ + $Object = $this->isInCache($ID,TRUE); + + /* If it's not in the cache DB, go away */ + if ( !$Object ) { return(0); } + } + + /* Create the temporary files */ + if (!file_exists($DatabaseTemp)) { touch($DatabaseTemp); } + if (!file_exists($IndexTemp)) { touch($IndexTemp); } + + /* Open the file handles */ + $IndexHandle = @fopen($Index, "r"); + $IndexTempHandle = @fopen($IndexTemp, "w"); + $DBHandle = @fopen($Database, "r"); + $DBTempHandle = @fopen($DatabaseTemp, "w"); + + /* Remove the selected ID from the database */ + while (!feof($IndexHandle)) + { + $Entry = fgets($IndexHandle, 4096); + $Entry = str_replace("\r","",$Entry); + $Entry = str_replace("\n","",$Entry); + $Settings = preg_split("/,/",$Entry); + + if ( $Entry != "" ) + { + $PicID = $Settings[0]; + $DBPos = $Settings[1]; + $PicSize = $Settings[2]; + $GeneratedTS = $Settings[3]; + $Hits = $Settings[4]; + + if ( $Settings[0] != $ID && $GeneratedTS > $TS) + { + $CurrentPos = ftell($DBTempHandle); + fwrite($IndexTempHandle, $PicID.",".$CurrentPos.",".$PicSize.",".$GeneratedTS.",".$Hits."\r\n"); + + fseek($DBHandle,$DBPos); + $Picture = fread($DBHandle,$PicSize); + fwrite($DBTempHandle,$Picture); + } + } + } + + /* Close the handles */ + fclose($IndexHandle); + fclose($IndexTempHandle); + fclose($DBHandle); + fclose($DBTempHandle); + + /* Remove the prod files */ + unlink($Database); + unlink($Index); + + /* Swap the temp & prod DB */ + rename($DatabaseTemp,$Database); + rename($IndexTemp,$Index); + } + + function isInCache($ID,$Verbose=FALSE,$UpdateHitsCount=FALSE) + { + /* Compute the paths */ + $Index = $this->CacheFolder."/".$this->CacheIndex; + + /* Search the picture in the index file */ + $Handle = @fopen($Index, "r"); + while (!feof($Handle)) + { + $IndexPos = ftell($Handle); + $Entry = fgets($Handle, 4096); + if ( $Entry != "" ) + { + $Settings = preg_split("/,/",$Entry); + $PicID = $Settings[0]; + if ( $PicID == $ID ) + { + fclose($Handle); + + $DBPos = $Settings[1]; + $PicSize = $Settings[2]; + $GeneratedTS = $Settings[3]; + $Hits = intval($Settings[4]); + + if ( $UpdateHitsCount ) + { + $Hits++; + if ( strlen($Hits) < 7 ) { $Hits = $Hits.str_repeat(" ",7-strlen($Hits)); } + + $Handle = @fopen($Index, "r+"); + fseek($Handle,$IndexPos); + fwrite($Handle, $PicID.",".$DBPos.",".$PicSize.",".$GeneratedTS.",".$Hits."\r\n"); + fclose($Handle); + } + + if ($Verbose) + { return(array("DBPos"=>$DBPos,"PicSize"=>$PicSize,"GeneratedTS"=>$GeneratedTS,"Hits"=>$Hits)); } + else + { return(TRUE); } + } + } + } + fclose($Handle); + + /* Picture isn't in the cache */ + return(FALSE); + } + + /* Automatic output method based on the calling interface */ + function autoOutput($ID,$Destination="output.png") + { + if (php_sapi_name() == "cli") + $this->saveFromCache($ID,$Destination); + else + $this->strokeFromCache($ID); + } + + function strokeFromCache($ID) + { + /* Get the raw picture from the cache */ + $Picture = $this->getFromCache($ID); + + /* Do we have a hit? */ + if ( $Picture == NULL ) { return(FALSE); } + + header('Content-type: image/png'); + echo $Picture; + + return(TRUE); + } + + function saveFromCache($ID,$Destination) + { + /* Get the raw picture from the cache */ + $Picture = $this->getFromCache($ID); + + /* Do we have a hit? */ + if ( $Picture == NULL ) { return(FALSE); } + + /* Flush the picture to a file */ + $Handle = fopen($Destination,"w"); + fwrite($Handle,$Picture); + fclose($Handle); + + /* All went fine */ + return(TRUE); + } + + function getFromCache($ID) + { + /* Compute the path */ + $Database = $this->CacheFolder."/".$this->CacheDB; + + /* Lookup for the picture in the cache */ + $CacheInfo = $this->isInCache($ID,TRUE,TRUE); + + /* Not in the cache */ + if (!$CacheInfo) { return(NULL); } + + /* Get the database extended information */ + $DBPos = $CacheInfo["DBPos"]; + $PicSize = $CacheInfo["PicSize"]; + + /* Extract the picture from the solid cache file */ + $Handle = @fopen($Database, "r"); + fseek($Handle,$DBPos); + $Picture = fread($Handle,$PicSize); + fclose($Handle); + + /* Return back the raw picture data */ + return($Picture); + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pData.class.php b/webdata/graph/pchart/class/pData.class.php new file mode 100644 index 0000000..2dfff95 --- /dev/null +++ b/webdata/graph/pchart/class/pData.class.php @@ -0,0 +1,788 @@ +array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100), + "1"=>array("R"=>224,"G"=>100,"B"=>46,"Alpha"=>100), + "2"=>array("R"=>224,"G"=>214,"B"=>46,"Alpha"=>100), + "3"=>array("R"=>46,"G"=>151,"B"=>224,"Alpha"=>100), + "4"=>array("R"=>176,"G"=>46,"B"=>224,"Alpha"=>100), + "5"=>array("R"=>224,"G"=>46,"B"=>117,"Alpha"=>100), + "6"=>array("R"=>92,"G"=>224,"B"=>46,"Alpha"=>100), + "7"=>array("R"=>224,"G"=>176,"B"=>46,"Alpha"=>100)); + + /* Class creator */ + function pData() + { + $this->Data = ""; + $this->Data["XAxisDisplay"] = AXIS_FORMAT_DEFAULT; + $this->Data["XAxisFormat"] = NULL; + $this->Data["XAxisName"] = NULL; + $this->Data["XAxisUnit"] = NULL; + $this->Data["Abscissa"] = NULL; + $this->Data["AbsicssaPosition"] = AXIS_POSITION_BOTTOM; + + $this->Data["Axis"][0]["Display"] = AXIS_FORMAT_DEFAULT; + $this->Data["Axis"][0]["Position"] = AXIS_POSITION_LEFT; + $this->Data["Axis"][0]["Identity"] = AXIS_Y; + } + + /* Add a single point or an array to the given serie */ + function addPoints($Values,$SerieName="Serie1") + { + if (!isset($this->Data["Series"][$SerieName])) + $this->initialise($SerieName); + + if ( is_array($Values) ) + { + foreach($Values as $Key => $Value) + { $this->Data["Series"][$SerieName]["Data"][] = $Value; } + } + else + $this->Data["Series"][$SerieName]["Data"][] = $Values; + + if ( $Values != VOID ) + { + $StrippedData = $this->stripVOID($this->Data["Series"][$SerieName]["Data"]); + if ( empty($StrippedData) ) { $this->Data["Series"][$SerieName]["Max"] = 0; $this->Data["Series"][$SerieName]["Min"] =0; return(0); } + $this->Data["Series"][$SerieName]["Max"] = max($StrippedData); + $this->Data["Series"][$SerieName]["Min"] = min($StrippedData); + } + } + + /* Strip VOID values */ + function stripVOID($Values) + { if (!is_array($Values)) { return(array()); } $Result = array(); foreach($Values as $Key => $Value) { if ( $Value != VOID ) { $Result[] = $Value; } } return($Result); } + + /* Return the number of values contained in a given serie */ + function getSerieCount($Serie) + { if (isset($this->Data["Series"][$Serie]["Data"])) { return(sizeof($this->Data["Series"][$Serie]["Data"])); } else { return(0); } } + + /* Remove a serie from the pData object */ + function removeSerie($Series) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie])) { unset($this->Data["Series"][$Serie]); } } + } + + /* Return a value from given serie & index */ + function getValueAt($Serie,$Index=0) + { if (isset($this->Data["Series"][$Serie]["Data"][$Index])) { return($this->Data["Series"][$Serie]["Data"][$Index]); } else { return(NULL); } } + + /* Return the values array */ + function getValues($Serie) + { if (isset($this->Data["Series"][$Serie]["Data"])) { return($this->Data["Series"][$Serie]["Data"]); } else { return(NULL); } } + + /* Reverse the values in the given serie */ + function reverseSerie($Series) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]["Data"])) { $this->Data["Series"][$Serie]["Data"] = array_reverse($this->Data["Series"][$Serie]["Data"]); } } + } + + /* Return the sum of the serie values */ + function getSum($Serie) + { if (isset($this->Data["Series"][$Serie])) { return(array_sum($this->Data["Series"][$Serie]["Data"])); } else { return(NULL); } } + + /* Return the max value of a given serie */ + function getMax($Serie) + { if (isset($this->Data["Series"][$Serie]["Max"])) { return($this->Data["Series"][$Serie]["Max"]); } else { return(NULL); } } + + /* Return the min value of a given serie */ + function getMin($Serie) + { if (isset($this->Data["Series"][$Serie]["Min"])) { return($this->Data["Series"][$Serie]["Min"]); } else { return(NULL); } } + + /* Set the description of a given serie */ + function setSerieShape($Series,$Shape=SERIE_SHAPE_FILLEDCIRCLE) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Shape"] = $Shape; } } + } + + /* Set the description of a given serie */ + function setSerieDescription($Series,$Description="My serie") + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Description"] = $Description; } } + } + + /* Set a serie as "drawable" while calling a rendering function */ + function setSerieDrawable($Series,$Drawable=TRUE) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["isDrawable"] = $Drawable; } } + } + + /* Set the icon associated to a given serie */ + function setSeriePicture($Series,$Picture=NULL) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Picture"] = $Picture; } } + } + + /* Set the name of the X Axis */ + function setXAxisName($Name) + { $this->Data["XAxisName"] = $Name; } + + /* Set the display mode of the X Axis */ + function setXAxisDisplay($Mode,$Format=NULL) + { $this->Data["XAxisDisplay"] = $Mode; $this->Data["XAxisFormat"] = $Format; } + + /* Set the unit that will be displayed on the X axis */ + function setXAxisUnit($Unit) + { $this->Data["XAxisUnit"] = $Unit; } + + /* Set the serie that will be used as abscissa */ + function setAbscissa($Serie) + { if (isset($this->Data["Series"][$Serie])) { $this->Data["Abscissa"] = $Serie; } } + + function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM) + { $this->Data["AbsicssaPosition"] = $Position; } + + /* Set the name of the abscissa axis */ + function setAbscissaName($Name) + { $this->Data["AbscissaName"] = $Name; } + + /* Create a scatter group specifyin X and Y data series */ + function setScatterSerie($SerieX,$SerieY,$ID=0) + { if (isset($this->Data["Series"][$SerieX]) && isset($this->Data["Series"][$SerieY]) ) { $this->initScatterSerie($ID); $this->Data["ScatterSeries"][$ID]["X"] = $SerieX; $this->Data["ScatterSeries"][$ID]["Y"] = $SerieY; } } + + /* Set the shape of a given sctatter serie */ + function setScatterSerieShape($ID,$Shape=SERIE_SHAPE_FILLEDCIRCLE) + { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Shape"] = $Shape; } } + + /* Set the description of a given scatter serie */ + function setScatterSerieDescription($ID,$Description="My serie") + { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Description"] = $Description; } } + + /* Set the icon associated to a given scatter serie */ + function setScatterSeriePicture($ID,$Picture=NULL) + { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Picture"] = $Picture; } } + + /* Set a scatter serie as "drawable" while calling a rendering function */ + function setScatterSerieDrawable($ID ,$Drawable=TRUE) + { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["isDrawable"] = $Drawable; } } + + /* Define if a scatter serie should be draw with ticks */ + function setScatterSerieTicks($ID,$Width=0) + { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Ticks"] = $Width; } } + + /* Define if a scatter serie should be draw with a special weight */ + function setScatterSerieWeight($ID,$Weight=0) + { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Weight"] = $Weight; } } + + /* Associate a color to a scatter serie */ + function setScatterSerieColor($ID,$Format) + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + if ( isset($this->Data["ScatterSeries"][$ID]) ) + { + $this->Data["ScatterSeries"][$ID]["Color"]["R"] = $R; + $this->Data["ScatterSeries"][$ID]["Color"]["G"] = $G; + $this->Data["ScatterSeries"][$ID]["Color"]["B"] = $B; + $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = $Alpha; + } + } + + /* Compute the series limits for an individual and global point of view */ + function limits() + { + $GlobalMin = ABSOLUTE_MAX; + $GlobalMax = ABSOLUTE_MIN; + + foreach($this->Data["Series"] as $Key => $Value) + { + if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"] == TRUE) + { + if ( $GlobalMin > $this->Data["Series"][$Key]["Min"] ) { $GlobalMin = $this->Data["Series"][$Key]["Min"]; } + if ( $GlobalMax < $this->Data["Series"][$Key]["Max"] ) { $GlobalMax = $this->Data["Series"][$Key]["Max"]; } + } + } + $this->Data["Min"] = $GlobalMin; + $this->Data["Max"] = $GlobalMax; + + return(array($GlobalMin,$GlobalMax)); + } + + /* Mark all series as drawable */ + function drawAll() + { foreach($this->Data["Series"] as $Key => $Value) { if ( $this->Data["Abscissa"] != $Key ) { $this->Data["Series"][$Key]["isDrawable"]=TRUE; } } } + + /* Return the average value of the given serie */ + function getSerieAverage($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]); + return(array_sum($SerieData)/sizeof($SerieData)); + } + else + return(NULL); + } + + /* Return the geometric mean of the given serie */ + function getGeometricMean($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]); + $Seriesum = 1; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum * $Value; } + return(pow($Seriesum,1/sizeof($SerieData))); + } + else + return(NULL); + } + + /* Return the harmonic mean of the given serie */ + function getHarmonicMean($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]); + $Seriesum = 0; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum + 1/$Value; } + return(sizeof($SerieData)/$Seriesum); + } + else + return(NULL); + } + + /* Return the standard deviation of the given serie */ + function getStandardDeviation($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $Average = $this->getSerieAverage($Serie); + $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]); + + $DeviationSum = 0; + foreach($SerieData as $Key => $Value) + $DeviationSum = $DeviationSum + ($Value-$Average)*($Value-$Average); + + $Deviation = sqrt($DeviationSum/count($SerieData)); + + return($Deviation); + } + else + return(NULL); + } + + /* Return the Coefficient of variation of the given serie */ + function getCoefficientOfVariation($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $Average = $this->getSerieAverage($Serie); + $StandardDeviation = $this->getStandardDeviation($Serie); + + if ( $StandardDeviation != 0 ) + return($StandardDeviation/$Average); + else + return(NULL); + } + else + return(NULL); + } + + /* Return the median value of the given serie */ + function getSerieMedian($Serie) + { + if ( isset($this->Data["Series"][$Serie]) ) + { + $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]); + sort($SerieData); + $SerieCenter = floor(sizeof($SerieData)/2); + + if ( isset($SerieData[$SerieCenter]) ) + return($SerieData[$SerieCenter]); + else + return(NULL); + } + else + return(NULL); + } + + /* Return the x th percentil of the given serie */ + function getSeriePercentile($Serie="Serie1",$Percentil=95) + { + if (!isset($this->Data["Series"][$Serie]["Data"])) { return(NULL); } + + $Values = count($this->Data["Series"][$Serie]["Data"])-1; + if ( $Values < 0 ) { $Values = 0; } + + $PercentilID = floor(($Values/100)*$Percentil+.5); + $SortedValues = $this->Data["Series"][$Serie]["Data"]; + sort($SortedValues); + + if ( is_numeric($SortedValues[$PercentilID]) ) + return($SortedValues[$PercentilID]); + else + return(NULL); + } + + /* Add random values to a given serie */ + function addRandomValues($SerieName="Serie1",$Options="") + { + $Values = isset($Options["Values"]) ? $Options["Values"] : 20; + $Min = isset($Options["Min"]) ? $Options["Min"] : 0; + $Max = isset($Options["Max"]) ? $Options["Max"] : 100; + $withFloat = isset($Options["withFloat"]) ? $Options["withFloat"] : FALSE; + + for ($i=0;$i<=$Values;$i++) + { + if ( $withFloat ) { $Value = rand($Min*100,$Max*100)/100; } else { $Value = rand($Min,$Max); } + $this->addPoints($Value,$SerieName); + } + } + + /* Test if we have valid data */ + function containsData() + { + if (!isset($this->Data["Series"])) { return(FALSE); } + + $Result = FALSE; + foreach($this->Data["Series"] as $Key => $Value) + { if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"]==TRUE) { $Result=TRUE; } } + return($Result); + } + + /* Set the display mode of an Axis */ + function setAxisDisplay($AxisID,$Mode=AXIS_FORMAT_DEFAULT,$Format=NULL) + { + if ( isset($this->Data["Axis"][$AxisID] ) ) + { + $this->Data["Axis"][$AxisID]["Display"] = $Mode; + if ( $Format != NULL ) { $this->Data["Axis"][$AxisID]["Format"] = $Format; } + } + } + + /* Set the position of an Axis */ + function setAxisPosition($AxisID,$Position=AXIS_POSITION_LEFT) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Position"] = $Position; } } + + /* Associate an unit to an axis */ + function setAxisUnit($AxisID,$Unit) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Unit"] = $Unit; } } + + /* Associate a name to an axis */ + function setAxisName($AxisID,$Name) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Name"] = $Name; } } + + /* Associate a color to an axis */ + function setAxisColor($AxisID,$Format) + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + if ( isset($this->Data["Axis"][$AxisID] ) ) + { + $this->Data["Axis"][$AxisID]["Color"]["R"] = $R; + $this->Data["Axis"][$AxisID]["Color"]["G"] = $G; + $this->Data["Axis"][$AxisID]["Color"]["B"] = $B; + $this->Data["Axis"][$AxisID]["Color"]["Alpha"] = $Alpha; + } + } + + + /* Design an axis as X or Y member */ + function setAxisXY($AxisID,$Identity=AXIS_Y) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Identity"] = $Identity; } } + + /* Associate one data serie with one axis */ + function setSerieOnAxis($Series,$AxisID) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) + { + $PreviousAxis = $this->Data["Series"][$Serie]["Axis"]; + + /* Create missing axis */ + if ( !isset($this->Data["Axis"][$AxisID] ) ) + { $this->Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; $this->Data["Axis"][$AxisID]["Identity"] = AXIS_Y;} + + $this->Data["Series"][$Serie]["Axis"] = $AxisID; + + /* Cleanup unused axis */ + $Found = FALSE; + foreach($this->Data["Series"] as $SerieName => $Values) { if ( $Values["Axis"] == $PreviousAxis ) { $Found = TRUE; } } + if (!$Found) { unset($this->Data["Axis"][$PreviousAxis]); } + } + } + + /* Define if a serie should be draw with ticks */ + function setSerieTicks($Series,$Width=0) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Ticks"] = $Width; } } + } + + /* Define if a serie should be draw with a special weight */ + function setSerieWeight($Series,$Weight=0) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Weight"] = $Weight; } } + } + + /* Returns the palette of the given serie */ + function getSeriePalette($Serie) + { + if ( !isset($this->Data["Series"][$Serie]) ) { return(NULL); } + + $Result = ""; + $Result["R"] = $this->Data["Series"][$Serie]["Color"]["R"]; + $Result["G"] = $this->Data["Series"][$Serie]["Color"]["G"]; + $Result["B"] = $this->Data["Series"][$Serie]["Color"]["B"]; + $Result["Alpha"] = $this->Data["Series"][$Serie]["Color"]["Alpha"]; + + return($Result); + } + + /* Set the color of one serie */ + function setPalette($Series,$Format=NULL) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + + foreach($Series as $Key => $Serie) + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + if ( isset($this->Data["Series"][$Serie]) ) + { + $OldR = $this->Data["Series"][$Serie]["Color"]["R"]; $OldG = $this->Data["Series"][$Serie]["Color"]["G"]; $OldB = $this->Data["Series"][$Serie]["Color"]["B"]; + $this->Data["Series"][$Serie]["Color"]["R"] = $R; + $this->Data["Series"][$Serie]["Color"]["G"] = $G; + $this->Data["Series"][$Serie]["Color"]["B"] = $B; + $this->Data["Series"][$Serie]["Color"]["Alpha"] = $Alpha; + + /* Do reverse processing on the internal palette array */ + foreach ($this->Palette as $Key => $Value) + { if ($Value["R"] == $OldR && $Value["G"] == $OldG && $Value["B"] == $OldB) { $this->Palette[$Key]["R"] = $R; $this->Palette[$Key]["G"] = $G; $this->Palette[$Key]["B"] = $B; $this->Palette[$Key]["Alpha"] = $Alpha;} } + } + } + } + + /* Load a palette file */ + function loadPalette($FileName,$Overwrite=FALSE) + { + if ( !file_exists($FileName) ) { return(-1); } + if ( $Overwrite ) { $this->Palette = ""; } + + $fileHandle = @fopen($FileName, "r"); + if (!$fileHandle) { return(-1); } + while (!feof($fileHandle)) + { + $buffer = fgets($fileHandle, 4096); + if ( preg_match("/,/",$buffer) ) + { + list($R,$G,$B,$Alpha) = preg_split("/,/",$buffer); + if ( $this->Palette == "" ) { $ID = 0; } else { $ID = count($this->Palette); } + $this->Palette[$ID] = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + } + } + fclose($fileHandle); + + /* Apply changes to current series */ + $ID = 0; + if ( isset($this->Data["Series"])) + { + foreach($this->Data["Series"] as $Key => $Value) + { + if ( !isset($this->Palette[$ID]) ) + $this->Data["Series"][$Key]["Color"] = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>0); + else + $this->Data["Series"][$Key]["Color"] = $this->Palette[$ID]; + $ID++; + } + } + } + + /* Initialise a given scatter serie */ + function initScatterSerie($ID) + { + if ( isset($this->Data["ScatterSeries"][$ID]) ) { return(0); } + + $this->Data["ScatterSeries"][$ID]["Description"] = "Scatter ".$ID; + $this->Data["ScatterSeries"][$ID]["isDrawable"] = TRUE; + $this->Data["ScatterSeries"][$ID]["Picture"] = NULL; + $this->Data["ScatterSeries"][$ID]["Ticks"] = 0; + $this->Data["ScatterSeries"][$ID]["Weight"] = 0; + + if ( isset($this->Palette[$ID]) ) + $this->Data["ScatterSeries"][$ID]["Color"] = $this->Palette[$ID]; + else + { + $this->Data["ScatterSeries"][$ID]["Color"]["R"] = rand(0,255); + $this->Data["ScatterSeries"][$ID]["Color"]["G"] = rand(0,255); + $this->Data["ScatterSeries"][$ID]["Color"]["B"] = rand(0,255); + $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = 100; + } + } + + /* Initialise a given serie */ + function initialise($Serie) + { + if ( isset($this->Data["Series"]) ) { $ID = count($this->Data["Series"]); } else { $ID = 0; } + + $this->Data["Series"][$Serie]["Description"] = $Serie; + $this->Data["Series"][$Serie]["isDrawable"] = TRUE; + $this->Data["Series"][$Serie]["Picture"] = NULL; + $this->Data["Series"][$Serie]["Max"] = NULL; + $this->Data["Series"][$Serie]["Min"] = NULL; + $this->Data["Series"][$Serie]["Axis"] = 0; + $this->Data["Series"][$Serie]["Ticks"] = 0; + $this->Data["Series"][$Serie]["Weight"] = 0; + $this->Data["Series"][$Serie]["Shape"] = SERIE_SHAPE_FILLEDCIRCLE; + + if ( isset($this->Palette[$ID]) ) + $this->Data["Series"][$Serie]["Color"] = $this->Palette[$ID]; + else + { + $this->Data["Series"][$Serie]["Color"]["R"] = rand(0,255); + $this->Data["Series"][$Serie]["Color"]["G"] = rand(0,255); + $this->Data["Series"][$Serie]["Color"]["B"] = rand(0,255); + $this->Data["Series"][$Serie]["Color"]["Alpha"] = 100; + } + } + + function normalize($NormalizationFactor=100,$UnitChange=NULL,$Round=1) + { + $Abscissa = $this->Data["Abscissa"]; + + $SelectedSeries = ""; + $MaxVal = 0; + foreach($this->Data["Axis"] as $AxisID => $Axis) + { + if ( $UnitChange != NULL ) { $this->Data["Axis"][$AxisID]["Unit"] = $UnitChange; } + + foreach($this->Data["Series"] as $SerieName => $Serie) + { + if ($Serie["Axis"] == $AxisID && $Serie["isDrawable"] == TRUE && $SerieName != $Abscissa) + { + $SelectedSeries[$SerieName] = $SerieName; + + if ( count($Serie["Data"] ) > $MaxVal ) { $MaxVal = count($Serie["Data"]); } + } + } + } + + for($i=0;$i<=$MaxVal-1;$i++) + { + $Factor = 0; + foreach ($SelectedSeries as $Key => $SerieName ) + { + $Value = $this->Data["Series"][$SerieName]["Data"][$i]; + if ( $Value != VOID ) + $Factor = $Factor + abs($Value); + } + + if ( $Factor != 0 ) + { + $Factor = $NormalizationFactor / $Factor; + + foreach ($SelectedSeries as $Key => $SerieName ) + { + $Value = $this->Data["Series"][$SerieName]["Data"][$i]; + + if ( $Value != VOID && $Factor != $NormalizationFactor ) + $this->Data["Series"][$SerieName]["Data"][$i] = round(abs($Value)*$Factor,$Round); + elseif ( $Value == VOID || $Value == 0 ) + $this->Data["Series"][$SerieName]["Data"][$i] = VOID; + elseif ( $Factor == $NormalizationFactor ) + $this->Data["Series"][$SerieName]["Data"][$i] = $NormalizationFactor; + } + } + } + + foreach ($SelectedSeries as $Key => $SerieName ) + { + $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + } + } + + /* Load data from a CSV (or similar) data source */ + function importFromCSV($FileName,$Options="") + { + $Delimiter = isset($Options["Delimiter"]) ? $Options["Delimiter"] : ","; + $GotHeader = isset($Options["GotHeader"]) ? $Options["GotHeader"] : FALSE; + $SkipColumns = isset($Options["SkipColumns"]) ? $Options["SkipColumns"] : array(-1); + $DefaultSerieName = isset($Options["DefaultSerieName"]) ? $Options["DefaultSerieName"] : "Serie"; + + $Handle = @fopen($FileName,"r"); + if ($Handle) + { + $HeaderParsed = FALSE; $SerieNames = ""; + while (!feof($Handle)) + { + $Buffer = fgets($Handle, 4096); + $Buffer = str_replace(chr(10),"",$Buffer); + $Buffer = str_replace(chr(13),"",$Buffer); + $Values = preg_split("/".$Delimiter."/",$Buffer); + + if ( $Buffer != "" ) + { + if ( $GotHeader && !$HeaderParsed ) + { + foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $Name; } } + $HeaderParsed = TRUE; + } + else + { + if ($SerieNames == "" ) { foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $DefaultSerieName.$Key; } } } + foreach($Values as $Key => $Value) { if ( !in_array($Key,$SkipColumns) ) { $this->addPoints($Value,$SerieNames[$Key]); } } + } + } + } + fclose($Handle); + } + } + + /* Create a dataset based on a formula */ + function createFunctionSerie($SerieName,$Formula="",$Options="") + { + $MinX = isset($Options["MinX"]) ? $Options["MinX"] : -10; + $MaxX = isset($Options["MaxX"]) ? $Options["MaxX"] : 10; + $XStep = isset($Options["XStep"]) ? $Options["XStep"] : 1; + $AutoDescription = isset($Options["AutoDescription"]) ? $Options["AutoDescription"] : FALSE; + $RecordAbscissa = isset($Options["RecordAbscissa"]) ? $Options["RecordAbscissa"] : FALSE; + $AbscissaSerie = isset($Options["AbscissaSerie"]) ? $Options["AbscissaSerie"] : "Abscissa"; + + if ( $Formula == "" ) { return(0); } + + $Result = ""; $Abscissa = ""; + for($i=$MinX; $i<=$MaxX; $i=$i+$XStep) + { + $Expression = "\$return = '!'.(".str_replace("z",$i,$Formula).");"; + if ( @eval($Expression) === FALSE ) { $return = VOID; } + if ( $return == "!" ) { $return = VOID; } else { $return = $this->right($return,strlen($return)-1); } + if ( $return == "NAN" ) { $return = VOID; } + if ( $return == "INF" ) { $return = VOID; } + if ( $return == "-INF" ) { $return = VOID; } + + $Abscissa[] = $i; + $Result[] = $return; + } + + $this->addPoints($Result,$SerieName); + if ( $AutoDescription ) { $this->setSerieDescription($SerieName,$Formula); } + if ( $RecordAbscissa ) { $this->addPoints($Abscissa,$AbscissaSerie); } + } + + function negateValues($Series) + { + if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); } + foreach($Series as $Key => $SerieName) + { + if (isset($this->Data["Series"][$SerieName])) + { + $Data = ""; + foreach($this->Data["Series"][$SerieName]["Data"] as $Key => $Value) + { if ( $Value == VOID ) { $Data[] = VOID; } else { $Data[] = -$Value; } } + $this->Data["Series"][$SerieName]["Data"] = $Data; + + $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"])); + } + } + } + + /* Return the data & configuration of the series */ + function getData() + { return($this->Data); } + + /* Save a palette element */ + function savePalette($ID,$Color) + { $this->Palette[$ID] = $Color; } + + /* Return the palette of the series */ + function getPalette() + { return($this->Palette); } + + /* Called by the scaling algorithm to save the config */ + function saveAxisConfig($Axis) { $this->Data["Axis"]=$Axis; } + + /* Save the Y Margin if set */ + function saveYMargin($Value) { $this->Data["YMargin"]=$Value; } + + /* Save extended configuration to the pData object */ + function saveExtendedData($Tag,$Values) { $this->Data["Extended"][$Tag]=$Values; } + + /* Called by the scaling algorithm to save the orientation of the scale */ + function saveOrientation($Orientation) { $this->Data["Orientation"]=$Orientation; } + + /* Convert a string to a single elements array */ + function convertToArray($Value) + { $Values = ""; $Values[] = $Value; return($Values); } + + /* Class string wrapper */ + function __toString() + { return("pData object."); } + + function left($value,$NbChar) { return substr($value,0,$NbChar); } + function right($value,$NbChar) { return substr($value,strlen($value)-$NbChar,$NbChar); } + function mid($value,$Depart,$NbChar) { return substr($value,$Depart-1,$NbChar); } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pDraw.class.php b/webdata/graph/pchart/class/pDraw.class.php new file mode 100644 index 0000000..2e75aeb --- /dev/null +++ b/webdata/graph/pchart/class/pDraw.class.php @@ -0,0 +1,6216 @@ +DataSet->getData(); + + foreach($Data["Series"] as $SerieName => $Serie) + { if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) { $Results++; } } + + return($Results); + } + + /* Fix box coordinates */ + function fixBoxCoordinates($Xa,$Ya,$Xb,$Yb) + { + $X1 = min($Xa,$Xb); $Y1 = min($Ya,$Yb); + $X2 = max($Xa,$Xb); $Y2 = max($Ya,$Yb); + + return(array($X1,$Y1,$X2,$Y2)); + } + + /* Draw a polygon */ + function drawPolygon($Points,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : FALSE; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $Alpha / 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $SkipX = isset($Format["SkipX"]) ? $Format["SkipX"] : OUT_OF_SIGHT; + $SkipY = isset($Format["SkipY"]) ? $Format["SkipY"] : OUT_OF_SIGHT; + + /* Calling the ImageFilledPolygon() function over the $Points array will round it */ + $Backup = $Points; + + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + + if ( $SkipX != OUT_OF_SIGHT ) { $SkipX = floor($SkipX); } + if ( $SkipY != OUT_OF_SIGHT ) { $SkipY = floor($SkipY); } + + $RestoreShadow = $this->Shadow; + if ( !$NoFill ) + { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + for($i=0;$i<=count($Points)-1;$i=$i+2) + { $Shadow[] = $Points[$i] + $this->ShadowX; $Shadow[] = $Points[$i+1] + $this->ShadowY; } + $this->drawPolygon($Shadow,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"NoBorder"=>TRUE)); + } + + $FillColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + + if ( count($Points) >= 6 ) + { ImageFilledPolygon($this->Picture,$Points,count($Points)/2,$FillColor); } + } + + if ( !$NoBorder ) + { + $Points = $Backup; + + if ( $NoFill ) + $BorderSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + else + $BorderSettings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + + for($i=0;$i<=count($Points)-1;$i=$i+2) + { + if ( isset($Points[$i+2]) ) + { + if ( !($Points[$i] == $Points[$i+2] && $Points[$i] == $SkipX ) && !($Points[$i+1] == $Points[$i+3] && $Points[$i+1] == $SkipY ) ) + $this->drawLine($Points[$i],$Points[$i+1],$Points[$i+2],$Points[$i+3],$BorderSettings); + } + else + { + if ( !($Points[$i] == $Points[0] && $Points[$i] == $SkipX ) && !($Points[$i+1] == $Points[1] && $Points[$i+1] == $SkipY ) ) + $this->drawLine($Points[$i],$Points[$i+1],$Points[0],$Points[1],$BorderSettings); + } + } + } + + $this->Shadow = $RestoreShadow; + } + + /* Apply AALias correction to the rounded box boundaries */ + function offsetCorrection($Value,$Mode) + { + $Value = round($Value,1); + + if ( $Value == 0 && $Mode == 1 ) { return(.9); } + if ( $Value == 0 ) { return(0); } + + if ( $Mode == 1) + { if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.9); }; if ( $Value == .2 ) { return(.8); }; if ( $Value == .3 ) { return(.8); }; if ( $Value == .4 ) { return(.7); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.6); }; if ( $Value == .9 ) { return(.9); }; } + + if ( $Mode == 2) + { if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.8); }; if ( $Value == .9 ) { return(.9); }; } + + if ( $Mode == 3) + { if ( $Value == 1 ) { return(.1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.9); }; if ( $Value == .6 ) { return(.6); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.4); }; if ( $Value == .9 ) { return(.5); }; } + + if ( $Mode == 4) + { if ( $Value == 1 ) { return(-1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.1); }; if ( $Value == .5 ) { return(-.1); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.1); }; if ( $Value == .8 ) { return(.1); }; if ( $Value == .9 ) { return(.1); }; } + } + + /* Draw a rectangle with rounded corners */ + function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1))/2); } + if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1))/2); } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE); + + if ( $Radius <= 0 ) { $this->drawRectangle($X1,$Y1,$X2,$Y2,$Color); return(0); } + + if ( $this->Antialias ) + { + $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color); + $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color); + $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color); + $this->drawLine($X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color); + } + else + { + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imageline($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color); + imageline($this->Picture,$X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color); + imageline($this->Picture,$X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color); + imageline($this->Picture,$X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color); + } + + $Step = 360 / (2 * PI * $Radius); + for($i=0;$i<=90;$i=$i+$Step) + { + $X = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Y = sin(($i+180)*PI/180) * $Radius + $Y1 + $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Y = sin(($i+90)*PI/180) * $Radius + $Y2 - $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos($i*PI/180) * $Radius + $X2 - $Radius; + $Y = sin($i*PI/180) * $Radius + $Y2 - $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos(($i+270)*PI/180) * $Radius + $X2 - $Radius; + $Y = sin(($i+270)*PI/180) * $Radius + $Y1 + $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + } + + /* Draw a rectangle with rounded corners */ + function drawRoundedFilledRectangle($X1,$Y1,$X2,$Y2,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + + /* Temporary fix for AA issue */ + $Y1 = floor($Y1); $Y2 = floor($Y2); $X1 = floor($X1); $X2 = floor($X2); + + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; } + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius*2 ) { $Radius = floor((($X2-$X1))/4); } + if ( $Y2 - $Y1 < $Radius*2 ) { $Radius = floor((($Y2-$Y1))/4); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawRoundedFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,$Radius,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE); + + if ( $Radius <= 0 ) { $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); return(0); } + + $YTop = $Y1+$Radius; + $YBottom = $Y2-$Radius; + + $Step = 360 / (2 * PI * $Radius); + $Positions = ""; $Radius--; $MinY = ""; $MaxY = ""; + for($i=0;$i<=90;$i=$i+$Step) + { + $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius; + $Yp = floor(sin(($i+180)*PI/180) * $Radius + $YTop); + if ( $MinY == "" || $Yp > $MinY ) { $MinY = $Yp; } + + if ( $Xp1 <= floor($X1) ) { $Xp1++; } + if ( $Xp2 >= floor($X2) ) { $Xp2--; } + $Xp1++; + + if ( !isset($Positions[$Yp]) ) + { $Positions[$Yp]["X1"] = $Xp1; $Positions[$Yp]["X2"] = $Xp2; } + else + { $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"]+$Xp1)/2; $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"]+$Xp2)/2; } + + $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius; + $Yp = floor(sin(($i+90)*PI/180) * $Radius + $YBottom); + if ( $MaxY == "" || $Yp < $MaxY ) { $MaxY = $Yp; } + + if ( $Xp1 <= floor($X1) ) { $Xp1++; } + if ( $Xp2 >= floor($X2) ) { $Xp2--; } + $Xp1++; + + if ( !isset($Positions[$Yp]) ) + { $Positions[$Yp]["X1"] = $Xp1; $Positions[$Yp]["X2"] = $Xp2; } + else + { $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"]+$Xp1)/2; $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"]+$Xp2)/2; } + } + + $ManualColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + foreach($Positions as $Yp => $Bounds) + { + $X1 = $Bounds["X1"]; $X1Dec = $this->getFirstDecimal($X1); if ( $X1Dec != 0 ) { $X1 = floor($X1)+1; } + $X2 = $Bounds["X2"]; $X2Dec = $this->getFirstDecimal($X2); if ( $X2Dec != 0 ) { $X2 = floor($X2)-1; } + imageline($this->Picture,$X1,$Yp,$X2,$Yp,$ManualColor); + } + $this->drawFilledRectangle($X1,$MinY+1,floor($X2),$MaxY-1,$Color); + + $Radius++; + $this->drawRoundedRectangle($X1,$Y1,$X2+1,$Y2-1,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + $this->Shadow = $RestoreShadow; + } + + /* Draw a rectangle with rounded corners */ + function drawRoundedFilledRectangle_deprecated($X1,$Y1,$X2,$Y2,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; } + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1)+2)/2); } + if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1)+2)/2); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawRoundedFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,$Radius,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + } + + if ( $this->getFirstDecimal($X2) >= 5 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($X1) <= 5 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + + if ( !$this->Antialias ) { $XOffset1 = 1; $XOffset2 = 1; } + + $YTop = floor($Y1+$Radius); + $YBottom = floor($Y2-$Radius); + + $this->drawFilledRectangle($X1-$XOffset1,$YTop,$X2+$XOffset2,$YBottom,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE)); + + $Step = 360 / (2 * PI * $Radius); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + $Color2 = $this->allocateColor($this->Picture,255,0,0,$Alpha); + $Drawn = ""; + + if ( $Alpha < 100 ) { $Drawn[$YTop] = FALSE; } + if ( $Alpha < 100 ) { $Drawn[$YBottom] = TRUE; } + + for($i=0;$i<=90;$i=$i+$Step) + { + $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius; + $Yp = sin(($i+180)*PI/180) * $Radius + $YTop; + + if ( $this->getFirstDecimal($Xp1) > 5 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + if ( $this->getFirstDecimal($Xp2) > 5 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($Yp) > 5 ) { $YOffset = 1; } else { $YOffset = 0; } + + if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 ) + imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color); + + $Drawn[$Yp+$YOffset] = $Xp2; + + $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius; + $Yp = sin(($i+90)*PI/180) * $Radius + $YBottom; + + if ( $this->getFirstDecimal($Xp1) > 7 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + if ( $this->getFirstDecimal($Xp2) > 7 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($Yp) > 5 ) { $YOffset = 1; } else { $YOffset = 0; } + + if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 ) + imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color); + + $Drawn[$Yp+$YOffset] = $Xp2; + } + + $this->drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + $this->Shadow = $RestoreShadow; + } + + /* Draw a rectangle */ + function drawRectangle($X1,$Y1,$X2,$Y2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : FALSE; + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + if ( $this->Antialias ) + { + if ( $NoAngle ) + { + $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2,$Y1+1,$X2,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X1,$Y1+1,$X1,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + else + { + $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2,$Y1,$X2,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X1,$Y1,$X1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + } + else + { + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagerectangle($this->Picture,$X1,$Y1,$X2,$Y2,$Color); + } + } + + /* Draw a filled rectangle */ + function drawFilledRectangle($X1,$Y1,$X2,$Y2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : NULL; + $Dash = isset($Format["Dash"]) ? $Format["Dash"] : FALSE; + $DashStep = isset($Format["DashStep"]) ? $Format["DashStep"] : 4; + $DashR = isset($Format["DashR"]) ? $Format["DashR"] : 0; + $DashG = isset($Format["DashG"]) ? $Format["DashG"] : 0; + $DashB = isset($Format["DashB"]) ? $Format["DashB"] : 0; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE; + + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks,"NoAngle"=>$NoAngle)); + } + + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + if ( $NoAngle ) + { + imagefilledrectangle($this->Picture,ceil($X1)+1,ceil($Y1),floor($X2)-1,floor($Y2),$Color); + imageline($this->Picture,ceil($X1),ceil($Y1)+1,ceil($X1),floor($Y2)-1,$Color); + imageline($this->Picture,floor($X2),ceil($Y1)+1,floor($X2),floor($Y2)-1,$Color); + } + else + imagefilledrectangle($this->Picture,ceil($X1),ceil($Y1),floor($X2),floor($Y2),$Color); + + if ( $Dash ) + { + if ( $BorderR != -1 ) { $iX1=$X1+1; $iY1=$Y1+1; $iX2=$X2-1; $iY2=$Y2-1; } else { $iX1=$X1; $iY1=$Y1; $iX2=$X2; $iY2=$Y2; } + + $Color = $this->allocateColor($this->Picture,$DashR,$DashG,$DashB,$Alpha); + $Y=$iY1-$DashStep; + for($X=$iX1; $X<=$iX2+($iY2-$iY1); $X=$X+$DashStep) + { + $Y=$Y+$DashStep; + if ( $X > $iX2 ) { $Xa = $X-($X-$iX2); $Ya = $iY1+($X-$iX2); } else { $Xa = $X; $Ya = $iY1; } + if ( $Y > $iY2 ) { $Xb = $iX1+($Y-$iY2); $Yb = $Y-($Y-$iY2); } else { $Xb = $iX1; $Yb = $Y; } + imageline($this->Picture,$Xa,$Ya,$Xb,$Yb,$Color); + } + } + + if ( $this->Antialias && !$NoBorder ) + { + if ( $X1 < ceil($X1) ) + { + $AlphaA = $Alpha * (ceil($X1) - $X1); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1)-1,ceil($Y1),ceil($X1)-1,floor($Y2),$Color); + } + + if ( $Y1 < ceil($Y1) ) + { + $AlphaA = $Alpha * (ceil($Y1) - $Y1); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1),ceil($Y1)-1,floor($X2),ceil($Y1)-1,$Color); + } + + if ( $X2 > floor($X2) ) + { + $AlphaA = $Alpha * (.5-($X2 - floor($X2))); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,floor($X2)+1,ceil($Y1),floor($X2)+1,floor($Y2),$Color); + } + + if ( $Y2 > floor($Y2) ) + { + $AlphaA = $Alpha * (.5-($Y2 - floor($Y2))); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1),floor($Y2)+1,floor($X2),floor($Y2)+1,$Color); + } + } + + if ( $BorderR != -1 ) + $this->drawRectangle($X1,$Y1,$X2,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$Ticks,"NoAngle"=>$NoAngle)); + + $this->Shadow = $RestoreShadow; + } + + /* Draw a rectangular marker of the specified size */ + function drawRectangleMarker($X,$Y,$Format="") + { + $Size = isset($Format["Size"]) ? $Format["Size"] : 4; + + $HalfSize = floor($Size/2); + $this->drawFilledRectangle($X-$HalfSize,$Y-$HalfSize,$X+$HalfSize,$Y+$HalfSize,$Format); + } + + /* Drawn a spline based on the bezier function */ + function drawSpline($Coordinates,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Force = isset($Format["Force"]) ? $Format["Force"] : 30; + $Forces = isset($Format["Forces"]) ? $Format["Forces"] : NULL; + $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : FALSE; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : FALSE; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + + $Cpt = NULL; $Mode = NULL; $Result = ""; + for($i=1;$i<=count($Coordinates)-1;$i++) + { + $X1 = $Coordinates[$i-1][0]; $Y1 = $Coordinates[$i-1][1]; + $X2 = $Coordinates[$i][0]; $Y2 = $Coordinates[$i][1]; + + if ( $Forces != NULL ) { $Force = $Forces[$i]; } + + /* First segment */ + if ( $i == 1 ) + { $Xv1 = $X1; $Yv1 = $Y1; } + else + { + $Angle1 = $this->getAngle($XLast,$YLast,$X1,$Y1); + $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2); + $XOff = cos($Angle2 * PI / 180) * $Force + $X1; + $YOff = sin($Angle2 * PI / 180) * $Force + $Y1; + + $Xv1 = cos($Angle1 * PI / 180) * $Force + $XOff; + $Yv1 = sin($Angle1 * PI / 180) * $Force + $YOff; + } + + /* Last segment */ + if ( $i == count($Coordinates)-1 ) + { $Xv2 = $X2; $Yv2 = $Y2; } + else + { + $Angle1 = $this->getAngle($X2,$Y2,$Coordinates[$i+1][0],$Coordinates[$i+1][1]); + $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2); + $XOff = cos(($Angle2+180) * PI / 180) * $Force + $X2; + $YOff = sin(($Angle2+180) * PI / 180) * $Force + $Y2; + + $Xv2 = cos(($Angle1+180) * PI / 180) * $Force + $XOff; + $Yv2 = sin(($Angle1+180) * PI / 180) * $Force + $YOff; + } + + $Path = $this->drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$Format); + if ($PathOnly) { $Result[] = $Path; } + + $XLast = $X1; $YLast = $Y1; + } + + return($Result); + } + + /* Draw a bezier curve with two controls points */ + function drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : FALSE; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : NULL; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $NoDraw = isset($Format["NoDraw"]) ? $Format["NoDraw"] : FALSE; + $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : FALSE; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + $DrawArrow = isset($Format["DrawArrow"]) ? $Format["DrawArrow"] : FALSE; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 10; + $ArrowRatio = isset($Format["ArrowRatio"]) ? $Format["ArrowRatio"] : .5; + $ArrowTwoHeads = isset($Format["ArrowTwoHeads"]) ? $Format["ArrowTwoHeads"] : FALSE; + + if ( $Segments == NULL ) + { + $Length = $this->getLength($X1,$Y1,$X2,$Y2); + $Precision = ($Length*125)/1000; + } + else + $Precision = $Segments; + + $P[0]["X"] = $X1; $P[0]["Y"] = $Y1; + $P[1]["X"] = $Xv1; $P[1]["Y"] = $Yv1; + $P[2]["X"] = $Xv2; $P[2]["Y"] = $Yv2; + $P[3]["X"] = $X2; $P[3]["Y"] = $Y2; + + /* Compute the bezier points */ + $Q = ""; $ID = 0; $Path = ""; + for($i=0;$i<=$Precision;$i=$i+1) + { + $u = $i / $Precision; + + $C = ""; + $C[0] = (1 - $u) * (1 - $u) * (1 - $u); + $C[1] = ($u * 3) * (1 - $u) * (1 - $u); + $C[2] = 3 * $u * $u * (1 - $u); + $C[3] = $u * $u * $u; + + for($j=0;$j<=3;$j++) + { + if ( !isset($Q[$ID]) ) { $Q[$ID] = ""; } + if ( !isset($Q[$ID]["X"]) ) { $Q[$ID]["X"] = 0; } + if ( !isset($Q[$ID]["Y"]) ) { $Q[$ID]["Y"] = 0; } + + $Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j]; + $Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j]; + } + $ID++; + } + $Q[$ID]["X"] = $X2; $Q[$ID]["Y"] = $Y2; + + if ( !$NoDraw ) + { + /* Display the control points */ + if ( $ShowC && !$PathOnly ) + { + $Xv1 = floor($Xv1); $Yv1 = floor($Yv1); $Xv2 = floor($Xv2); $Yv2 = floor($Yv2); + + $this->drawLine($X1,$Y1,$X2,$Y2,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>30)); + + $MyMarkerSettings = array("R"=>255,"G"=>0,"B"=>0,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4); + $this->drawRectangleMarker($Xv1,$Yv1,$MyMarkerSettings); + $this->drawText($Xv1+4,$Yv1,"v1"); + $MyMarkerSettings = array("R"=>0,"G"=>0,"B"=>255,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4); + $this->drawRectangleMarker($Xv2,$Yv2,$MyMarkerSettings); + $this->drawText($Xv2+4,$Yv2,"v2"); + } + + /* Draw the bezier */ + $LastX = NULL; $LastY = NULL; $Cpt = NULL; $Mode = NULL; $ArrowS = NULL; + foreach ($Q as $Key => $Point) + { + $X = $Point["X"]; $Y = $Point["Y"]; + + /* Get the first segment */ + if ( $ArrowS == NULL && $LastX != NULL && $LastY != NULL ) + { $ArrowS["X2"] = $LastX; $ArrowS["Y2"] = $LastY; $ArrowS["X1"] = $X; $ArrowS["Y1"] = $Y; } + + if ( $LastX != NULL && $LastY != NULL && !$PathOnly) + list($Cpt,$Mode) = $this->drawLine($LastX,$LastY,$X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Cpt"=>$Cpt,"Mode"=>$Mode,"Weight"=>$Weight)); + + /* Get the last segment */ + $ArrowE["X1"] = $LastX; $ArrowE["Y1"] = $LastY; $ArrowE["X2"] = $X; $ArrowE["Y2"] = $Y; + + $LastX = $X; $LastY = $Y; + } + + if ( $DrawArrow && !$PathOnly ) + { + $ArrowSettings = array("FillR"=>$R,"FillG"=>$G,"FillB"=>$B,"Alpha"=>$Alpha,"Size"=>$ArrowSize,"Ratio"=>$ArrowRatio); + if ( $ArrowTwoHeads ) + $this->drawArrow($ArrowS["X1"],$ArrowS["Y1"],$ArrowS["X2"],$ArrowS["Y2"],$ArrowSettings); + + $this->drawArrow($ArrowE["X1"],$ArrowE["Y1"],$ArrowE["X2"],$ArrowE["Y2"],$ArrowSettings); + } + } + return($Q); + } + + /* Draw a line between two points */ + function drawLine($X1,$Y1,$X2,$Y2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $Cpt = isset($Format["Cpt"]) ? $Format["Cpt"] : 1; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : 1; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : NULL; + + if ( $this->Antialias == FALSE && $Ticks == NULL ) + { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $ShadowColor = $this->allocateColor($this->Picture,$this->ShadowR,$this->ShadowG,$this->ShadowB,$this->Shadowa); + imageline($this->Picture,$X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,$ShadowColor); + } + + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imageline($this->Picture,$X1,$Y1,$X2,$Y2,$Color); + return(0); + } + + $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); + if ( $Distance == 0 ) { return(-1); } + + /* Derivative algorithm for overweighted lines, re-route to polygons primitives */ + if ( $Weight != NULL ) + { + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + $PolySettings = array ("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderAlpha"=>$Alpha); + + if ( $Ticks == NULL ) + { + $Points = ""; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $X1; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Y1; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $X1; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Y1; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $X2; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Y2; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $X2; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Y2; + + $this->drawPolygon($Points,$PolySettings); + } + else + { + for($i=0;$i<=$Distance;$i=$i+$Ticks*2) + { + $Xa = (($X2-$X1)/$Distance) * $i + $X1; $Ya = (($Y2-$Y1)/$Distance) * $i + $Y1; + $Xb = (($X2-$X1)/$Distance) * ($i+$Ticks) + $X1; $Yb = (($Y2-$Y1)/$Distance) * ($i+$Ticks) + $Y1; + + $Points = ""; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $Xa; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Ya; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $Xa; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Ya; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $Xb; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Yb; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $Xb; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Yb; + + $this->drawPolygon($Points,$PolySettings); + } + } + + return(1); + } + + $XStep = ($X2-$X1) / $Distance; + $YStep = ($Y2-$Y1) / $Distance; + + for($i=0;$i<=$Distance;$i++) + { + $X = $i * $XStep + $X1; + $Y = $i * $YStep + $Y1; + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + + if ( $Threshold != NULL ) + { + foreach($Threshold as $Key => $Parameters) + { + if ( $Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) + { + if ( isset($Parameters["R"]) ) { $RT = $Parameters["R"]; } else { $RT = 0; } + if ( isset($Parameters["G"]) ) { $GT = $Parameters["G"]; } else { $GT = 0; } + if ( isset($Parameters["B"]) ) { $BT = $Parameters["B"]; } else { $BT = 0; } + if ( isset($Parameters["Alpha"]) ) { $AlphaT = $Parameters["Alpha"]; } else { $AlphaT = 0; } + $Color = array("R"=>$RT,"G"=>$GT,"B"=>$BT,"Alpha"=>$AlphaT); + } + } + } + + if ( $Ticks != NULL ) + { + if ( $Cpt % $Ticks == 0 ) + { $Cpt = 0; if ( $Mode == 1 ) { $Mode = 0; } else { $Mode = 1; } } + + if ( $Mode == 1 ) + $this->drawAntialiasPixel($X,$Y,$Color); + + $Cpt++; + } + else + $this->drawAntialiasPixel($X,$Y,$Color); + } + + return(array($Cpt,$Mode)); + } + + /* Draw a circle */ + function drawCircle($Xc,$Yc,$Height,$Width,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + + $Height = abs($Height); + $Width = abs($Width); + + if ( $Height == 0 ) { $Height = 1; } + if ( $Width == 0 ) { $Width = 1; } + $Xc = floor($Xc); $Yc = floor($Yc); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawCircle($Xc+$this->ShadowX,$Yc+$this->ShadowY,$Height,$Width,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks)); + } + + if ( $Width == 0 ) { $Width = $Height; } + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + $Step = 360 / (2 * PI * max($Width,$Height)); + $Mode = 1; $Cpt = 1; + for($i=0;$i<=360;$i=$i+$Step) + { + $X = cos($i*PI/180) * $Height + $Xc; + $Y = sin($i*PI/180) * $Width + $Yc; + + if ( $Ticks != NULL ) + { + if ( $Cpt % $Ticks == 0 ) + { $Cpt = 0; if ( $Mode == 1 ) { $Mode = 0; } else { $Mode = 1; } } + + if ( $Mode == 1 ) + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $Cpt++; + } + else + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + } + $this->Shadow = $RestoreShadow; + } + + /* Draw a filled circle */ + function drawFilledCircle($X,$Y,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + + if ( $Radius == 0 ) { $Radius = 1; } + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + $X = floor($X); $Y = floor($Y); + + $Radius = abs($Radius); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawFilledCircle($X+$this->ShadowX,$Y+$this->ShadowY,$Radius,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks)); + } + + $this->Mask = ""; + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + for ($i=0; $i<=$Radius*2; $i++) + { + $Slice = sqrt($Radius * $Radius - ($Radius - $i) * ($Radius - $i)); + $XPos = floor($Slice); + $YPos = $Y + $i - $Radius; + $AAlias = $Slice - floor($Slice); + + $this->Mask[$X-$XPos][$YPos] = TRUE; + $this->Mask[$X+$XPos][$YPos] = TRUE; + imageline($this->Picture,$X-$XPos,$YPos,$X+$XPos,$YPos,$Color); + } + if ( $this->Antialias ) + $this->drawCircle($X,$Y,$Radius,$Radius,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + + $this->Mask = ""; + + if ( $BorderR != -1 ) + $this->drawCircle($X,$Y,$Radius,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$Ticks)); + + $this->Shadow = $RestoreShadow; + } + + /* Write text */ + function drawText($X,$Y,$Text,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Align = isset($Format["Align"]) ? $Format["Align"] : TEXT_ALIGN_BOTTOMLEFT; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->FontColorA; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $ShowOrigine = isset($Format["ShowOrigine"]) ? $Format["ShowOrigine"] : FALSE; + $TOffset = isset($Format["TOffset"]) ? $Format["TOffset"] : 2; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : FALSE; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : TRUE; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 6; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : FALSE; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 6; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 255; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 255; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 255; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxBorderG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxBorderB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxBorderAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; + $NoShadow = isset($Format["NoShadow"]) ? $Format["NoShadow"] : FALSE; + + $Shadow = $this->Shadow; + if ( $NoShadow ) { $this->Shadow = FALSE; } + + if ( $BoxSurrounding != "" ) { $BoxBorderR = $BoxR - $BoxSurrounding; $BoxBorderG = $BoxG - $BoxSurrounding; $BoxBorderB = $BoxB - $BoxSurrounding; $BoxBorderAlpha = $BoxAlpha; } + + if ( $ShowOrigine ) + { + $MyMarkerSettings = array("R"=>255,"G"=>0,"B"=>0,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4); + $this->drawRectangleMarker($X,$Y,$MyMarkerSettings); + } + + $TxtPos = $this->getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text); + + if ( $DrawBox && ($Angle == 0 || $Angle == 90 || $Angle == 180 || $Angle == 270)) + { + $T[0]["X"]=0;$T[0]["Y"]=0;$T[1]["X"]=0;$T[1]["Y"]=0;$T[2]["X"]=0;$T[2]["Y"]=0;$T[3]["X"]=0;$T[3]["Y"]=0; + if ( $Angle == 0 ) { $T[0]["X"]=-$TOffset;$T[0]["Y"]=$TOffset;$T[1]["X"]=$TOffset;$T[1]["Y"]=$TOffset;$T[2]["X"]=$TOffset;$T[2]["Y"]=-$TOffset;$T[3]["X"]=-$TOffset;$T[3]["Y"]=-$TOffset; } + + $X1 = min($TxtPos[0]["X"],$TxtPos[1]["X"],$TxtPos[2]["X"],$TxtPos[3]["X"]) - $BorderOffset + 3; + $Y1 = min($TxtPos[0]["Y"],$TxtPos[1]["Y"],$TxtPos[2]["Y"],$TxtPos[3]["Y"]) - $BorderOffset; + $X2 = max($TxtPos[0]["X"],$TxtPos[1]["X"],$TxtPos[2]["X"],$TxtPos[3]["X"]) + $BorderOffset + 3; + $Y2 = max($TxtPos[0]["Y"],$TxtPos[1]["Y"],$TxtPos[2]["Y"],$TxtPos[3]["Y"]) + $BorderOffset - 3; + + $X1 = $X1 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; + $Y1 = $Y1 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; + $X2 = $X2 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; + $Y2 = $Y2 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; + + $Settings = array("R"=>$BoxR,"G"=>$BoxG,"B"=>$BoxB,"Alpha"=>$BoxAlpha,"BorderR"=>$BoxBorderR,"BorderG"=>$BoxBorderG,"BorderB"=>$BoxBorderB,"BorderAlpha"=>$BoxBorderAlpha); + + if ( $BoxRounded ) + { $this->drawRoundedFilledRectangle($X1,$Y1,$X2,$Y2,$RoundedRadius,$Settings); } + else + { $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Settings); } + } + + $X = $X - $TxtPos[$Align]["X"] + $X; + $Y = $Y - $TxtPos[$Align]["Y"] + $Y; + + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $C_ShadowColor = $this->allocateColor($this->Picture,$this->ShadowR,$this->ShadowG,$this->ShadowB,$this->Shadowa); + imagettftext($this->Picture,$FontSize,$Angle,$X+$this->ShadowX,$Y+$this->ShadowY,$C_ShadowColor,$FontName,$Text); + } + + $C_TextColor = $this->AllocateColor($this->Picture,$R,$G,$B,$Alpha); + imagettftext($this->Picture,$FontSize,$Angle,$X,$Y,$C_TextColor,$FontName,$Text); + + $this->Shadow = $Shadow; + + return($TxtPos); + } + + /* Draw a gradient within a defined area */ + function drawGradientArea($X1,$Y1,$X2,$Y2,$Direction,$Format="") + { + $StartR = isset($Format["StartR"]) ? $Format["StartR"] : 90; + $StartG = isset($Format["StartG"]) ? $Format["StartG"] : 90; + $StartB = isset($Format["StartB"]) ? $Format["StartB"] : 90; + $EndR = isset($Format["EndR"]) ? $Format["EndR"] : 0; + $EndG = isset($Format["EndG"]) ? $Format["EndG"] : 0; + $EndB = isset($Format["EndB"]) ? $Format["EndB"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Levels = isset($Format["Levels"]) ? $Format["Levels"] : NULL; + + $Shadow = $this->Shadow; + $this->Shadow = FALSE; + + if ( $StartR == $EndR && $StartG == $EndG && $StartB == $EndB ) + { + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,array("R"=>$StartR,"G"=>$StartG,"B"=>$StartB,"Alpha"=>$Alpha)); + return(0); + } + + if ( $Levels != NULL ) + { $EndR=$StartR+$Levels; $EndG=$StartG+$Levels; $EndB=$StartB+$Levels; } + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + if ( $Direction == DIRECTION_VERTICAL ) { $Width = abs($Y2-$Y1); } + if ( $Direction == DIRECTION_HORIZONTAL ) { $Width = abs($X2-$X1); } + + $Step = max(abs($EndR-$StartR),abs($EndG-$StartG),abs($EndB-$StartB)); + $StepSize = $Width/$Step; + $RStep = ($EndR-$StartR)/$Step; + $GStep = ($EndG-$StartG)/$Step; + $BStep = ($EndB-$StartB)/$Step; + + $R=$StartR;$G=$StartG;$B=$StartB; + switch($Direction) + { + case DIRECTION_VERTICAL: + $StartY = $Y1; $EndY = floor($Y2)+1; $LastY2 = $StartY; + for($i=0;$i<=$Step;$i++) + { + $Y2 = floor($StartY + ($i * $StepSize)); + + if ($Y2 > $EndY) { $Y2 = $EndY; } + if (($Y1 != $Y2 && $Y1 < $Y2) || $Y2 == $EndY) + { + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); + $LastY2 = max($LastY2,$Y2); + $Y1 = $Y2+1; + } + $R = $R + $RStep; $G = $G + $GStep; $B = $B + $BStep; + } + if ( $LastY2 < $EndY && isset($Color)) { for ($i=$LastY2+1;$i<=$EndY;$i++) { $this->drawLine($X1,$i,$X2,$i,$Color); } } + break; + + case DIRECTION_HORIZONTAL: + $StartX = $X1; $EndX = $X2; + for($i=0;$i<=$Step;$i++) + { + $X2 = floor($StartX + ($i * $StepSize)); + + if ($X2 > $EndX) { $X2 = $EndX; } + if (($X1 != $X2 && $X1 < $X2) || $X2 == $EndX) + { + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); + $X1 = $X2+1; + } + $R = $R + $RStep; $G = $G + $GStep; $B = $B + $BStep; + } + if ( $X2 < $EndX && isset($Color)) { $this->drawFilledRectangle($X2,$Y1,$EndX,$Y2,$Color); } + break; + } + + $this->Shadow = $Shadow; + + } + + /* Draw an aliased pixel */ + function drawAntialiasPixel($X,$Y,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) + return(-1); + + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + if ( !$this->Antialias ) + { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $ShadowColor = $this->allocateColor($this->Picture,$this->ShadowR,$this->ShadowG,$this->ShadowB,$this->Shadowa); + imagesetpixel($this->Picture,$X+$this->ShadowX,$Y+$this->ShadowY,$ShadowColor); + } + + $PlotColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagesetpixel($this->Picture,$X,$Y,$PlotColor); + + return(0); + } + + $Plot = ""; + $Xi = floor($X); + $Yi = floor($Y); + + if ( $Xi == $X && $Yi == $Y) + { + if ( $Alpha == 100 ) + $this->drawAlphaPixel($X,$Y,100,$R,$G,$B); + else + $this->drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B); + } + else + { + $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; + if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); } + + $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; + if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); } + + $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha; + if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); } + + $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha; + if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); } + } + } + + /* Draw a semi-transparent pixel */ + function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B) + { + if ( isset($this->Mask[$X])) { if ( isset($this->Mask[$X][$Y]) ) { return(0); } } + + if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) + return(-1); + + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $AlphaFactor = floor(($Alpha / 100) * $this->Shadowa); + $ShadowColor = $this->allocateColor($this->Picture,$this->ShadowR,$this->ShadowG,$this->ShadowB,$AlphaFactor); + imagesetpixel($this->Picture,$X+$this->ShadowX,$Y+$this->ShadowY,$ShadowColor); + } + + $C_Aliased = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagesetpixel($this->Picture,$X,$Y,$C_Aliased); + } + + /* Convert apha to base 10 */ + function convertAlpha($AlphaValue) + { return((127/100)*(100-$AlphaValue)); } + + /* Allocate a color with transparency */ + function allocateColor($Picture,$R,$G,$B,$Alpha=100) + { + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + if ( $Alpha < 0 ) { $Alpha = 0; } + if ( $Alpha > 100) { $Alpha = 100; } + + $Alpha = $this->convertAlpha($Alpha); + return(imagecolorallocatealpha($Picture,$R,$G,$B,$Alpha)); + } + + /* Load a PNG file and draw it over the chart */ + function drawFromPNG($X,$Y,$FileName) + { $this->drawFromPicture(1,$FileName,$X,$Y); } + + /* Load a GIF file and draw it over the chart */ + function drawFromGIF($X,$Y,$FileName) + { $this->drawFromPicture(2,$FileName,$X,$Y); } + + /* Load a JPEG file and draw it over the chart */ + function drawFromJPG($X,$Y,$FileName) + { $this->drawFromPicture(3,$FileName,$X,$Y); } + + function getPicInfo($FileName) + { + $Infos = getimagesize($FileName); + $Width = $Infos[0]; + $Height = $Infos[1]; + $Type = $Infos["mime"]; + + if ( $Type == "image/png") { $Type = 1; } + if ( $Type == "image/gif") { $Type = 2; } + if ( $Type == "image/jpeg ") { $Type = 3; } + + return(array($Width,$Height,$Type)); + } + + /* Generic loader function for external pictures */ + function drawFromPicture($PicType,$FileName,$X,$Y) + { + if ( file_exists($FileName)) + { + list($Width,$Height) = $this->getPicInfo($FileName); + + if ( $PicType == 1 ) + { $Raster = imagecreatefrompng($FileName); } + elseif ( $PicType == 2 ) + { $Raster = imagecreatefromgif($FileName); } + elseif ( $PicType == 3 ) + { $Raster = imagecreatefromjpeg($FileName); } + else + { return(0); } + + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + if ( $PicType == 3 ) + $this->drawFilledRectangle($X+$this->ShadowX,$Y+$this->ShadowY,$X+$Width+$this->ShadowX,$Y+$Height+$this->ShadowY,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + else + { + $TranparentID = imagecolortransparent($Raster); + for ($Xc=0;$Xc<=$Width-1;$Xc++) + { + for ($Yc=0;$Yc<=$Height-1;$Yc++) + { + $RGBa = imagecolorat($Raster,$Xc,$Yc); + $Values = imagecolorsforindex($Raster,$RGBa); + if ( $Values["alpha"] < 120 ) + { + $AlphaFactor = floor(($this->Shadowa / 100) * ((100 / 127) * (127-$Values["alpha"]))); + $this->drawAlphaPixel($X+$Xc+$this->ShadowX,$Y+$Yc+$this->ShadowY,$AlphaFactor,$this->ShadowR,$this->ShadowG,$this->ShadowB); + } + } + } + } + } + $this->Shadow = $RestoreShadow; + + imagecopy($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height); + imagedestroy($Raster); + } + } + + /* Draw an arrow */ + function drawArrow($X1,$Y1,$X2,$Y2,$Format="") + { + $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; + $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; + $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Size = isset($Format["Size"]) ? $Format["Size"] : 10; + $Ratio = isset($Format["Ratio"]) ? $Format["Ratio"] : .5; + $TwoHeads = isset($Format["TwoHeads"]) ? $Format["TwoHeads"] : FALSE; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : FALSE; + + /* Calculate the line angle */ + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + + /* Override Shadow support, this will be managed internally */ + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) + { + $this->Shadow = FALSE; + $this->drawArrow($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,array("FillR"=>$this->ShadowR,"FillG"=>$this->ShadowG,"FillB"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Size"=>$Size,"Ratio"=>$Ratio,"TwoHeads"=>$TwoHeads,"Ticks"=>$Ticks)); + } + + /* Draw the 1st Head */ + $TailX = cos(($Angle-180)*PI/180)*$Size+$X2; + $TailY = sin(($Angle-180)*PI/180)*$Size+$Y2; + + $Points = ""; + $Points[] = $X2; $Points[] = $Y2; + $Points[] = cos(($Angle-90)*PI/180)*$Size*$Ratio+$TailX; $Points[] = sin(($Angle-90)*PI/180)*$Size*$Ratio+$TailY; + $Points[] = cos(($Angle-270)*PI/180)*$Size*$Ratio+$TailX; $Points[] = sin(($Angle-270)*PI/180)*$Size*$Ratio+$TailY; + $Points[] = $X2; $Points[] = $Y2; + + /* Visual correction */ + if ($Angle == 180 || $Angle == 360 ) { $Points[4] = $Points[2]; } + if ($Angle == 90 || $Angle == 270 ) { $Points[5] = $Points[3]; } + + $ArrowColor = $this->allocateColor($this->Picture,$FillR,$FillG,$FillB,$Alpha); + ImageFilledPolygon($this->Picture,$Points,4,$ArrowColor); + + $this->drawLine($Points[0],$Points[1],$Points[2],$Points[3],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[2],$Points[3],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[0],$Points[1],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + /* Draw the second head */ + if ( $TwoHeads ) + { + $Angle = $this->getAngle($X2,$Y2,$X1,$Y1); + + $TailX2 = cos(($Angle-180)*PI/180)*$Size+$X1; + $TailY2 = sin(($Angle-180)*PI/180)*$Size+$Y1; + + $Points = ""; + $Points[] = $X1; $Points[] = $Y1; + $Points[] = cos(($Angle-90)*PI/180)*$Size*$Ratio+$TailX2; $Points[] = sin(($Angle-90)*PI/180)*$Size*$Ratio+$TailY2; + $Points[] = cos(($Angle-270)*PI/180)*$Size*$Ratio+$TailX2; $Points[] = sin(($Angle-270)*PI/180)*$Size*$Ratio+$TailY2; + $Points[] = $X1; $Points[] = $Y1; + + /* Visual correction */ + if ($Angle == 180 || $Angle == 360 ) { $Points[4] = $Points[2]; } + if ($Angle == 90 || $Angle == 270 ) { $Points[5] = $Points[3]; } + + $ArrowColor = $this->allocateColor($this->Picture,$FillR,$FillG,$FillB,$Alpha); + ImageFilledPolygon($this->Picture,$Points,4,$ArrowColor); + + $this->drawLine($Points[0],$Points[1],$Points[2],$Points[3],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[2],$Points[3],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[0],$Points[1],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + $this->drawLine($TailX,$TailY,$TailX2,$TailY2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + else + $this->drawLine($X1,$Y1,$TailX,$TailY,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + + /* Re-enable shadows */ + $this->Shadow = $RestoreShadow; + } + + /* Draw a label with associated arrow */ + function drawArrowLabel($X1,$Y1,$Text,$Format="") + { + $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; + $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; + $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Length = isset($Format["Length"]) ? $Format["Length"] : 50; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 315; + $Size = isset($Format["Size"]) ? $Format["Size"] : 10; + $Position = isset($Format["Position"]) ? $Format["Position"] : POSITION_TOP; + $RoundPos = isset($Format["RoundPos"]) ? $Format["RoundPos"] : FALSE; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + + $Angle = $Angle % 360; + + $X2 = sin(($Angle+180)*PI/180)*$Length+$X1; + $Y2 = cos(($Angle+180)*PI/180)*$Length+$Y1; + + if ( $RoundPos && $Angle > 0 && $Angle < 180 ) { $Y2 = ceil($Y2); } + if ( $RoundPos && $Angle > 180 ) { $Y2 = floor($Y2); } + + $this->drawArrow($X2,$Y2,$X1,$Y1,$Format); + + $Size = imagettfbbox($FontSize,0,$FontName,$Text); + $TxtWidth = max(abs($Size[2]-$Size[0]),abs($Size[0]-$Size[6])); + $TxtHeight = max(abs($Size[1]-$Size[7]),abs($Size[3]-$Size[1])); + + if ( $Angle > 0 && $Angle < 180 ) + { + $this->drawLine($X2,$Y2,$X2-$TxtWidth,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + if ( $Position == POSITION_TOP ) + $this->drawText($X2,$Y2-2,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_BOTTOMRIGHT)); + else + $this->drawText($X2,$Y2+4,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_TOPRIGHT)); + } + else + { + $this->drawLine($X2,$Y2,$X2+$TxtWidth,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + if ( $Position == POSITION_TOP ) + $this->drawText($X2,$Y2-2,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + else + $this->drawText($X2,$Y2+4,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_TOPLEFT)); + } + } + + /* Draw a progress bar filled with specified % */ + function drawProgress($X,$Y,$Percent,$Format="") + { + if ( $Percent > 100 ) { $Percent = 100; } + if ( $Percent < 0 ) { $Percent = 0; } + + $Width = isset($Format["Width"]) ? $Format["Width"] : 200; + $Height = isset($Format["Height"]) ? $Format["Height"] : 20; + $Orientation = isset($Format["Orientation"]) ? $Format["Orientation"] : ORIENTATION_HORIZONTAL; + $ShowLabel = isset($Format["ShowLabel"]) ? $Format["ShowLabel"] : FALSE; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : LABEL_POS_INSIDE; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 10; + $R = isset($Format["R"]) ? $Format["R"] : 130; + $G = isset($Format["G"]) ? $Format["G"] : 130; + $B = isset($Format["B"]) ? $Format["B"] : 130; + $RFade = isset($Format["RFade"]) ? $Format["RFade"] : -1; + $GFade = isset($Format["GFade"]) ? $Format["GFade"] : -1; + $BFade = isset($Format["BFade"]) ? $Format["BFade"] : -1; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 0; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 0; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 0; + $BoxBackR = isset($Format["BoxBackR"]) ? $Format["BoxBackR"] : 255; + $BoxBackG = isset($Format["BoxBackG"]) ? $Format["BoxBackG"] : 255; + $BoxBackB = isset($Format["BoxBackB"]) ? $Format["BoxBackB"] : 255; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : NULL; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : FALSE; + + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) + { + $RFade = (($RFade-$R)/100)*$Percent+$R; + $GFade = (($GFade-$G)/100)*$Percent+$G; + $BFade = (($BFade-$B)/100)*$Percent+$B; + } + + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + if ( $BoxSurrounding != NULL ) { $BoxBorderR = $BoxBackR + $Surrounding; $BoxBorderG = $BoxBackG + $Surrounding; $BoxBorderB = $BoxBackB + $Surrounding; } + + if ( $Orientation == ORIENTATION_VERTICAL ) + { + $InnerHeight = (($Height-2)/100)*$Percent; + $this->drawFilledRectangle($X,$Y,$X+$Width,$Y-$Height,array("R"=>$BoxBackR,"G"=>$BoxBackG,"B"=>$BoxBackB,"BorderR"=>$BoxBorderR,"BorderG"=>$BoxBorderG,"BorderB"=>$BoxBorderB,"NoAngle"=>$NoAngle)); + + $RestoreShadow = $this->Shadow; $this->Shadow = FALSE; + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) + { + $GradientOptions = array("StartR"=>$RFade,"StartG"=>$GFade,"StartB"=>$BFade,"EndR"=>$R,"EndG"=>$G,"EndB"=>$B); + $this->drawGradientArea($X+1,$Y-1,$X+$Width-1,$Y-$InnerHeight,DIRECTION_VERTICAL,$GradientOptions); + + if ( $Surrounding ) + $this->drawRectangle($X+1,$Y-1,$X+$Width-1,$Y-$InnerHeight,array("R"=>255,"G"=>255,"B"=>255,"Alpha"=>$Surrounding)); + } + else + $this->drawFilledRectangle($X+1,$Y-1,$X+$Width-1,$Y-$InnerHeight,array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + + $this->Shadow = $RestoreShadow; + + if ( $ShowLabel && $LabelPos == LABEL_POS_BOTTOM ) { $this->drawText($X+($Width/2),$Y+$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_TOPMIDDLE)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_TOP ) { $this->drawText($X+($Width/2),$Y-$Height-$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_INSIDE ) { $this->drawText($X+($Width/2),$Y-$InnerHeight-$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT,"Angle"=>90)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_CENTER ) { $this->drawText($X+($Width/2),$Y-($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"Angle"=>90)); } + } + else + { + if ( $Percent == 100 ) + $InnerWidth = $Width-1; + else + $InnerWidth = (($Width-2)/100)*$Percent; + + $this->drawFilledRectangle($X,$Y,$X+$Width,$Y+$Height,array("R"=>$BoxBackR,"G"=>$BoxBackG,"B"=>$BoxBackB,"BorderR"=>$BoxBorderR,"BorderG"=>$BoxBorderG,"BorderB"=>$BoxBorderB,"NoAngle"=>$NoAngle)); + + $RestoreShadow = $this->Shadow; $this->Shadow = FALSE; + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) + { + $GradientOptions = array("StartR"=>$R,"StartG"=>$G,"StartB"=>$B,"EndR"=>$RFade,"EndG"=>$GFade,"EndB"=>$BFade); + $this->drawGradientArea($X+1,$Y+1,$X+$InnerWidth,$Y+$Height-1,DIRECTION_HORIZONTAL,$GradientOptions); + + if ( $Surrounding ) + $this->drawRectangle($X+1,$Y+1,$X+$InnerWidth,$Y+$Height-1,array("R"=>255,"G"=>255,"B"=>255,"Alpha"=>$Surrounding)); + } + else + $this->drawFilledRectangle($X+1,$Y+1,$X+$InnerWidth,$Y+$Height-1,array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + + $this->Shadow = $RestoreShadow; + + if ( $ShowLabel && $LabelPos == LABEL_POS_LEFT ) { $this->drawText($X-$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_RIGHT ) { $this->drawText($X+$Width+$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_CENTER ) { $this->drawText($X+($Width/2),$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); } + if ( $ShowLabel && $LabelPos == LABEL_POS_INSIDE ) { $this->drawText($X+$InnerWidth+$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT)); } + } + } + + /* Get the legend box size */ + function getLegendSize($Format="") + { + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 5; + + $Data = $this->DataSet->getData(); + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && isset($Serie["Picture"])) + { + list($PicWidth,$PicHeight) = $this->getPicInfo($Serie["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $X=100; $Y=100; + + $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + if ( $Mode == LEGEND_VERTICAL ) + { + $BoxArray = $this->getTextBox($vX+$IconAreaWidth+4,$vY+$IconAreaHeight/2,$FontName,$FontSize,0,$Serie["Description"]); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Lines = preg_split("/\n/",$Serie["Description"]); + $vY = $vY + max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->getTextBox($vX+$IconAreaWidth+6,$Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key),$FontName,$FontSize,0,$Value); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { $Boundaries["B"] = $vY+$IconAreaHeight+$TopOffset; } + + $Width = ($Boundaries["R"]+$Margin) - ($Boundaries["L"]-$Margin); + $Height = ($Boundaries["B"]+$Margin) - ($Boundaries["T"]-$Margin); + + return(array("Width"=>$Width,"Height"=>$Height)); + } + + /* Draw the legend of the active series */ + function drawLegend($X,$Y,$Format="") + { + $Family = isset($Format["Family"]) ? $Format["Family"] : LEGEND_FAMILY_BOX; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->FontColorR; + $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->FontColorG; + $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->FontColorB; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $R = isset($Format["R"]) ? $Format["R"] : 200; + $G = isset($Format["G"]) ? $Format["G"] : 200; + $B = isset($Format["B"]) ? $Format["B"] : 200; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + + $Data = $this->DataSet->getData(); + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && isset($Serie["Picture"])) + { + list($PicWidth,$PicHeight) = $this->getPicInfo($Serie["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + if ( $Mode == LEGEND_VERTICAL ) + { + $BoxArray = $this->getTextBox($vX+$IconAreaWidth+4,$vY+$IconAreaHeight/2,$FontName,$FontSize,0,$Serie["Description"]); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Lines = preg_split("/\n/",$Serie["Description"]); + $vY = $vY + max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->getTextBox($vX+$IconAreaWidth+6,$Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key),$FontName,$FontSize,0,$Value); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { $Boundaries["B"] = $vY+$IconAreaHeight+$TopOffset; } + + if ( $Style == LEGEND_ROUND ) + $this->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + elseif ( $Style == LEGEND_BOX ) + $this->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + + $RestoreShadow = $this->Shadow; $this->Shadow = FALSE; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; + $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + if ( isset($Serie["Picture"]) ) + { + $Picture = $Serie["Picture"]; + list($PicWidth,$PicHeight) = $this->getPicInfo($Picture); + $PicX = $X+$IconAreaWidth/2; $PicY = $Y+$IconAreaHeight/2; + + $this->drawFromPNG($PicX-$PicWidth/2,$PicY-$PicHeight/2,$Picture); + } + else + { + if ( $Family == LEGEND_FAMILY_BOX ) + { + if ( $BoxWidth != $IconAreaWidth ) { $XOffset = floor(($IconAreaWidth-$BoxWidth)/2); } else { $XOffset = 0; } + if ( $BoxHeight != $IconAreaHeight ) { $YOffset = floor(($IconAreaHeight-$BoxHeight)/2); } else { $YOffset = 0; } + + $this->drawFilledRectangle($X+1+$XOffset,$Y+1+$YOffset,$X+$BoxWidth+$XOffset+1,$Y+$BoxHeight+1+$YOffset,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); + $this->drawFilledRectangle($X+$XOffset,$Y+$YOffset,$X+$BoxWidth+$XOffset,$Y+$BoxHeight+$YOffset,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); + } + elseif ( $Family == LEGEND_FAMILY_CIRCLE ) + { + $this->drawFilledCircle($X+1+$IconAreaWidth/2,$Y+1+$IconAreaHeight/2,min($IconAreaHeight/2,$IconAreaWidth/2),array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); + $this->drawFilledCircle($X+$IconAreaWidth/2,$Y+$IconAreaHeight/2,min($IconAreaHeight/2,$IconAreaWidth/2),array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); + } + elseif ( $Family == LEGEND_FAMILY_LINE ) + { + $this->drawLine($X+1,$Y+1+$IconAreaHeight/2,$X+1+$IconAreaWidth,$Y+1+$IconAreaHeight/2,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20,"Ticks"=>$Ticks,"Weight"=>$Weight)); + $this->drawLine($X,$Y+$IconAreaHeight/2,$X+$IconAreaWidth,$Y+$IconAreaHeight/2,array("R"=>$R,"G"=>$G,"B"=>$B,"Ticks"=>$Ticks,"Weight"=>$Weight)); + } + } + + if ( $Mode == LEGEND_VERTICAL ) + { + $Lines = preg_split("/\n/",$Serie["Description"]); + foreach($Lines as $Key => $Value) + $this->drawText($X+$IconAreaWidth+4,$Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key),$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontSize"=>$FontSize,"FontName"=>$FontName)); + + $Y=$Y+max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->drawText($X+$IconAreaWidth+4,$Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key),$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontSize"=>$FontSize,"FontName"=>$FontName)); + $Width[] = $BoxArray[1]["X"]; + } + $X=max($Width)+2+$XStep; + } + } + } + + + $this->Shadow = $RestoreShadow; + } + + function drawScale($Format="") + { + $Pos = isset($Format["Pos"]) ? $Format["Pos"] : SCALE_POS_LEFTRIGHT; + $Floating = isset($Format["Floating"]) ? $Format["Floating"] : FALSE; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : SCALE_MODE_FLOATING; + $RemoveXAxis = isset($Format["RemoveXAxis"]) ? $Format["RemoveXAxis"] : FALSE; + $MinDivHeight = isset($Format["MinDivHeight"]) ? $Format["MinDivHeight"] : 20; + $Factors = isset($Format["Factors"]) ? $Format["Factors"] : array(1,2,5); + $ManualScale = isset($Format["ManualScale"]) ? $Format["ManualScale"] : array("0"=>array("Min"=>-100,"Max"=>100)); + $XMargin = isset($Format["XMargin"]) ? $Format["XMargin"] : AUTO; + $YMargin = isset($Format["YMargin"]) ? $Format["YMargin"] : 0; + $ScaleSpacing = isset($Format["ScaleSpacing"]) ? $Format["ScaleSpacing"] : 15; + $InnerTickWidth = isset($Format["InnerTickWidth"]) ? $Format["InnerTickWidth"] : 2; + $OuterTickWidth = isset($Format["OuterTickWidth"]) ? $Format["OuterTickWidth"] : 2; + $DrawXLines = isset($Format["DrawXLines"]) ? $Format["DrawXLines"] : TRUE; + $DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL; + $GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4; + $GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255; + $GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255; + $GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255; + $GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40; + $AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0; + $AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0; + $AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 100; + $TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0; + $TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0; + $TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0; + $TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100; + $DrawSubTicks = isset($Format["DrawSubTicks"]) ? $Format["DrawSubTicks"] : FALSE; + $InnerSubTickWidth = isset($Format["InnerSubTickWidth"]) ? $Format["InnerSubTickWidth"] : 0; + $OuterSubTickWidth = isset($Format["OuterSubTickWidth"]) ? $Format["OuterSubTickWidth"] : 2; + $SubTickR = isset($Format["SubTickR"]) ? $Format["SubTickR"] : 255; + $SubTickG = isset($Format["SubTickG"]) ? $Format["SubTickG"] : 0; + $SubTickB = isset($Format["SubTickB"]) ? $Format["SubTickB"] : 0; + $SubTickAlpha = isset($Format["SubTickAlpha"]) ? $Format["SubTickAlpha"] : 100; + $AutoAxisLabels = isset($Format["AutoAxisLabels"]) ? $Format["AutoAxisLabels"] : TRUE; + $XReleasePercent = isset($Format["XReleasePercent"]) ? $Format["XReleasePercent"] : 1; + $DrawArrows = isset($Format["DrawArrows"]) ? $Format["DrawArrows"] : FALSE; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 8; + $CycleBackground = isset($Format["CycleBackground"]) ? $Format["CycleBackground"] : FALSE; + $BackgroundR1 = isset($Format["BackgroundR1"]) ? $Format["BackgroundR1"] : 255; + $BackgroundG1 = isset($Format["BackgroundG1"]) ? $Format["BackgroundG1"] : 255; + $BackgroundB1 = isset($Format["BackgroundB1"]) ? $Format["BackgroundB1"] : 255; + $BackgroundAlpha1 = isset($Format["BackgroundAlpha1"]) ? $Format["BackgroundAlpha1"] : 20; + $BackgroundR2 = isset($Format["BackgroundR2"]) ? $Format["BackgroundR2"] : 230; + $BackgroundG2 = isset($Format["BackgroundG2"]) ? $Format["BackgroundG2"] : 230; + $BackgroundB2 = isset($Format["BackgroundB2"]) ? $Format["BackgroundB2"] : 230; + $BackgroundAlpha2 = isset($Format["BackgroundAlpha2"]) ? $Format["BackgroundAlpha2"] : 20; + $LabelingMethod = isset($Format["LabelingMethod"]) ? $Format["LabelingMethod"] : LABELING_ALL; + $LabelSkip = isset($Format["LabelSkip"]) ? $Format["LabelSkip"] : 0; + $LabelRotation = isset($Format["LabelRotation"]) ? $Format["LabelRotation"] : 0; + $RemoveSkippedAxis = isset($Format["RemoveSkippedAxis"]) ? $Format["RemoveSkippedAxis"] : FALSE; + $SkippedAxisTicks = isset($Format["SkippedAxisTicks"]) ? $Format["SkippedAxisTicks"] : $GridTicks+2; + $SkippedAxisR = isset($Format["SkippedAxisR"]) ? $Format["SkippedAxisR"] : $GridR; + $SkippedAxisG = isset($Format["SkippedAxisG"]) ? $Format["SkippedAxisG"] : $GridG; + $SkippedAxisB = isset($Format["SkippedAxisB"]) ? $Format["SkippedAxisB"] : $GridB; + $SkippedAxisAlpha = isset($Format["SkippedAxisAlpha"]) ? $Format["SkippedAxisAlpha"] : $GridAlpha-30; + $SkippedTickR = isset($Format["SkippedTickR"]) ? $Format["SkippedTickR"] : $TickRo; + $SkippedTickG = isset($Format["SkippedTickG"]) ? $Format["SkippedTickG"] : $TickGo; + $SkippedTickB = isset($Format["SkippedTicksB"]) ? $Format["SkippedTickB"] : $TickBo; + $SkippedTickAlpha = isset($Format["SkippedTickAlpha"]) ? $Format["SkippedTickAlpha"] : $TickAlpha-80; + $SkippedInnerTickWidth = isset($Format["SkippedInnerTickWidth"]) ? $Format["SkippedInnerTickWidth"] : 0; + $SkippedOuterTickWidth = isset($Format["SkippedOuterTickWidth"]) ? $Format["SkippedOuterTickWidth"] : 2; + + /* Floating scale require X & Y margins to be set manually */ + if ( $Floating && ( $XMargin == AUTO || $YMargin == 0 ) ) { $Floating = FALSE; } + + /* Skip a NOTICE event in case of an empty array */ + if ( $DrawYLines == NONE || $DrawYLines == FALSE ) { $DrawYLines = array("zarma"=>"31"); } + + /* Define the color for the skipped elements */ + $SkippedAxisColor = array("R"=>$SkippedAxisR,"G"=>$SkippedAxisG,"B"=>$SkippedAxisB,"Alpha"=>$SkippedAxisAlpha,"Ticks"=>$SkippedAxisTicks); + $SkippedTickColor = array("R"=>$SkippedTickR,"G"=>$SkippedTickG,"B"=>$SkippedTickB,"Alpha"=>$SkippedTickAlpha); + + $Data = $this->DataSet->getData(); + if ( isset($Data["Abscissa"]) ) { $Abscissa = $Data["Abscissa"]; } else { $Abscissa = NULL; } + + /* Unset the abscissa axis, needed if we display multiple charts on the same picture */ + if ( $Abscissa != NULL ) + { + foreach($Data["Axis"] as $AxisID => $Parameters) + { if ($Parameters["Identity"] == AXIS_X) { unset($Data["Axis"][$AxisID]); } } + } + + /* Build the scale settings */ + $GotXAxis = FALSE; + foreach($Data["Axis"] as $AxisID => $AxisParameter) + { + if ( $AxisParameter["Identity"] == AXIS_X ) { $GotXAxis = TRUE; } + + if ( $Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_Y) + { $Height = $this->GraphAreaY2-$this->GraphAreaY1 - $YMargin*2; } + elseif ( $Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_X) + { $Height = $this->GraphAreaX2-$this->GraphAreaX1; } + elseif ( $Pos == SCALE_POS_TOPBOTTOM && $AxisParameter["Identity"] == AXIS_Y) + { $Height = $this->GraphAreaX2-$this->GraphAreaX1 - $YMargin*2;; } + else + { $Height = $this->GraphAreaY2-$this->GraphAreaY1; } + + $AxisMin = ABSOLUTE_MAX; $AxisMax = OUT_OF_SIGHT; + if ( $Mode == SCALE_MODE_FLOATING || $Mode == SCALE_MODE_START0 ) + { + foreach($Data["Series"] as $SerieID => $SerieParameter) + { + if ( $SerieParameter["Axis"] == $AxisID && $Data["Series"][$SerieID]["isDrawable"] && $Data["Abscissa"] != $SerieID) + { + $AxisMax = max($AxisMax,$Data["Series"][$SerieID]["Max"]); + $AxisMin = min($AxisMin,$Data["Series"][$SerieID]["Min"]); + } + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + if ( $Mode == SCALE_MODE_START0 ) { $Data["Axis"][$AxisID]["Min"] = 0; } + } + elseif ( $Mode == SCALE_MODE_MANUAL ) + { + if ( isset($ManualScale[$AxisID]["Min"]) && isset($ManualScale[$AxisID]["Max"]) ) + { + $Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"]; + $Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"]; + } + else + { echo "Manual scale boundaries not set."; exit(); } + } + elseif ( $Mode == SCALE_MODE_ADDALL || $Mode == SCALE_MODE_ADDALL_START0 ) + { + $Series = ""; + foreach($Data["Series"] as $SerieID => $SerieParameter) + { if ( $SerieParameter["Axis"] == $AxisID && $SerieParameter["isDrawable"] && $Data["Abscissa"] != $SerieID ) { $Series[$SerieID] = count($Data["Series"][$SerieID]["Data"]); } } + + for ($ID=0;$ID<=max($Series)-1;$ID++) + { + $PointMin = 0; $PointMax = 0; + foreach($Series as $SerieID => $ValuesCount ) + { + if (isset($Data["Series"][$SerieID]["Data"][$ID]) && $Data["Series"][$SerieID]["Data"][$ID] != NULL ) + { + $Value = $Data["Series"][$SerieID]["Data"][$ID]; + if ( $Value > 0 ) { $PointMax = $PointMax + $Value; } else { $PointMin = $PointMin + $Value; } + } + } + $AxisMax = max($AxisMax,$PointMax); + $AxisMin = min($AxisMin,$PointMin); + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + } + $MaxDivs = floor($Height/$MinDivHeight); + + if ( $Mode == SCALE_MODE_ADDALL_START0 ) { $Data["Axis"][$AxisID]["Min"] = 0; } + + $Scale = $this->computeScale($Data["Axis"][$AxisID]["Min"],$Data["Axis"][$AxisID]["Max"],$MaxDivs,$Factors,$AxisID); + + $Data["Axis"][$AxisID]["Margin"] = $AxisParameter["Identity"] == AXIS_X ? $XMargin : $YMargin; + $Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"]; + $Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"]; + $Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"]; + $Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"]; + + if ( isset($Scale["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = $Scale["Format"]; } + + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { $Data["Axis"][$AxisID]["Display"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { $Data["Axis"][$AxisID]["Unit"] = NULL; } + } + + /* Still no X axis */ + if ( $GotXAxis == FALSE ) + { + if ( $Abscissa != NULL ) + { + $Points = count($Data["Series"][$Abscissa]["Data"]); + if ( $AutoAxisLabels ) + $AxisName = isset($Data["Series"][$Abscissa]["Description"]) ? $Data["Series"][$Abscissa]["Description"] : NULL; + else + $AxisName = NULL; + } + else + { + $Points = 0; + $AxisName = isset($Data["XAxisName"]) ? $Data["XAxisName"] : NULL; + foreach($Data["Series"] as $SerieID => $SerieParameter) + { if ( $SerieParameter["isDrawable"] ) { $Points = max($Points,count($SerieParameter["Data"])); } } + } + + $AxisID = count($Data["Axis"]); + $Data["Axis"][$AxisID]["Identity"] = AXIS_X; + if ( $Pos == SCALE_POS_LEFTRIGHT ) { $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_BOTTOM; } else { $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; } + if ( isset($Data["AbscissaName"]) ) { $Data["Axis"][$AxisID]["Name"] = $Data["AbscissaName"]; } + if ( $XMargin == AUTO ) + { + if ( $Pos == SCALE_POS_LEFTRIGHT ) + { $Height = $this->GraphAreaX2-$this->GraphAreaX1; } + else + { $Height = $this->GraphAreaY2-$this->GraphAreaY1; } + + if ( $Points == 1 ) + $Data["Axis"][$AxisID]["Margin"] = $Height / 2; + else + $Data["Axis"][$AxisID]["Margin"] = ($Height/$Points) / 2; + } + else + { $Data["Axis"][$AxisID]["Margin"] = $XMargin; } + $Data["Axis"][$AxisID]["Rows"] = $Points-1; + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { $Data["Axis"][$AxisID]["Display"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { $Data["Axis"][$AxisID]["Unit"] = NULL; } + } + + /* Do we need to reverse the abscissa position? */ + if ( $Pos != SCALE_POS_LEFTRIGHT ) + { + if ( $Data["AbsicssaPosition"] == AXIS_POSITION_BOTTOM ) + { $Data["AbsicssaPosition"] = AXIS_POSITION_LEFT; } + else + { $Data["AbsicssaPosition"] = AXIS_POSITION_RIGHT; } + } + $Data["Axis"][$AxisID]["Position"] = $Data["AbsicssaPosition"]; + + $this->DataSet->saveOrientation($Pos); + $this->DataSet->saveAxisConfig($Data["Axis"]); + $this->DataSet->saveYMargin($YMargin); + + $FontColorRo = $this->FontColorR; $FontColorGo = $this->FontColorG; $FontColorBo = $this->FontColorB; + + $AxisPos["L"] = $this->GraphAreaX1; $AxisPos["R"] = $this->GraphAreaX2; $AxisPos["T"] = $this->GraphAreaY1; $AxisPos["B"] = $this->GraphAreaY2; + foreach($Data["Axis"] as $AxisID => $Parameters) + { + if ( isset($Parameters["Color"]) ) + { + $AxisR = $Parameters["Color"]["R"]; $AxisG = $Parameters["Color"]["G"]; $AxisB = $Parameters["Color"]["B"]; + $TickR = $Parameters["Color"]["R"]; $TickG = $Parameters["Color"]["G"]; $TickB = $Parameters["Color"]["B"]; + $this->setFontProperties(array("R"=>$Parameters["Color"]["R"],"G"=>$Parameters["Color"]["G"],"B"=>$Parameters["Color"]["B"])); + } + else + { + $AxisR = $AxisRo; $AxisG = $AxisGo; $AxisB = $AxisBo; + $TickR = $TickRo; $TickG = $TickGo; $TickB = $TickBo; + $this->setFontProperties(array("R"=>$FontColorRo,"G"=>$FontColorGo,"B"=>$FontColorBo)); + } + + $LastValue = "w00t"; $ID = 1; + if ( $Parameters["Identity"] == AXIS_X ) + { + if ( $Pos == SCALE_POS_LEFTRIGHT ) + { + if ( $Parameters["Position"] == AXIS_POSITION_BOTTOM ) + { + if ( $LabelRotation == 0 ) { $LabelAlign = TEXT_ALIGN_TOPMIDDLE; $YLabelOffset = 2; } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $YLabelOffset = 5; } + if ( $LabelRotation == 180 ) { $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; $YLabelOffset = 5; } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $YLabelOffset = 2; } + + if ( !$RemoveXAxis ) + { + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->drawLine($this->GraphAreaX1+$Parameters["Margin"],$AxisPos["B"],$this->GraphAreaX2-$Parameters["Margin"],$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($this->GraphAreaX1,$AxisPos["B"],$this->GraphAreaX2,$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($this->GraphAreaX2-$Parameters["Margin"],$AxisPos["B"],$this->GraphAreaX2+($ArrowSize*2),$AxisPos["B"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { $Step = $Width; } else { $Step = $Width / ($Parameters["Rows"]); } + + $MaxBottom = $AxisPos["B"]; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + + if ( $Abscissa != NULL ) + { if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { $Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i],$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); } else { $Value = ""; } } + else + { + if ( isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"]) ) + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); + else + $Value = $i; + } + + $ID++; $Skipped = TRUE; + if ( $this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) + { + $Bounds = $this->drawText($XPos,$YPos+$OuterTickWidth+$YLabelOffset,$Value,array("Angle"=>$LabelRotation,"Align"=>$LabelAlign)); + $TxtBottom = $YPos+$OuterTickWidth+2+($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtBottom); + $LastValue = $Value; + $Skipped = FALSE; + } + + if ( $RemoveXAxis ) { $Skipped = FALSE; } + + if ( $Skipped ) + { + if ( $DrawXLines && !$RemoveSkippedAxis ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,$SkippedAxisColor); } + if ( ($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis) { $this->drawLine($XPos,$YPos-$SkippedInnerTickWidth,$XPos,$YPos+$SkippedOuterTickWidth,$SkippedTickColor); } + } + else + { + if ( $DrawXLines && ($XPos != $this->GraphAreaX1 && $XPos != $this->GraphAreaX2) ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + if ( ($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { $this->drawLine($XPos,$YPos-$InnerTickWidth,$XPos,$YPos+$OuterTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); } + } + } + + if ( isset($Parameters["Name"]) && !$RemoveXAxis) + { + $YPos = $MaxBottom+2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + $MaxBottom = $Bounds[0]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } + elseif ( $Parameters["Position"] == AXIS_POSITION_TOP ) + { + if ( $LabelRotation == 0 ) { $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; $YLabelOffset = 2; } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $YLabelOffset = 2; } + if ( $LabelRotation == 180 ) { $LabelAlign = TEXT_ALIGN_TOPMIDDLE; $YLabelOffset = 5; } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $YLabelOffset = 5; } + + if ( !$RemoveXAxis ) + { + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->drawLine($this->GraphAreaX1+$Parameters["Margin"],$AxisPos["T"],$this->GraphAreaX2-$Parameters["Margin"],$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($this->GraphAreaX1,$AxisPos["T"],$this->GraphAreaX2,$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($this->GraphAreaX2-$Parameters["Margin"],$AxisPos["T"],$this->GraphAreaX2+($ArrowSize*2),$AxisPos["T"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { $Step = $Width; } else { $Step = $Width / $Parameters["Rows"]; } + + $MinTop = $AxisPos["T"]; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + + if ( $Abscissa != NULL ) + { if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { $Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i],$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); } else { $Value = ""; } } + else + { + if ( isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"]) ) + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); + else + $Value = $i; + } + + $ID++; $Skipped = TRUE; + if ( $this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) + { + $Bounds = $this->drawText($XPos,$YPos-$OuterTickWidth-$YLabelOffset,$Value,array("Angle"=>$LabelRotation,"Align"=>$LabelAlign)); + $TxtBox = $YPos-$OuterTickWidth-2-($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtBox); + $LastValue = $Value; + $Skipped = FALSE; + } + + if ( $RemoveXAxis ) { $Skipped = FALSE; } + + if ( $Skipped ) + { + if ( $DrawXLines && !$RemoveSkippedAxis ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,$SkippedAxisColor); } + if ( ($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis ) { $this->drawLine($XPos,$YPos+$SkippedInnerTickWidth,$XPos,$YPos-$SkippedOuterTickWidth,$SkippedTickColor); } + } + else + { + if ( $DrawXLines ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + if ( ($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { $this->drawLine($XPos,$YPos+$InnerTickWidth,$XPos,$YPos-$OuterTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); } + } + + } + + if ( isset($Parameters["Name"]) && !$RemoveXAxis ) + { + $YPos = $MinTop-2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + $MinTop = $Bounds[2]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } + } + elseif ( $Pos == SCALE_POS_TOPBOTTOM ) + { + if ( $Parameters["Position"] == AXIS_POSITION_LEFT ) + { + if ( $LabelRotation == 0 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = -2; } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = -6; } + if ( $LabelRotation == 180 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = -2; } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = -5; } + + if ( !$RemoveXAxis ) + { + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->drawLine($AxisPos["L"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["L"],$this->GraphAreaY2-$Parameters["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($AxisPos["L"],$this->GraphAreaY1,$AxisPos["L"],$this->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($AxisPos["L"],$this->GraphAreaY2-$Parameters["Margin"],$AxisPos["L"],$this->GraphAreaY2+($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { $Step = $Height; } else { $Step = $Height / $Parameters["Rows"]; } + + $MinLeft = $AxisPos["L"]; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step*$i; + $XPos = $AxisPos["L"]; + + if ( $Abscissa != NULL ) + { if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { $Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i],$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); } else { $Value = ""; } } + else + { + if ( isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"]) ) + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); + else + $Value = $i; + } + + $ID++; $Skipped = TRUE; + if ( $this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) + { + $Bounds = $this->drawText($XPos-$OuterTickWidth+$XLabelOffset,$YPos,$Value,array("Angle"=>$LabelRotation,"Align"=>$LabelAlign)); + $TxtBox = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtBox); + $LastValue = $Value; + $Skipped = FALSE; + } + + if ( $RemoveXAxis ) { $Skipped = FALSE; } + + if ( $Skipped ) + { + if ( $DrawXLines && !$RemoveSkippedAxis ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,$SkippedAxisColor); } + if ( ($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis ) { $this->drawLine($XPos-$SkippedOuterTickWidth,$YPos,$XPos+$SkippedInnerTickWidth,$YPos,$SkippedTickColor); } + } + else + { + if ( $DrawXLines && ($YPos != $this->GraphAreaY1 && $YPos != $this->GraphAreaY2) ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + if ( ($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { $this->drawLine($XPos-$OuterTickWidth,$YPos,$XPos+$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); } + } + + } + if ( isset($Parameters["Name"]) && !$RemoveXAxis ) + { + $XPos = $MinLeft-2; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>90)); + $MinLeft = $Bounds[0]["X"]; + + $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } + elseif ( $Parameters["Position"] == AXIS_POSITION_RIGHT ) + { + if ( $LabelRotation == 0 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = 2; } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = 6; } + if ( $LabelRotation == 180 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = 5; } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = 7; } + + if ( !$RemoveXAxis ) + { + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->drawLine($AxisPos["R"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["R"],$this->GraphAreaY2-$Parameters["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($AxisPos["R"],$this->GraphAreaY1,$AxisPos["R"],$this->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($AxisPos["R"],$this->GraphAreaY2-$Parameters["Margin"],$AxisPos["R"],$this->GraphAreaY2+($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { $Step = $Height; } else { $Step = $Height / $Parameters["Rows"]; } + + $MaxRight = $AxisPos["R"]; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step*$i; + $XPos = $AxisPos["R"]; + + if ( $Abscissa != NULL ) + { if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { $Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i],$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); } else { $Value = ""; } } + else + { + if ( isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"]) ) + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Data["XAxisDisplay"],$Data["XAxisFormat"],$Data["XAxisUnit"]); + else + $Value = $i; + } + + $ID++; $Skipped = TRUE; + if ( $this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) + { + $Bounds = $this->drawText($XPos+$OuterTickWidth+$XLabelOffset,$YPos,$Value,array("Angle"=>$LabelRotation,"Align"=>$LabelAlign)); + $TxtBox = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxRight = max($MaxRight,$TxtBox); + $LastValue = $Value; + $Skipped = FALSE; + } + + if ( $RemoveXAxis ) { $Skipped = FALSE; } + + if ( $Skipped ) + { + if ( $DrawXLines && !$RemoveSkippedAxis ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,$SkippedAxisColor); } + if ( ($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis ) { $this->drawLine($XPos+$SkippedOuterTickWidth,$YPos,$XPos-$SkippedInnerTickWidth,$YPos,$SkippedTickColor); } + } + else + { + if ( $DrawXLines ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + if ( ($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { $this->drawLine($XPos+$OuterTickWidth,$YPos,$XPos-$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); } + } + + } + + if ( isset($Parameters["Name"]) && !$RemoveXAxis) + { + $XPos = $MaxRight+4; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270)); + $MaxRight = $Bounds[1]["X"]; + + $this->DataSet->Data["GraphArea"]["X2"] = $MaxRight + $this->FontSize; + } + + $AxisPos["R"] = $MaxRight + $ScaleSpacing; + } + } + } + + + + if ( $Parameters["Identity"] == AXIS_Y ) + { + if ( $Pos == SCALE_POS_LEFTRIGHT ) + { + if ( $Parameters["Position"] == AXIS_POSITION_LEFT ) + { + + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->drawLine($AxisPos["L"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["L"],$this->GraphAreaY2-$Parameters["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($AxisPos["L"],$this->GraphAreaY1,$AxisPos["L"],$this->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($AxisPos["L"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["L"],$this->GraphAreaY1-($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + $Step = $Height / $Parameters["Rows"]; $SubTicksSize = $Step /2; $MinLeft = $AxisPos["L"]; + $LastY = NULL; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step*$i; + $XPos = $AxisPos["L"]; + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Parameters["Display"],$Parameters["Format"],$Parameters["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastY != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->drawFilledRectangle($this->GraphAreaX1+$FloatingOffset,$LastY,$this->GraphAreaX2-$FloatingOffset,$YPos,$BGColor); } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) + $this->drawLine($XPos-$OuterSubTickWidth,$YPos-$SubTicksSize,$XPos+$InnerSubTickWidth,$YPos-$SubTicksSize,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->drawLine($XPos-$OuterTickWidth,$YPos,$XPos+$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->drawText($XPos-$OuterTickWidth-2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + $TxtLeft = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($Parameters["Name"]) ) + { + $XPos = $MinLeft-2; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>90)); + $MinLeft = $Bounds[2]["X"]; + + $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } + elseif ( $Parameters["Position"] == AXIS_POSITION_RIGHT ) + { + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->drawLine($AxisPos["R"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["R"],$this->GraphAreaY2-$Parameters["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($AxisPos["R"],$this->GraphAreaY1,$AxisPos["R"],$this->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($AxisPos["R"],$this->GraphAreaY1+$Parameters["Margin"],$AxisPos["R"],$this->GraphAreaY1-($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + $Step = $Height / $Parameters["Rows"]; $SubTicksSize = $Step /2; $MaxLeft = $AxisPos["R"]; + $LastY = NULL; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step*$i; + $XPos = $AxisPos["R"]; + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Parameters["Display"],$Parameters["Format"],$Parameters["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastY != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->drawFilledRectangle($this->GraphAreaX1+$FloatingOffset,$LastY,$this->GraphAreaX2-$FloatingOffset,$YPos,$BGColor); } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { $this->drawLine($this->GraphAreaX1+$FloatingOffset,$YPos,$this->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) + $this->drawLine($XPos-$OuterSubTickWidth,$YPos-$SubTicksSize,$XPos+$InnerSubTickWidth,$YPos-$SubTicksSize,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->drawLine($XPos-$InnerTickWidth,$YPos,$XPos+$OuterTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->drawText($XPos+$OuterTickWidth+2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + $TxtLeft = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxLeft = max($MaxLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($Parameters["Name"]) ) + { + $XPos = $MaxLeft+6; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270)); + $MaxLeft = $Bounds[2]["X"]; + + $this->DataSet->Data["GraphArea"]["X2"] = $MaxLeft + $this->FontSize; + } + $AxisPos["R"] = $MaxLeft + $ScaleSpacing; + } + } + elseif ( $Pos == SCALE_POS_TOPBOTTOM ) + { + if ( $Parameters["Position"] == AXIS_POSITION_TOP ) + { + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->drawLine($this->GraphAreaX1+$Parameters["Margin"],$AxisPos["T"],$this->GraphAreaX2-$Parameters["Margin"],$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($this->GraphAreaX1,$AxisPos["T"],$this->GraphAreaX2,$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($this->GraphAreaX2-$Parameters["Margin"],$AxisPos["T"],$this->GraphAreaX2+($ArrowSize*2),$AxisPos["T"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + $Step = $Width / $Parameters["Rows"]; $SubTicksSize = $Step /2; $MinTop = $AxisPos["T"]; + $LastX = NULL; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Parameters["Display"],$Parameters["Format"],$Parameters["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastX != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->drawFilledRectangle($LastX,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,$BGColor); } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) + $this->drawLine($XPos+$SubTicksSize,$YPos-$OuterSubTickWidth,$XPos+$SubTicksSize,$YPos+$InnerSubTickWidth,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->drawLine($XPos,$YPos-$OuterTickWidth,$XPos,$YPos+$InnerTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->drawText($XPos,$YPos-$OuterTickWidth-2,$Value,array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + $TxtHeight = $YPos-$OuterTickWidth-2-($Bounds[1]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtHeight); + + $LastX = $XPos; + } + + if ( isset($Parameters["Name"]) ) + { + $YPos = $MinTop-2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + $MinTop = $Bounds[2]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } + elseif ( $Parameters["Position"] == AXIS_POSITION_BOTTOM ) + { + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->drawLine($this->GraphAreaX1+$Parameters["Margin"],$AxisPos["B"],$this->GraphAreaX2-$Parameters["Margin"],$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->drawLine($this->GraphAreaX1,$AxisPos["B"],$this->GraphAreaX2,$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->drawArrow($this->GraphAreaX2-$Parameters["Margin"],$AxisPos["B"],$this->GraphAreaX2+($ArrowSize*2),$AxisPos["B"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + $Step = $Width / $Parameters["Rows"]; $SubTicksSize = $Step /2; $MaxBottom = $AxisPos["B"]; + $LastX = NULL; + for($i=0;$i<=$Parameters["Rows"];$i++) + { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + $Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i,$Parameters["Display"],$Parameters["Format"],$Parameters["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastX != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->drawFilledRectangle($LastX,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,$BGColor); } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { $this->drawLine($XPos,$this->GraphAreaY1+$FloatingOffset,$XPos,$this->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) + $this->drawLine($XPos+$SubTicksSize,$YPos-$OuterSubTickWidth,$XPos+$SubTicksSize,$YPos+$InnerSubTickWidth,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->drawLine($XPos,$YPos-$OuterTickWidth,$XPos,$YPos+$InnerTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->drawText($XPos,$YPos+$OuterTickWidth+2,$Value,array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + $TxtHeight = $YPos+$OuterTickWidth+2+($Bounds[1]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtHeight); + + $LastX = $XPos; + } + + if ( isset($Parameters["Name"]) ) + { + $YPos = $MaxBottom+2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + $MaxBottom = $Bounds[0]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } + } + } + } + } + + function isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) + { + if ( $LabelingMethod == LABELING_DIFFERENT && $Value != $LastValue ) { return(TRUE); } + if ( $LabelingMethod == LABELING_DIFFERENT && $Value == $LastValue ) { return(FALSE); } + if ( $LabelingMethod == LABELING_ALL && $LabelSkip == 0 ) { return(TRUE); } + if ( $LabelingMethod == LABELING_ALL && ($ID+$LabelSkip) % ($LabelSkip+1) != 1 ) { return(FALSE); } + + return(TRUE); + } + + /* Compute the scale, check for the best visual factors */ + function computeScale($XMin,$XMax,$MaxDivs,$Factors,$AxisID=0) + { + /* Compute each factors */ + $Results = ""; + foreach ($Factors as $Key => $Factor) + $Results[$Factor] = $this->processScale($XMin,$XMax,$MaxDivs,array($Factor),$AxisID); + + /* Remove scales that are creating to much decimals */ + $GoodScaleFactors = ""; + foreach ($Results as $Key => $Result) + { + $Decimals = preg_split("/\./",$Result["RowHeight"]); + if ( (!isset($Decimals[1])) || (strlen($Decimals[1]) < 6) ) { $GoodScaleFactors[] = $Key; } + } + + /* Found no correct scale, shame,... returns the 1st one as default */ + if ( $GoodScaleFactors == "" ) { return($Results[$Factors[0]]); } + + /* Find the factor that cause the maximum number of Rows */ + $MaxRows = 0; $BestFactor = 0; + foreach($GoodScaleFactors as $Key => $Factor) + { if ( $Results[$Factor]["Rows"] > $MaxRows ) { $MaxRows = $Results[$Factor]["Rows"]; $BestFactor = $Factor; } } + + /* Return the best visual scale */ + return($Results[$BestFactor]); + } + + /* Compute the best matching scale based on size & factors */ + function processScale($XMin,$XMax,$MaxDivs,$Factors,$AxisID) + { + $ScaleHeight = abs(ceil($XMax)-floor($XMin)); + + if ( isset($this->DataSet->Data["Axis"][$AxisID]["Format"]) ) + $Format = $this->DataSet->Data["Axis"][$AxisID]["Format"]; + else + $Format = NULL; + + if ( isset($this->DataSet->Data["Axis"][$AxisID]["Display"]) ) + $Mode = $this->DataSet->Data["Axis"][$AxisID]["Display"]; + else + $Mode = AXIS_FORMAT_DEFAULT; + + $Scale = ""; + if ( $XMin != $XMax ) + { + $Found = FALSE; $Rescaled = FALSE; $Scaled10Factor = .0001; $Result = 0; + while(!$Found) + { + foreach($Factors as $Key => $Factor) + { + if ( !$Found ) + { + if ( !($this->modulo($XMin,$Factor*$Scaled10Factor) == 0) || ($XMin != floor($XMin))) { $XMinRescaled = floor($XMin/($Factor*$Scaled10Factor))*$Factor*$Scaled10Factor; } else { $XMinRescaled = $XMin; } + if ( !($this->modulo($XMax,$Factor*$Scaled10Factor) == 0) || ($XMax != floor($XMax))) { $XMaxRescaled = floor($XMax/($Factor*$Scaled10Factor))*$Factor*$Scaled10Factor+($Factor*$Scaled10Factor); } else { $XMaxRescaled = $XMax; } + $ScaleHeightRescaled = abs($XMaxRescaled-$XMinRescaled); + + if ( !$Found && floor($ScaleHeightRescaled/($Factor*$Scaled10Factor)) <= $MaxDivs ) { $Found = TRUE; $Rescaled = TRUE; $Result = $Factor * $Scaled10Factor; } + } + } + $Scaled10Factor = $Scaled10Factor * 10; + } + + /* ReCall Min / Max / Height */ + if ( $Rescaled ) { $XMin = $XMinRescaled; $XMax = $XMaxRescaled; $ScaleHeight = $ScaleHeightRescaled; } + + /* Compute rows size */ + $Rows = floor($ScaleHeight / $Result); if ( $Rows == 0 ) { $Rows = 1; } + $RowHeight = $ScaleHeight / $Rows; + + /* Return the results */ + $Scale["Rows"] = $Rows; $Scale["RowHeight"] = $RowHeight; $Scale["XMin"] = $XMin; $Scale["XMax"] = $XMax; + + /* Compute the needed decimals for the metric view to avoid repetition of the same X Axis labels */ + if ( $Mode == AXIS_FORMAT_METRIC && $Format == NULL ) + { + $Done = FALSE; $GoodDecimals = 0; + for($Decimals=0;$Decimals<=10;$Decimals++) + { + if ( !$Done ) + { + $LastLabel = "zob"; $ScaleOK = TRUE; + for($i=0;$i<=$Rows;$i++) + { + $Value = $XMin + $i*$RowHeight; + $Label = $this->scaleFormat($Value,AXIS_FORMAT_METRIC,$Decimals); + + if ( $LastLabel == $Label ) { $ScaleOK = FALSE; } + $LastLabel = $Label; + } + if ( $ScaleOK ) { $Done = TRUE; $GoodDecimals = $Decimals; } + } + } + + $Scale["Format"] = $GoodDecimals; + } + } + else + { + /* If all values are the same we keep a +1/-1 scale */ + $Rows = 2; $XMin = $XMax-1; $XMax = $XMax+1; $RowHeight = 1; + + /* Return the results */ + $Scale["Rows"] = $Rows; $Scale["RowHeight"] = $RowHeight; $Scale["XMin"] = $XMin; $Scale["XMax"] = $XMax; + } + + return($Scale); + } + + function modulo($Value1,$Value2) + { + if (floor($Value2) == 0) { return(0); } + if (floor($Value2) != 0) { return($Value1 % $Value2); } + + $MinValue = min($Value1,$Value2); $Factor = 10; + while ( floor($MinValue*$Factor) == 0 ) + { $Factor = $Factor * 10; } + + return(($Value1*$Factor) % ($Value2*$Factor)); + } + + /* Draw an X threshold */ + function drawXThreshold($Value,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : FALSE; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : FALSE; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : NULL; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 5; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : TRUE; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : FALSE; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 3; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : TRUE; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 30; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + $ValueIsLabel = isset($Format["ValueIsLabel"]) ? $Format["ValueIsLabel"] : FALSE; + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + $XScale = $this->scaleGetXSettings(); + + if ( is_array($Value) ) { foreach ($Value as $Key => $ID) { $this->drawXThreshold($ID,$Format); } return(0); } + + if ( $ValueIsLabel ) + { + $Format["ValueIsLabel"] = FALSE; + foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $SerieValue) + { if ( $SerieValue == $Value ) { $this->drawXThreshold($Key,$Format); } } + + return(0); + } + + $CaptionSettings = array("DrawBox"=>$DrawBox,"DrawBoxBorder"=>$DrawBoxBorder,"BorderOffset"=>$BorderOffset,"BoxRounded"=>$BoxRounded,"RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR,"BoxG"=>$BoxG,"BoxB"=>$BoxB,"BoxAlpha"=>$BoxAlpha,"BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR,"BoxBorderG"=>$BoxBorderG,"BoxBorderB"=>$BoxBorderB,"BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR,"G"=>$CaptionG,"B"=>$CaptionB,"Alpha"=>$CaptionAlpha); + + if ( $Caption == NULL ) + { + if ( isset($Data["Abscissa"]) ) + { + if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$Value]) ) + $Caption = $Data["Series"][$Data["Abscissa"]]["Data"][$Value]; + else + $Caption = $Value; + } + else + $Caption = $Value; + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] *2 ) / $XScale[1]; + $XPos = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value; + $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; + + if ( $XPos >= $this->GraphAreaX1 + $AbscissaMargin && $XPos <= $this->GraphAreaX2 - $AbscissaMargin ) + { + $this->drawLine($XPos,$YPos1,$XPos,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->drawLine($XPos-1,$YPos1,$XPos-1,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->drawLine($XPos+1,$YPos1,$XPos+1,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $Y = $YPos1 + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; } + else + { $Y = $YPos2 - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; } + + $this->drawText($XPos,$Y,$Caption,$CaptionSettings); + } + + return(array("X"=>$XPos)); + } + } + elseif( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] *2 ) / $XScale[1]; + $XPos = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value; + $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; + + if ( $XPos >= $this->GraphAreaY1 + $AbscissaMargin && $XPos <= $this->GraphAreaY2 - $AbscissaMargin ) + { + $this->drawLine($YPos1,$XPos,$YPos2,$XPos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->drawLine($YPos1,$XPos-1,$YPos2,$XPos-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->drawLine($YPos1,$XPos+1,$YPos2,$XPos+1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $Y = $YPos1 + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + else + { $Y = $YPos2 - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + + $this->drawText($Y,$XPos,$Caption,$CaptionSettings); + } + + return(array("X"=>$XPos)); + } + } + } + + /* Draw an X threshold area */ + function drawXThresholdArea($Value1,$Value2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : TRUE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : NULL; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : TRUE; + + $RestoreShadow = $this->Shadow; + if ( $DisableShadowOnArea && $this->Shadow ) { $this->Shadow = FALSE; } + + if ($BorderAlpha >100) { $BorderAlpha = 100;} + + $Data = $this->DataSet->getData(); + $XScale = $this->scaleGetXSettings(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] *2 ) / $XScale[1]; + $XPos1 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value1; + $XPos2 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value2; + $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; + + if ( $XPos1 < $this->GraphAreaX1 + $XScale[0] ) { $XPos1 = $this->GraphAreaX1 + $XScale[0]; } + if ( $XPos1 > $this->GraphAreaX2 - $XScale[0] ) { $XPos1 = $this->GraphAreaX2 - $XScale[0]; } + if ( $XPos2 < $this->GraphAreaX1 + $XScale[0] ) { $XPos2 = $this->GraphAreaX1 + $XScale[0]; } + if ( $XPos2 > $this->GraphAreaX2 - $XScale[0] ) { $XPos2 = $this->GraphAreaX2 - $XScale[0]; } + + $this->drawFilledRectangle($XPos1,$YPos1,$XPos2,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + if ( $Border ) + { + $this->drawLine($XPos1,$YPos1,$XPos1,$YPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->drawLine($XPos2,$YPos1,$XPos2,$YPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) + { + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$AreaName); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if ( abs($XPos2 - $XPos1) > $TxtWidth ) { $NameAngle = 0; } else { $NameAngle = 90; } + } + $this->Shadow = $RestoreShadow; + $this->drawText($XPos,$YPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>$NameAngle,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->Shadow = FALSE; } + } + + $this->Shadow = $RestoreShadow; + return(array("X1"=>$XPos1,"X2"=>$XPos2)); + } + elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] *2 ) / $XScale[1]; + $XPos1 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value1; + $XPos2 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value2; + $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; + + if ( $XPos1 < $this->GraphAreaY1 + $XScale[0] ) { $XPos1 = $this->GraphAreaY1 + $XScale[0]; } + if ( $XPos1 > $this->GraphAreaY2 - $XScale[0] ) { $XPos1 = $this->GraphAreaY2 - $XScale[0]; } + if ( $XPos2 < $this->GraphAreaY1 + $XScale[0] ) { $XPos2 = $this->GraphAreaY1 + $XScale[0]; } + if ( $XPos2 > $this->GraphAreaY2 - $XScale[0] ) { $XPos2 = $this->GraphAreaY2 - $XScale[0]; } + + $this->drawFilledRectangle($YPos1,$XPos1,$YPos2,$XPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + if ( $Border ) + { + $this->drawLine($YPos1,$XPos1,$YPos2,$XPos1,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->drawLine($YPos1,$XPos2,$YPos2,$XPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + + $this->Shadow = $RestoreShadow; + $this->drawText($YPos,$XPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>0,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->Shadow = FALSE; } + } + + $this->Shadow = $RestoreShadow; + return(array("X1"=>$XPos1,"X2"=>$XPos2)); + } + } + + /* Draw an Y threshold with the computed scale */ + function drawThreshold($Value,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : FALSE; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : FALSE; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : NULL; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 10; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : TRUE; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : FALSE; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : TRUE; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : FALSE; + + if ( is_array($Value) ) { foreach ($Value as $Key => $ID) { $this->drawThreshold($ID,$Format); } return(0); } + + $CaptionSettings = array("DrawBox"=>$DrawBox,"DrawBoxBorder"=>$DrawBoxBorder,"BorderOffset"=>$BorderOffset,"BoxRounded"=>$BoxRounded,"RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR,"BoxG"=>$BoxG,"BoxB"=>$BoxB,"BoxAlpha"=>$BoxAlpha,"BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR,"BoxBorderG"=>$BoxBorderG,"BoxBorderB"=>$BoxBorderB,"BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR,"G"=>$CaptionG,"B"=>$CaptionB,"Alpha"=>$CaptionAlpha); + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ( $NoMargin ) { $AbscissaMargin = 0; } + if ( !isset($Data["Axis"][$AxisID]) ) { return(-1); } + if ( $Caption == NULL ) { $Caption = $Value; } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $YPos = $this->scaleComputeY($Value,array("AxisID"=>$AxisID)); + if ( $YPos >= $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] && $YPos <= $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] ) + { + $X1 = $this->GraphAreaX1 + $AbscissaMargin; + $X2 = $this->GraphAreaX2 - $AbscissaMargin; + + $this->drawLine($X1,$YPos,$X2,$YPos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->drawLine($X1,$YPos-1,$X2,$YPos-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->drawLine($X1,$YPos+1,$X2,$YPos+1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $X = $X1 + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + else + { $X = $X2 - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + + $this->drawText($X,$YPos,$Caption,$CaptionSettings); + } + } + + return(array("Y"=>$YPos)); + } + + if ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + $XPos = $this->scaleComputeY($Value,array("AxisID"=>$AxisID)); + if ( $XPos >= $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] && $XPos <= $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] ) + { + $Y1 = $this->GraphAreaY1 + $AbscissaMargin; + $Y2 = $this->GraphAreaY2 - $AbscissaMargin; + + $this->drawLine($XPos,$Y1,$XPos,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->drawLine($XPos-1,$Y1,$XPos-1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->drawLine($XPos+1,$Y1,$XPos+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $Y = $Y1 + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; } + else + { $Y = $Y2 - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; } + + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + $this->drawText($XPos,$Y,$Caption,$CaptionSettings); + } + } + + return(array("Y"=>$XPos)); + } + } + + /* Draw a threshold with the computed scale */ + function drawThresholdArea($Value1,$Value2,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : TRUE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : NULL; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : TRUE; + $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : FALSE; + + if ($Value1 > $Value2) { list($Value1, $Value2) = array($Value2, $Value1); } + + $RestoreShadow = $this->Shadow; + if ( $DisableShadowOnArea && $this->Shadow ) { $this->Shadow = FALSE; } + + if ($BorderAlpha >100) { $BorderAlpha = 100;} + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ( $NoMargin ) { $AbscissaMargin = 0; } + if ( !isset($Data["Axis"][$AxisID]) ) { return(-1); } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $XPos1 = $this->GraphAreaX1 + $AbscissaMargin; + $XPos2 = $this->GraphAreaX2 - $AbscissaMargin; + $YPos1 = $this->scaleComputeY($Value1,array("AxisID"=>$AxisID)); + $YPos2 = $this->scaleComputeY($Value2,array("AxisID"=>$AxisID)); + + if ( $YPos1 < $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] ) { $YPos1 = $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; } + if ( $YPos1 > $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] ) { $YPos1 = $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; } + if ( $YPos2 < $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] ) { $YPos2 = $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; } + if ( $YPos2 > $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] ) { $YPos2 = $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; } + + $this->drawFilledRectangle($XPos1,$YPos1,$XPos2,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + if ( $Border ) + { + $this->drawLine($XPos1,$YPos1,$XPos2,$YPos1,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->drawLine($XPos1,$YPos2,$XPos2,$YPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + $this->Shadow = $RestoreShadow; + $this->drawText($XPos,$YPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>0,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->Shadow = FALSE; } + } + + $this->Shadow = $RestoreShadow; + return(array("Y1"=>$YPos1,"Y2"=>$YPos2)); + } + elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + $YPos1 = $this->GraphAreaY1 + $AbscissaMargin; + $YPos2 = $this->GraphAreaY2 - $AbscissaMargin; + $XPos1 = $this->scaleComputeY($Value1,array("AxisID"=>$AxisID)); + $XPos2 = $this->scaleComputeY($Value2,array("AxisID"=>$AxisID)); + + if ( $XPos1 < $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] ) { $XPos1 = $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; } + if ( $XPos1 > $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] ) { $XPos1 = $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; } + if ( $XPos2 < $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] ) { $XPos2 = $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; } + if ( $XPos2 > $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] ) { $XPos2 = $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; } + + $this->drawFilledRectangle($XPos1,$YPos1,$XPos2,$YPos2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + if ( $Border ) + { + $this->drawLine($XPos1,$YPos1,$XPos1,$YPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->drawLine($XPos2,$YPos1,$XPos2,$YPos2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($YPos2-$YPos1)/2 + $YPos1; + $YPos = ($XPos2-$XPos1)/2 + $XPos1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) + { + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$AreaName); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if ( abs($XPos2 - $XPos1) > $TxtWidth ) { $NameAngle = 0; } else { $NameAngle = 90; } + } + $this->Shadow = $RestoreShadow; + $this->drawText($YPos,$XPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>$NameAngle,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->Shadow = FALSE; } + } + + $this->Shadow = $RestoreShadow; + return(array("Y1"=>$XPos1,"Y2"=>$XPos2)); + } + } + + function scaleGetXSettings() + { + $Data = $this->DataSet->getData(); + foreach($Data["Axis"] as $AxisID => $Settings) + { + if ( $Settings["Identity"] == AXIS_X ) + { + $Rows = $Settings["Rows"]; + + return(array($Settings["Margin"],$Rows)); + } + } + } + + function scaleComputeY($Values,$Option="",$ReturnOnly0Height=FALSE) + { + $AxisID = isset($Option["AxisID"]) ? $Option["AxisID"] : 0; + $SerieName = isset($Option["SerieName"]) ? $Option["SerieName"] : NULL; + + $Data = $this->DataSet->getData(); + if ( !isset($Data["Axis"][$AxisID]) ) { return(-1); } + + if ( $SerieName != NULL ) { $AxisID = $Data["Series"][$SerieName]["Axis"]; } + if ( !is_array($Values) ) { $tmp = $Values; $Values = ""; $Values[0] = $tmp; } + + $Result = ""; + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + if ( $ReturnOnly0Height ) + { foreach($Values as $Key => $Value) { if ( $Value == VOID ) { $Result[] = VOID; } else { $Result[] = $Step * $Value; } } } + else + { foreach($Values as $Key => $Value) { if ( $Value == VOID ) { $Result[] = VOID; } else { $Result[] = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] - ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); } } } + } + else + { + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleWidth = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Width / $ScaleWidth; + + if ( $ReturnOnly0Height ) + { foreach($Values as $Key => $Value) { if ( $Value == VOID ) { $Result[] = VOID; } else { $Result[] = $Step * $Value; } } } + else + { foreach($Values as $Key => $Value) { if ( $Value == VOID ) { $Result[] = VOID; } else { $Result[] = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); } } } + } + + if ( count($Result) == 1 ) + return($Result[0]); + else + return($Result); + } + + /* Format the axis values */ + function scaleFormat($Value,$Mode=NULL,$Format=NULL,$Unit=NULL) + { + if ( $Value == VOID ) { return(""); } + + if ( $Mode == AXIS_FORMAT_TRAFFIC ) + { + if ( $Value == 0 ) { return("0B"); } + $Units = array("B","KB","MB","GB","TB","PB"); + $Sign = ""; if ( $Value < 0 ) { $Value = abs($Value); $Sign = "-"; } + + $Value = number_format($Value/pow(1024,($Scale=floor(log($Value,1024)))),2,",","."); + return($Sign.$Value." ".$Units[$Scale]); + } + + if ( $Mode == AXIS_FORMAT_CUSTOM ) + { if ( function_exists($Format) ) { return(call_user_func($Format,$Value)); } } + + if ( $Mode == AXIS_FORMAT_DATE ) + { if ( $Format == NULL ) { $Pattern = "d/m/Y"; } else { $Pattern = $Format; } return(gmdate($Pattern,$Value)); } + + if ( $Mode == AXIS_FORMAT_TIME ) + { if ( $Format == NULL ) { $Pattern = "H:i:s"; } else { $Pattern = $Format; } return(gmdate($Pattern,$Value)); } + + if ( $Mode == AXIS_FORMAT_CURRENCY ) + { return($Format.number_format($Value,2)); } + + if ( $Mode == AXIS_FORMAT_METRIC ) + { + if (abs($Value) > 1000000000) + return(round($Value/1000000000,$Format)."g".$Unit); + if (abs($Value) > 1000000) + return(round($Value/1000000,$Format)."m".$Unit); + elseif (abs($Value) >= 1000) + return(round($Value/1000,$Format)."k".$Unit); + + } + return($Value.$Unit); + } + + /* Write Max value on a chart */ + function writeBounds($Type=BOUND_BOTH,$Format=NULL) + { + $MaxLabelTxt = isset($Format["MaxLabelTxt"]) ? $Format["MaxLabelTxt"] : "max="; + $MinLabelTxt = isset($Format["MinLabelTxt"]) ? $Format["MinLabelTxt"] : "min="; + $Decimals = isset($Format["Decimals"]) ? $Format["Decimals"] : 1; + $ExcludedSeries = isset($Format["ExcludedSeries"]) ? $Format["ExcludedSeries"] : ""; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 4; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $MaxDisplayR = isset($Format["MaxDisplayR"]) ? $Format["MaxDisplayR"] : 0; + $MaxDisplayG = isset($Format["MaxDisplayG"]) ? $Format["MaxDisplayG"] : 0; + $MaxDisplayB = isset($Format["MaxDisplayB"]) ? $Format["MaxDisplayB"] : 0; + $MinDisplayR = isset($Format["MinDisplayR"]) ? $Format["MinDisplayR"] : 255; + $MinDisplayG = isset($Format["MinDisplayG"]) ? $Format["MinDisplayG"] : 255; + $MinDisplayB = isset($Format["MinDisplayB"]) ? $Format["MinDisplayB"] : 255; + $MinLabelPos = isset($Format["MinLabelPos"]) ? $Format["MinLabelPos"] : BOUND_LABEL_POS_AUTO; + $MaxLabelPos = isset($Format["MaxLabelPos"]) ? $Format["MaxLabelPos"] : BOUND_LABEL_POS_AUTO; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : TRUE; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : FALSE; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : TRUE; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + + $CaptionSettings = array("DrawBox"=>$DrawBox,"DrawBoxBorder"=>$DrawBoxBorder,"BorderOffset"=>$BorderOffset,"BoxRounded"=>$BoxRounded,"RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR,"BoxG"=>$BoxG,"BoxB"=>$BoxB,"BoxAlpha"=>$BoxAlpha,"BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR,"BoxBorderG"=>$BoxBorderG,"BoxBorderB"=>$BoxBorderB,"BoxBorderAlpha"=>$BoxBorderAlpha); + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $Data = $this->DataSet->getData(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && !isset($ExcludedSeries[$SerieName])) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $MinValue = $this->DataSet->getMin($SerieName); + $MaxValue = $this->DataSet->getMax($SerieName); + + $MinPos = VOID; $MaxPos = VOID; + foreach($Serie["Data"] as $Key => $Value) + { + if ( $Value == $MinValue && $MinPos == VOID ) { $MinPos = $Key; } + if ( $Value == $MaxValue ) { $MaxPos = $Key; } + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + $X = $this->GraphAreaX1 + $XMargin; + $SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0; + + if ( $Type == BOUND_MAX || $Type == BOUND_BOTH ) + { + if ( $MaxLabelPos == BOUND_LABEL_POS_TOP || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0) ) { $YPos = $PosArray[$MaxPos] - $DisplayOffset + 2; $Align = TEXT_ALIGN_BOTTOMMIDDLE; } + if ( $MaxLabelPos == BOUND_LABEL_POS_BOTTOM || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0) ) { $YPos = $PosArray[$MaxPos] + $DisplayOffset + 2; $Align = TEXT_ALIGN_TOPMIDDLE; } + + $XPos = $X + $MaxPos*$XStep + $SerieOffset; + $Label = $MaxLabelTxt.$this->scaleFormat(round($MaxValue,$Decimals),$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"])/2); } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { $XOffset = -(($TxtPos[1]["X"] - $this->GraphAreaX2)/2); } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"]; } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { $YOffset = -($TxtPos[0]["Y"] - $this->GraphAreaY2); } + + $CaptionSettings["R"] = $MaxDisplayR; $CaptionSettings["G"] = $MaxDisplayG; + $CaptionSettings["B"] = $MaxDisplayB; $CaptionSettings["Align"] = $Align; + + $this->drawText($XPos+$XOffset,$YPos+$YOffset,$Label,$CaptionSettings); + } + + if ( $Type == BOUND_MIN || $Type == BOUND_BOTH ) + { + if ( $MinLabelPos == BOUND_LABEL_POS_TOP || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0) ) { $YPos = $PosArray[$MinPos] - $DisplayOffset + 2; $Align = TEXT_ALIGN_BOTTOMMIDDLE; } + if ( $MinLabelPos == BOUND_LABEL_POS_BOTTOM || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0) ) { $YPos = $PosArray[$MinPos] + $DisplayOffset + 2; $Align = TEXT_ALIGN_TOPMIDDLE; } + + $XPos = $X + $MinPos*$XStep + $SerieOffset; + $Label = $MinLabelTxt.$this->scaleFormat(round($MinValue,$Decimals),$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"])/2); } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { $XOffset = -(($TxtPos[1]["X"] - $this->GraphAreaX2)/2); } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"]; } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { $YOffset = -($TxtPos[0]["Y"] - $this->GraphAreaY2); } + + $CaptionSettings["R"] = $MinDisplayR; $CaptionSettings["G"] = $MinDisplayG; + $CaptionSettings["B"] = $MinDisplayB; $CaptionSettings["Align"] = $Align; + + $this->drawText($XPos+$XOffset,$YPos-$DisplayOffset+$YOffset,$Label,$CaptionSettings); + } + } + else + { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + $X = $this->GraphAreaY1 + $XMargin; + $SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0; + + if ( $Type == BOUND_MAX || $Type == BOUND_BOTH ) + { + if ( $MaxLabelPos == BOUND_LABEL_POS_TOP || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0) ) { $YPos = $PosArray[$MaxPos] + $DisplayOffset + 2; $Align = TEXT_ALIGN_MIDDLELEFT; } + if ( $MaxLabelPos == BOUND_LABEL_POS_BOTTOM || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0) ) { $YPos = $PosArray[$MaxPos] - $DisplayOffset + 2; $Align = TEXT_ALIGN_MIDDLERIGHT; } + + $XPos = $X + $MaxPos*$XStep + $SerieOffset; + $Label = $MaxLabelTxt.$this->scaleFormat($MaxValue,$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($YPos,$XPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"]; } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { $XOffset = -($TxtPos[1]["X"] - $this->GraphAreaX2); } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"])/2; } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { $YOffset = -(($TxtPos[0]["Y"] - $this->GraphAreaY2)/2);} + + $CaptionSettings["R"] = $MaxDisplayR; $CaptionSettings["G"] = $MaxDisplayG; + $CaptionSettings["B"] = $MaxDisplayB; $CaptionSettings["Align"] = $Align; + + $this->drawText($YPos+$XOffset,$XPos+$YOffset,$Label,$CaptionSettings); + } + + if ( $Type == BOUND_MIN || $Type == BOUND_BOTH ) + { + if ( $MinLabelPos == BOUND_LABEL_POS_TOP || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0) ) { $YPos = $PosArray[$MinPos] + $DisplayOffset + 2; $Align = TEXT_ALIGN_MIDDLELEFT; } + if ( $MinLabelPos == BOUND_LABEL_POS_BOTTOM || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0) ) { $YPos = $PosArray[$MinPos] - $DisplayOffset + 2; $Align = TEXT_ALIGN_MIDDLERIGHT; } + + $XPos = $X + $MinPos*$XStep + $SerieOffset; + $Label = $MinLabelTxt.$this->scaleFormat($MinValue,$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($YPos,$XPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"]; } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { $XOffset = -($TxtPos[1]["X"] - $this->GraphAreaX2); } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"])/2; } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { $YOffset = -(($TxtPos[0]["Y"] - $this->GraphAreaY2)/2);} + + $CaptionSettings["R"] = $MinDisplayR; $CaptionSettings["G"] = $MinDisplayG; + $CaptionSettings["B"] = $MinDisplayB; $CaptionSettings["Align"] = $Align; + + $this->drawText($YPos+$XOffset,$XPos+$YOffset,$Label,$CaptionSettings); + } + } + } + } + } + + /* Draw a plot chart */ + function drawPlotChart($Format=NULL) + { + $PlotSize = isset($Format["PlotSize"]) ? $Format["PlotSize"] : NULL; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 50; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 50; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 50; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $BorderSize = isset($Format["BorderSize"]) ? $Format["BorderSize"] : 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 4; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + if ( isset($Serie["Weight"]) ) { $SerieWeight = $Serie["Weight"] + 2; } else { $SerieWeight = 2; } + if ( $PlotSize != NULL ) { $SerieWeight = $PlotSize; } + + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + if ( isset($Serie["Picture"]) ) + { $Picture = $Serie["Picture"]; list($PicWidth,$PicHeight,$PicType) = $this->getPicInfo($Picture); } + else { $Picture = NULL; $PicOffset = 0; } + + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Shape = $Serie["Shape"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + if ( $Picture != NULL ) { $PicOffset = $PicHeight / 2; $SerieWeight = 0; } + $X = $this->GraphAreaX1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues ) + $this->drawText($X,$Y-$DisplayOffset-$SerieWeight-$BorderSize-$PicOffset,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $Y != VOID ) + { + if ( $RecordImageMap ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$SerieWeight,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Picture != NULL ) + { $this->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); } + else + { $this->drawShape($X,$Y,$Shape,$SerieWeight,$PlotBorder,$BorderSize,$R,$G,$B,$Alpha,$BorderR,$BorderG,$BorderB,$BorderAlpha); } + } + $X = $X + $XStep; + } + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + if ( $Picture != NULL ) { $PicOffset = $PicWidth / 2; $SerieWeight = 0; } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues ) + $this->drawText($X+$DisplayOffset+$SerieWeight+$BorderSize+$PicOffset,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $X != VOID ) + { + if ( $RecordImageMap ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$SerieWeight,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Picture != NULL ) + { $this->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); } + else + { $this->drawShape($X,$Y,$Shape,$SerieWeight,$PlotBorder,$BorderSize,$R,$G,$B,$Alpha,$BorderR,$BorderG,$BorderB,$BorderAlpha); } + } + $Y = $Y + $YStep; + } + } + } + } + } + + /* Draw a spline chart */ + function drawSplineChart($Format=NULL) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : TRUE; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : NULL; // 234 + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : NULL; // 55 + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : NULL; // 26 + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + if ( $BreakR == NULL ) + $BreakSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks); + else + $BreakSettings = array("R"=>$BreakR,"G"=>$BreakG,"B"=>$BreakB,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks,"Weight"=>$Weight); + + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $WayPoints = ""; + $Force = $XStep / 5; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $LastX = 1; $LastY = 1; + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues ) + $this->drawText($X,$Y-$DisplayOffset,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $RecordImageMap && $Y != VOID ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Y == VOID && $LastY != NULL ) + { $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); $WayPoints = ""; } + + if ( $Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid ) + { $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); } + + if ( $Y != VOID ) + $WayPoints[] = array($X,$Y); + + if ( $Y != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $Y == VOID ) { $Y = NULL; } + + $LastX = $X; $LastY = $Y; + $X = $X + $XStep; + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $WayPoints = ""; + $Force = $YStep / 5; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $LastX = 1; $LastY = 1; + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues ) + $this->drawText($X+$DisplayOffset,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $RecordImageMap && $X != VOID ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $X == VOID && $LastX != NULL ) + { $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); $WayPoints = ""; } + + if ( $X != VOID && $LastX == NULL && $LastGoodX != NULL && !$BreakVoid ) + { $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); } + + if ( $X != VOID ) + $WayPoints[] = array($X,$Y); + + if ( $X != VOID ) { $LastGoodX = $X; $LastGoodY = $Y; } + if ( $X == VOID ) { $X = NULL; } + + $LastX = $X; $LastY = $Y; + $Y = $Y + $YStep; + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + } + } + } + } + + /* Draw a filled spline chart */ + function drawFilledSplineChart($Format=NULL) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : TRUE; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : NULL; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + if ( $AroundZero ) { $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); } + + if ( $Threshold != NULL ) + { + foreach($Threshold as $Key => $Params) + { + $Threshold[$Key]["MinX"] = $this->scaleComputeY($Params["Min"],array("AxisID"=>$Serie["Axis"])); + $Threshold[$Key]["MaxX"] = $this->scaleComputeY($Params["Max"],array("AxisID"=>$Serie["Axis"])); + } + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $WayPoints = ""; + $Force = $XStep / 5; + + if ( !$AroundZero ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero < $this->GraphAreaY1+1 ) { $YZero = $this->GraphAreaY1+1; } + + $LastX = ""; $LastY = ""; + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues ) + $this->drawText($X,$Y-$DisplayOffset,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $Y == VOID ) + { + $Area = $this->drawSpline($WayPoints,array("Force"=>$Force,"PathOnly"=>TRUE)); + + if ( $Area != "" ) + { + foreach ($Area as $key => $Points) + { + $Corners = ""; $Corners[] = $Area[$key][0]["X"]; $Corners[] = $YZero; + foreach($Points as $subKey => $Point) + { + if ( $subKey == count($Points)-1) { $Corners[] = $Point["X"]-1; } else { $Corners[] = $Point["X"]; } + $Corners[] = $Point["Y"]+1; + } + $Corners[] = $Points[$subKey]["X"]-1; $Corners[] = $YZero; + + $this->drawPolygonChart($Corners,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/2,"NoBorder"=>TRUE,"Threshold"=>$Threshold)); + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + + $WayPoints = ""; + } + else + $WayPoints[] = array($X,$Y-.5); /* -.5 for AA visual fix */ + + $X = $X + $XStep; + } + $Area = $this->drawSpline($WayPoints,array("Force"=>$Force,"PathOnly"=>TRUE)); + + if ( $Area != "" ) + { + foreach ($Area as $key => $Points) + { + $Corners = ""; $Corners[] = $Area[$key][0]["X"]; $Corners[] = $YZero; + foreach($Points as $subKey => $Point) + { + if ( $subKey == count($Points)-1) { $Corners[] = $Point["X"]-1; } else { $Corners[] = $Point["X"]; } + $Corners[] = $Point["Y"]+1; + } + $Corners[] = $Points[$subKey]["X"]-1; $Corners[] = $YZero; + + $this->drawPolygonChart($Corners,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/2,"NoBorder"=>TRUE,"Threshold"=>$Threshold)); + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $WayPoints = ""; + $Force = $YStep / 5; + + if ( !$AroundZero ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues ) + $this->drawText($X+$DisplayOffset,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + + if ( $X == VOID ) + { + $Area = $this->drawSpline($WayPoints,array("Force"=>$Force,"PathOnly"=>TRUE)); + + if ( $Area != "" ) + { + foreach ($Area as $key => $Points) + { + $Corners = ""; $Corners[] = $YZero; $Corners[] = $Area[$key][0]["Y"]; + foreach($Points as $subKey => $Point) + { + if ( $subKey == count($Points)-1) { $Corners[] = $Point["X"]-1; } else { $Corners[] = $Point["X"]; } + $Corners[] = $Point["Y"]; + } + $Corners[] = $YZero; $Corners[] = $Points[$subKey]["Y"]-1; + + $this->drawPolygonChart($Corners,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/2,"NoBorder"=>TRUE,"Threshold"=>$Threshold)); + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + + $WayPoints = ""; + } + else + $WayPoints[] = array($X,$Y); + + $Y = $Y + $YStep; + } + $Area = $this->drawSpline($WayPoints,array("Force"=>$Force,"PathOnly"=>TRUE)); + + if ( $Area != "" ) + { + foreach ($Area as $key => $Points) + { + $Corners = ""; $Corners[] = $YZero; $Corners[] = $Area[$key][0]["Y"]; + foreach($Points as $subKey => $Point) + { + if ( $subKey == count($Points)-1) { $Corners[] = $Point["X"]-1; } else { $Corners[] = $Point["X"]; } + $Corners[] = $Point["Y"]; + } + $Corners[] = $YZero; $Corners[] = $Points[$subKey]["Y"]-1; + + $this->drawPolygonChart($Corners,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/2,"NoBorder"=>TRUE,"Threshold"=>$Threshold)); + } + $this->drawSpline($WayPoints,array("Force"=>$Force,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + + } + } + } + } + + /* Draw a line chart */ + function drawLineChart($Format=NULL) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : TRUE; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : NULL; + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : NULL; + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : NULL; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + $ForceColor = isset($Format["ForceColor"]) ? $Format["ForceColor"] : FALSE; + $ForceR = isset($Format["ForceR"]) ? $Format["ForceR"] : 0; + $ForceG = isset($Format["ForceG"]) ? $Format["ForceG"] : 0; + $ForceB = isset($Format["ForceB"]) ? $Format["ForceB"] : 0; + $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : 100; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + if ( $ForceColor ) + { $R = $ForceR; $G = $ForceG; $B = $ForceB; $Alpha = $ForceAlpha; } + + if ( $BreakR == NULL ) + $BreakSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks,"Weight"=>$Weight); + else + $BreakSettings = array("R"=>$BreakR,"G"=>$BreakG,"B"=>$BreakB,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks,"Weight"=>$Weight); + + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $Serie["Data"][$Key] > 0 ) { $Align = TEXT_ALIGN_BOTTOMMIDDLE; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_TOPMIDDLE; $Offset = -$DisplayOffset; } + $this->drawText($X,$Y-$Offset-$Weight,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align)); + } + + if ( $RecordImageMap && $Y != VOID ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Y != VOID && $LastX != NULL && $LastY != NULL ) + $this->drawLine($LastX,$LastY,$X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid ) + { $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); $LastGoodY = NULL; } + + if ( $Y != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $Y == VOID ) { $Y = NULL; } + + $LastX = $X; $LastY = $Y; + $X = $X + $XStep; + } + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { $this->drawText($X+$DisplayOffset+$Weight,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); } + + if ( $RecordImageMap && $X != VOID ) { $this->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $X != VOID && $LastX != NULL && $LastY != NULL ) + $this->drawLine($LastX,$LastY,$X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $X != VOID && $LastX == NULL && $LastGoodY != NULL && !$BreakVoid ) + { $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); $LastGoodY = NULL; } + + if ( $X != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $X == VOID ) { $X = NULL; } + + $LastX = $X; $LastY = $Y; + $Y = $Y + $YStep; + } + } + } + } + } + + /* Draw a line chart */ + function drawZoneChart($SerieA,$SerieB,$Format=NULL) + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 150; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 150; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 150; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 50; + $LineTicks = isset($Format["LineTicks"]) ? $Format["LineTicks"] : 1; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 150; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 150; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 150; + $AreaAlpha = isset($Format["AreaAlpha"]) ? $Format["AreaAlpha"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + if ( !isset($Data["Series"][$SerieA]["Data"]) || !isset($Data["Series"][$SerieB]["Data"]) ) { return(0); } + $SerieAData = $Data["Series"][$SerieA]["Data"]; + $SerieBData = $Data["Series"][$SerieB]["Data"]; + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArrayA = $this->scaleComputeY($SerieAData,array("AxisID"=>$AxisID)); + $PosArrayB = $this->scaleComputeY($SerieBData,array("AxisID"=>$AxisID)); + if ( count($PosArrayA) != count($PosArrayB) ) { return(0); } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $LastX = NULL; $LastY = NULL; + + $LastX = NULL; $LastY1 = NULL; $LastY2 = NULL; + $BoundsA = ""; $BoundsB = ""; + foreach($PosArrayA as $Key => $Y1) + { + $Y2 = $PosArrayB[$Key]; + + $BoundsA[] = $X; $BoundsA[] = $Y1; + $BoundsB[] = $X; $BoundsB[] = $Y2; + + $LastX = $X; + $LastY1 = $Y1; $LastY2 = $Y2; + + $X = $X + $XStep; + } + $Bounds = array_merge($BoundsA,$this->reversePlots($BoundsB)); + $this->drawPolygonChart($Bounds,array("R"=>$AreaR,"G"=>$AreaG,"B"=>$AreaB,"Alpha"=>$AreaAlpha)); + + for($i=0;$i<=count($BoundsA)-4;$i=$i+2) + { + $this->drawLine($BoundsA[$i],$BoundsA[$i+1],$BoundsA[$i+2],$BoundsA[$i+3],array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha,"Ticks"=>$LineTicks)); + $this->drawLine($BoundsB[$i],$BoundsB[$i+1],$BoundsB[$i+2],$BoundsB[$i+3],array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha,"Ticks"=>$LineTicks)); + } + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $LastX = NULL; $LastY = NULL; + + $LastY = NULL; $LastX1 = NULL; $LastX2 = NULL; + $BoundsA = ""; $BoundsB = ""; + foreach($PosArrayA as $Key => $X1) + { + $X2 = $PosArrayB[$Key]; + + $BoundsA[] = $X1; $BoundsA[] = $Y; + $BoundsB[] = $X2; $BoundsB[] = $Y; + + $LastY = $Y; + $LastX1 = $X1; $LastX2 = $X2; + + $Y = $Y + $YStep; + } + $Bounds = array_merge($BoundsA,$this->reversePlots($BoundsB)); + $this->drawPolygonChart($Bounds,array("R"=>$AreaR,"G"=>$AreaG,"B"=>$AreaB,"Alpha"=>$AreaAlpha)); + + for($i=0;$i<=count($BoundsA)-4;$i=$i+2) + { + $this->drawLine($BoundsA[$i],$BoundsA[$i+1],$BoundsA[$i+2],$BoundsA[$i+3],array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha,"Ticks"=>$LineTicks)); + $this->drawLine($BoundsB[$i],$BoundsB[$i+1],$BoundsB[$i+2],$BoundsB[$i+3],array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha,"Ticks"=>$LineTicks)); + } + } + } + + /* Draw a step chart */ + function drawStepChart($Format=NULL) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : FALSE; + $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : TRUE; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : NULL; + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : NULL; + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : NULL; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] :FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + if ( $BreakR == NULL ) + $BreakSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks,"Weight"=>$Weight); + else + $BreakSettings = array("R"=>$BreakR,"G"=>$BreakG,"B"=>$BreakB,"Alpha"=>$Alpha,"Ticks"=>$VoidTicks,"Weight"=>$Weight); + + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight); + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $Init = FALSE; + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $Y <= $LastY ) { $Align = TEXT_ALIGN_BOTTOMMIDDLE; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_TOPMIDDLE; $Offset = -$DisplayOffset; } + $this->drawText($X,$Y-$Offset-$Weight,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align)); + } + + if ( $Y != VOID && $LastX != NULL && $LastY != NULL ) + { + $this->drawLine($LastX,$LastY,$X,$LastY,$Color); + $this->drawLine($X,$LastY,$X,$Y,$Color); + if ( $ReCenter && $X+$XStep < $this->GraphAreaX2 - $XMargin ) + { + $this->drawLine($X,$Y,$X+$XStep,$Y,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X-$ImageMapPlotSize).",".floor($Y-$ImageMapPlotSize).",".floor($X+$XStep+$ImageMapPlotSize).",".floor($Y+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + else + { if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastX-$ImageMapPlotSize).",".floor($LastY-$ImageMapPlotSize).",".floor($X+$ImageMapPlotSize).",".floor($LastY+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } } + } + + if ( $Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid ) + { + if ( $ReCenter ) + { + $this->drawLine($LastGoodX+$XStep,$LastGoodY,$X,$LastGoodY,$BreakSettings); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastGoodX+$XStep-$ImageMapPlotSize).",".floor($LastGoodY-$ImageMapPlotSize).",".floor($X+$ImageMapPlotSize).",".floor($LastGoodY+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + else + { + $this->drawLine($LastGoodX,$LastGoodY,$X,$LastGoodY,$BreakSettings); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastGoodX-$ImageMapPlotSize).",".floor($LastGoodY-$ImageMapPlotSize).",".floor($X+$ImageMapPlotSize).",".floor($LastGoodY+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + + $this->drawLine($X,$LastGoodY,$X,$Y,$BreakSettings); + $LastGoodY = NULL; + } + elseif( !$BreakVoid && $LastGoodY == NULL && $Y != VOID ) + { + $this->drawLine($this->GraphAreaX1 + $XMargin,$Y,$X,$Y,$BreakSettings); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($this->GraphAreaX1+$XMargin-$ImageMapPlotSize).",".floor($Y-$ImageMapPlotSize).",".floor($X+$ImageMapPlotSize).",".floor($Y+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + + if ( $Y != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $Y == VOID ) { $Y = NULL; } + + if ( !$Init && $ReCenter ) { $X = $X - $XStep/2; $Init = TRUE; } + $LastX = $X; $LastY = $Y; + if ( $LastX < $this->GraphAreaX1 + $XMargin ) { $LastX = $this->GraphAreaX1 + $XMargin; } + $X = $X + $XStep; + } + if ( $ReCenter ) + { + $this->drawLine($LastX,$LastY,$this->GraphAreaX2 - $XMargin,$LastY,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastX-$ImageMapPlotSize).",".floor($LastY-$ImageMapPlotSize).",".floor($this->GraphAreaX2-$XMargin+$ImageMapPlotSize).",".floor($LastY+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $Init = FALSE; + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $X >= $LastX ) { $Align = TEXT_ALIGN_MIDDLELEFT; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_MIDDLERIGHT; $Offset = -$DisplayOffset; } + $this->drawText($X+$Offset+$Weight,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align)); + } + + if ( $X != VOID && $LastX != NULL && $LastY != NULL ) + { + $this->drawLine($LastX,$LastY,$LastX,$Y,$Color); + $this->drawLine($LastX,$Y,$X,$Y,$Color); + + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastX-$ImageMapPlotSize).",".floor($LastY-$ImageMapPlotSize).",".floor($LastX+$XStep+$ImageMapPlotSize).",".floor($Y+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + + if ( $X != VOID && $LastX == NULL && $LastGoodY != NULL && !$BreakVoid ) + { + $this->drawLine($LastGoodX,$LastGoodY,$LastGoodX,$LastGoodY+$YStep,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastGoodX-$ImageMapPlotSize).",".floor($LastGoodY-$ImageMapPlotSize).",".floor($LastGoodX+$ImageMapPlotSize).",".floor($LastGoodY+$YStep+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + $this->drawLine($LastGoodX,$LastGoodY+$YStep,$LastGoodX,$Y,$BreakSettings); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastGoodX-$ImageMapPlotSize).",".floor($LastGoodY+$YStep-$ImageMapPlotSize).",".floor($LastGoodX+$ImageMapPlotSize).",".floor($YStep+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + $this->drawLine($LastGoodX,$Y,$X,$Y,$BreakSettings); + $LastGoodY = NULL; + } + elseif ( $X != VOID && $LastGoodY == NULL && !$BreakVoid ) + { + $this->drawLine($X,$this->GraphAreaY1 + $XMargin,$X,$Y,$BreakSettings); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X-$ImageMapPlotSize).",".floor($this->GraphAreaY1+$XMargin-$ImageMapPlotSize).",".floor($X+$ImageMapPlotSize).",".floor($Y+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + + if ( $X != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $X == VOID ) { $X = NULL; } + + if ( !$Init && $ReCenter ) { $Y = $Y - $YStep/2; $Init = TRUE; } + $LastX = $X; $LastY = $Y; + if ( $LastY < $this->GraphAreaY1 + $XMargin ) { $LastY = $this->GraphAreaY1 + $XMargin; } + $Y = $Y + $YStep; + } + if ( $ReCenter ) + { + $this->drawLine($LastX,$LastY,$LastX,$this->GraphAreaY2 - $XMargin,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($LastX-$ImageMapPlotSize).",".floor($LastY-$ImageMapPlotSize).",".floor($LastX+$ImageMapPlotSize).",".floor($this->GraphAreaY2-$XMargin+$ImageMapPlotSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + } + } + } + } + + /* Draw a step chart */ + function drawFilledStepChart($Format=NULL) + { + $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : TRUE; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] :FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : NULL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : TRUE; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + if ( $ForceTransparency != NULL ) { $Color["Alpha"] = $ForceTransparency; } else { $Color["Alpha"] = $Alpha; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero < $this->GraphAreaY1+1 ) { $YZero = $this->GraphAreaY1+1; } + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !$AroundZero ) { $YZero = $this->GraphAreaY2-1; } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $Points = ""; $Init = FALSE; + foreach($PosArray as $Key => $Y) + { + if ( $Y == VOID && $LastX != NULL && $LastY != NULL && $Points !="" ) + { + $Points[] = $LastX; $Points[] = $LastY; + $Points[] = $X; $Points[] = $LastY; + $Points[] = $X; $Points[] = $YZero; + $this->drawPolygon($Points,$Color); + $Points = ""; + } + + if ( $Y != VOID && $LastX != NULL && $LastY != NULL ) + { + if ( $Points == "") { $Points[] = $LastX; $Points[] = $YZero; } + $Points[] = $LastX; $Points[] = $LastY; + $Points[] = $X; $Points[] = $LastY; + $Points[] = $X; $Points[] = $Y; + } + + if ( $Y != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $Y == VOID ) { $Y = NULL; } + + if ( !$Init && $ReCenter ) { $X = $X - $XStep/2; $Init = TRUE; } + $LastX = $X; $LastY = $Y; + if ( $LastX < $this->GraphAreaX1 + $XMargin ) { $LastX = $this->GraphAreaX1 + $XMargin; } + $X = $X + $XStep; + } + + if ( $ReCenter ) + { + $Points[] = $LastX+$XStep/2; $Points[] = $LastY; + $Points[] = $LastX+$XStep/2; $Points[] = $YZero; + } + else + { $Points[] = $LastX; $Points[] = $YZero; } + + $this->drawPolygon($Points,$Color); + } + else + { + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $LastGoodY = NULL; $LastGoodX = NULL; $Points = ""; + foreach($PosArray as $Key => $X) + { + if ( $X == VOID && $LastX != NULL && $LastY != NULL && $Points !="" ) + { + $Points[] = $LastX; $Points[] = $LastY; + $Points[] = $LastX; $Points[] = $Y; + $Points[] = $YZero; $Points[] = $Y; + $this->drawPolygon($Points,$Color); + $Points = ""; + } + + if ( $X != VOID && $LastX != NULL && $LastY != NULL ) + { + if ( $Points == "") { $Points[] = $YZero; $Points[] = $LastY; } + $Points[] = $LastX; $Points[] = $LastY; + $Points[] = $LastX; $Points[] = $Y; + $Points[] = $X; $Points[] = $Y; + } + + if ( $X != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $X == VOID ) { $X = NULL; } + + if ( $LastX == NULL && $ReCenter ) { $Y = $Y - $YStep/2; } + $LastX = $X; $LastY = $Y; + if ( $LastY < $this->GraphAreaY1 + $XMargin ) { $LastY = $this->GraphAreaY1 + $XMargin; } + $Y = $Y + $YStep; + } + + if ( $ReCenter ) + { + $Points[] = $LastX; $Points[] = $LastY+$YStep/2; + $Points[] = $YZero; $Points[] = $LastY+$YStep/2; + } + else + { $Points[] = $YZero; $Points[] = $LastY; } + + $this->drawPolygon($Points,$Color); + } + } + } + } + + /* Draw an area chart */ + function drawAreaChart($Format=NULL) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : 25; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : TRUE; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : NULL; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + if ( $Threshold != NULL ) + { + foreach($Threshold as $Key => $Params) + { + $Threshold[$Key]["MinX"] = $this->scaleComputeY($Params["Min"],array("AxisID"=>$Serie["Axis"])); + $Threshold[$Key]["MaxX"] = $this->scaleComputeY($Params["Max"],array("AxisID"=>$Serie["Axis"])); + } + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + + $Areas = ""; $AreaID = 0; + $Areas[$AreaID][] = $this->GraphAreaX1 + $XMargin; + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaY2-1; } + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $Y) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $Serie["Data"][$Key] > 0 ) { $Align = TEXT_ALIGN_BOTTOMMIDDLE; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_TOPMIDDLE; $Offset = -$DisplayOffset; } + $this->drawText($X,$Y-$Offset,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align)); + } + + if ( $Y == VOID && isset($Areas[$AreaID]) ) + { + if($LastX == NULL) + { $Areas[$AreaID][] = $X; } + else + { $Areas[$AreaID][] = $LastX; } + + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaY2-1; } + $AreaID++; + } + elseif ($Y != VOID) + { + if ( !isset($Areas[$AreaID]) ) + { + $Areas[$AreaID][] = $X; + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaY2-1; } + } + + $Areas[$AreaID][] = $X; + $Areas[$AreaID][] = $Y; + } + + $LastX = $X; + $X = $X + $XStep; + } + $Areas[$AreaID][] = $LastX; + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaY2-1; } + + /* Handle shadows in the areas */ + if ( $this->Shadow ) + { + $ShadowArea = ""; + foreach($Areas as $Key => $Points) + { + $ShadowArea[$Key] = ""; + foreach($Points as $Key2 => $Value) + { + if ( $Key2 % 2 == 0 ) + { $ShadowArea[$Key][] = $Value + $this->ShadowX; } + else + { $ShadowArea[$Key][] = $Value + $this->ShadowY; } + } + } + + foreach($ShadowArea as $Key => $Points) + $this->drawPolygonChart($Points,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + } + + $Alpha = $ForceTransparency != NULL ? $ForceTransparency : $Alpha; + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Threshold"=>$Threshold); + + foreach($Areas as $Key => $Points) + $this->drawPolygonChart($Points,$Color); + } + else + { + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + + $Areas = ""; $AreaID = 0; + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaX1+1; } + $Areas[$AreaID][] = $this->GraphAreaY1 + $XMargin; + + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; $LastX = NULL; $LastY = NULL; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $X) + { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $Serie["Data"][$Key] > 0 ) { $Align = TEXT_ALIGN_BOTTOMMIDDLE; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_TOPMIDDLE; $Offset = -$DisplayOffset; } + $this->drawText($X+$Offset,$Y,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align)); + } + + if ( $X == VOID && isset($Areas[$AreaID]) ) + { + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaX1+1; } + + if($LastY == NULL) + { $Areas[$AreaID][] = $Y; } + else + { $Areas[$AreaID][] = $LastY; } + + $AreaID++; + } + elseif ($X != VOID) + { + if ( !isset($Areas[$AreaID]) ) + { + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaX1+1; } + $Areas[$AreaID][] = $Y; + } + + $Areas[$AreaID][] = $X; + $Areas[$AreaID][] = $Y; + } + + $LastX = $X; $LastY = $Y; + $Y = $Y + $YStep; + } + if ( $AroundZero ) { $Areas[$AreaID][] = $YZero; } else { $Areas[$AreaID][] = $this->GraphAreaX1+1; } + $Areas[$AreaID][] = $LastY; + + /* Handle shadows in the areas */ + if ( $this->Shadow ) + { + $ShadowArea = ""; + foreach($Areas as $Key => $Points) + { + $ShadowArea[$Key] = ""; + foreach($Points as $Key2 => $Value) + { + if ( $Key2 % 2 == 0 ) + { $ShadowArea[$Key][] = $Value + $this->ShadowX; } + else + { $ShadowArea[$Key][] = $Value + $this->ShadowY; } + } + } + + foreach($ShadowArea as $Key => $Points) + $this->drawPolygonChart($Points,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + } + + $Alpha = $ForceTransparency != NULL ? $ForceTransparency : $Alpha; + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Threshold"=>$Threshold); + + foreach($Areas as $Key => $Points) + $this->drawPolygonChart($Points,$Color); + } + } + } + } + + + /* Draw a bar chart */ + function drawBarChart($Format=NULL) + { + $Floating0Serie = isset($Format["Floating0Serie"]) ? $Format["Floating0Serie"] : NULL; + $Floating0Value = isset($Format["Floating0Value"]) ? $Format["Floating0Value"] : NULL; + $Draw0Line = isset($Format["Draw0Line"]) ? $Format["Draw0Line"] : FALSE; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOrientation = isset($Format["DisplayOrientation"]) ? $Format["DisplayOrientation"] : ORIENTATION_HORIZONTAL; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayFont = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontName; + $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; + $DisplayPos = isset($Format["DisplayPos"]) ? $Format["DisplayPos"] : LABEL_POS_OUTSIDE; + $DisplayShadow = isset($Format["DisplayShadow"]) ? $Format["DisplayShadow"] : TRUE; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : TRUE; + $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; + $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : FALSE; + $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : FALSE; + $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; + $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; + $TxtMargin = isset($Format["TxtMargin"]) ? $Format["TxtMargin"] : 6; + $OverrideColors = isset($Format["OverrideColors"]) ? $Format["OverrideColors"] : NULL; + $OverrideSurrounding = isset($Format["OverrideSurrounding"]) ? $Format["OverrideSurrounding"] : 30; + $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : NULL; + $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; + $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; + $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( $OverrideColors != NULL ) + { + $OverrideColors = $this->validatePalette($OverrideColors,$OverrideSurrounding); + $this->DataSet->saveExtendedData("Palette",$OverrideColors); + } + + $RestoreShadow = $this->Shadow; + + $SeriesCount = $this->countDrawableSeries(); + $CurrentSerie = 0; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = $R; $DisplayG = $G; $DisplayB = $B; } + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + if ( $InnerSurrounding != NULL ) { $InnerBorderR = $R+$InnerSurrounding; $InnerBorderG = $G+$InnerSurrounding; $InnerBorderB = $B+$InnerSurrounding; } + if ( $InnerBorderR == -1 ) { $InnerColor = NULL; } else { $InnerColor = array("R"=>$InnerBorderR,"G"=>$InnerBorderG,"B"=>$InnerBorderB); } + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB); + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + if ( $Floating0Value != NULL ) + { $YZero = $this->scaleComputeY($Floating0Value,array("AxisID"=>$Serie["Axis"])); } + else + { $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero < $this->GraphAreaY1+1 ) { $YZero = $this->GraphAreaY1+1; } + + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; + + if ( $AroundZero ) { $Y1 = $YZero; } else { $Y1 = $this->GraphAreaY2-1; } + if ( $XDivs == 0 ) { $XSize = ($this->GraphAreaX2-$this->GraphAreaX1)/($SeriesCount+$Interleave); } else { $XSize = ($XStep / ($SeriesCount+$Interleave) ); } + + $XOffset = -($XSize*$SeriesCount)/2 + $CurrentSerie * $XSize; + if ( $X + $XOffset <= $this->GraphAreaX1 ) { $XOffset = $this->GraphAreaX1 - $X + 1 ; } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $XOffset + $XSize / 2; + + if ( $Rounded || $BorderR != -1) { $XSpace = 1; } else { $XSpace = 0; } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $ID = 0; + foreach($PosArray as $Key => $Y2) + { + if ( $Floating0Serie != NULL ) + { + if ( isset($Data["Series"][$Floating0Serie]["Data"][$Key]) ) + { $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; } + else + { $Value = 0; } + + $YZero = $this->scaleComputeY($Value,array("AxisID"=>$Serie["Axis"])); + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero < $this->GraphAreaY1+1 ) { $YZero = $this->GraphAreaY1+1; } + + if ( $AroundZero ) { $Y1 = $YZero; } else { $Y1 = $this->GraphAreaY2-1; } + } + + if ( $OverrideColors != NULL ) + { if ( isset($OverrideColors[$ID]) ) { $Color = array("R"=>$OverrideColors[$ID]["R"],"G"=>$OverrideColors[$ID]["G"],"B"=>$OverrideColors[$ID]["B"],"Alpha"=>$OverrideColors[$ID]["Alpha"],"BorderR"=>$OverrideColors[$ID]["BorderR"],"BorderG"=>$OverrideColors[$ID]["BorderG"],"BorderB"=>$OverrideColors[$ID]["BorderB"]); } else { $Color = $this->getRandomColor(); } } + + if ( $Y2 != VOID ) + { + $BarHeight = $Y1 - $Y2; + + if ( $Serie["Data"][$Key] == 0 ) + { + $this->drawLine($X+$XOffset+$XSpace,$Y1,$X+$XOffset+$XSize-$XSpace,$Y1,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X+$XOffset+$XSpace).",".floor($Y1-1).",".floor($X+$XOffset+$XSize-$XSpace).",".floor($Y1+1),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + else + { + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X+$XOffset+$XSpace).",".floor($Y1).",".floor($X+$XOffset+$XSize-$XSpace).",".floor($Y2),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Rounded ) + $this->drawRoundedFilledRectangle($X+$XOffset+$XSpace,$Y1,$X+$XOffset+$XSize-$XSpace,$Y2,$RoundRadius,$Color); + else + { + $this->drawFilledRectangle($X+$XOffset+$XSpace,$Y1,$X+$XOffset+$XSize-$XSpace,$Y2,$Color); + + if ( $InnerColor != NULL ) { $this->drawRectangle($X+$XOffset+$XSpace+1,min($Y1,$Y2)+1,$X+$XOffset+$XSize-$XSpace-1,max($Y1,$Y2)-1,$InnerColor); } + + if ( $Gradient ) + { + $this->Shadow = FALSE; + + if ( $GradientMode == GRADIENT_SIMPLE ) + { + if ( $Serie["Data"][$Key] >= 0 ) + $GradienColor = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + else + $GradienColor = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + + $this->drawGradientArea($X+$XOffset+$XSpace,$Y1,$X+$XOffset+$XSize-$XSpace,$Y2,DIRECTION_VERTICAL,$GradienColor); + } + elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) + { + $GradienColor1 = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + $GradienColor2 = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $XSpan = floor($XSize / 3); + + $this->drawGradientArea($X+$XOffset+$XSpace,$Y1,$X+$XOffset+$XSpan-$XSpace,$Y2,DIRECTION_HORIZONTAL,$GradienColor1); + $this->drawGradientArea($X+$XOffset+$XSpan+$XSpace,$Y1,$X+$XOffset+$XSize-$XSpace,$Y2,DIRECTION_HORIZONTAL,$GradienColor2); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $Draw0Line ) + { + $Line0Color = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20); + + if ( abs($Y1 - $Y2) > 3 ) { $Line0Width = 3; } else { $Line0Width = 1; } + if ( $Y1 - $Y2 < 0 ) { $Line0Width = -$Line0Width; } + + $this->drawFilledRectangle($X+$XOffset+$XSpace,floor($Y1),$X+$XOffset+$XSize-$XSpace,floor($Y1)-$Line0Width,$Line0Color); + $this->drawLine($X+$XOffset+$XSpace,floor($Y1),$X+$XOffset+$XSize-$XSpace,floor($Y1),$Line0Color); + } + } + + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $DisplayShadow ) { $this->Shadow = TRUE; } + + $Caption = $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,90,$Caption); + $TxtHeight = $TxtPos[0]["Y"] - $TxtPos[1]["Y"] + $TxtMargin; + + if ( $DisplayPos == LABEL_POS_INSIDE && abs($TxtHeight) < abs($BarHeight) ) + { + $CenterX = (($X+$XOffset+$XSize-$XSpace)-($X+$XOffset+$XSpace))/2 + $X+$XOffset+$XSpace; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $this->drawText($CenterX,$CenterY,$Caption,array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize,"Angle"=>90)); + } + else + { + if ( $Serie["Data"][$Key] >= 0 ) { $Align = TEXT_ALIGN_BOTTOMMIDDLE; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_TOPMIDDLE; $Offset = -$DisplayOffset; } + $this->drawText($X+$XOffset+$XSize/2,$Y2-$Offset,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align,"FontSize"=>$DisplaySize)); + } + + $this->Shadow = $RestoreShadow; + } + } + + $X = $X + $XStep; + $ID++; + } + } + else + { + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + + if ( $XDivs == 0 ) { $YStep = 0; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + + $Y = $this->GraphAreaY1 + $XMargin; + + if ( $AroundZero ) { $X1 = $YZero; } else { $X1 = $this->GraphAreaX1+1; } + if ( $XDivs == 0 ) { $YSize = ($this->GraphAreaY2-$this->GraphAreaY1)/($SeriesCount+$Interleave); } else { $YSize = ($YStep / ($SeriesCount+$Interleave) ); } + + $YOffset = -($YSize*$SeriesCount)/2 + $CurrentSerie * $YSize; + if ( $Y + $YOffset <= $this->GraphAreaY1 ) { $YOffset = $this->GraphAreaY1 - $Y + 1 ; } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $YOffset + $YSize / 2; + + if ( $Rounded || $BorderR != -1 ) { $YSpace = 1; } else { $YSpace = 0; } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $ID = 0 ; + foreach($PosArray as $Key => $X2) + { + if ( $Floating0Serie != NULL ) + { + if ( isset($Data["Series"][$Floating0Serie]["Data"][$Key]) ) + $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; + else { $Value = 0; } + + $YZero = $this->scaleComputeY($Value,array("AxisID"=>$Serie["Axis"])); + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + if ( $AroundZero ) { $X1 = $YZero; } else { $X1 = $this->GraphAreaX1+1; } + } + + if ( $OverrideColors != NULL ) + { if ( isset($OverrideColors[$ID]) ) { $Color = array("R"=>$OverrideColors[$ID]["R"],"G"=>$OverrideColors[$ID]["G"],"B"=>$OverrideColors[$ID]["B"],"Alpha"=>$OverrideColors[$ID]["Alpha"],"BorderR"=>$OverrideColors[$ID]["BorderR"],"BorderG"=>$OverrideColors[$ID]["BorderG"],"BorderB"=>$OverrideColors[$ID]["BorderB"]); } else { $Color = $this->getRandomColor(); } } + + if ( $X2 != VOID ) + { + $BarWidth = $X2 - $X1; + + if ( $Serie["Data"][$Key] == 0 ) + { + $this->drawLine($X1,$Y+$YOffset+$YSpace,$X1,$Y+$YOffset+$YSize-$YSpace,$Color); + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X1-1).",".floor($Y+$YOffset+$YSpace).",".floor($X1+1).",".floor($Y+$YOffset+$YSize-$YSpace),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + } + else + { + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X1).",".floor($Y+$YOffset+$YSpace).",".floor($X2).",".floor($Y+$YOffset+$YSize-$YSpace),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Rounded ) + $this->drawRoundedFilledRectangle($X1+1,$Y+$YOffset+$YSpace,$X2,$Y+$YOffset+$YSize-$YSpace,$RoundRadius,$Color); + else + { + $this->drawFilledRectangle($X1,$Y+$YOffset+$YSpace,$X2,$Y+$YOffset+$YSize-$YSpace,$Color); + + if ( $InnerColor != NULL ) { $this->drawRectangle(min($X1,$X2)+1,$Y+$YOffset+$YSpace+1,max($X1,$X2)-1,$Y+$YOffset+$YSize-$YSpace-1,$InnerColor); } + + if ( $Gradient ) + { + $this->Shadow = FALSE; + + if ( $GradientMode == GRADIENT_SIMPLE ) + { + if ( $Serie["Data"][$Key] >= 0 ) + $GradienColor = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + else + $GradienColor = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + + $this->drawGradientArea($X1,$Y+$YOffset+$YSpace,$X2,$Y+$YOffset+$YSize-$YSpace,DIRECTION_HORIZONTAL,$GradienColor); + } + elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) + { + $GradienColor1 = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + $GradienColor2 = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $YSpan = floor($YSize / 3); + + $this->drawGradientArea($X1,$Y+$YOffset+$YSpace,$X2,$Y+$YOffset+$YSpan-$YSpace,DIRECTION_VERTICAL,$GradienColor1); + $this->drawGradientArea($X1,$Y+$YOffset+$YSpan,$X2,$Y+$YOffset+$YSize-$YSpace,DIRECTION_VERTICAL,$GradienColor2); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $Draw0Line ) + { + $Line0Color = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20); + + if ( abs($X1 - $X2) > 3 ) { $Line0Width = 3; } else { $Line0Width = 1; } + if ( $X2 - $X1 < 0 ) { $Line0Width = -$Line0Width; } + + $this->drawFilledRectangle(floor($X1),$Y+$YOffset+$YSpace,floor($X1)+$Line0Width,$Y+$YOffset+$YSize-$YSpace,$Line0Color); + $this->drawLine(floor($X1),$Y+$YOffset+$YSpace,floor($X1),$Y+$YOffset+$YSize-$YSpace,$Line0Color); + } + } + + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) + { + if ( $DisplayShadow ) { $this->Shadow = TRUE; } + + $Caption = $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"] + $TxtMargin; + + if ( $DisplayPos == LABEL_POS_INSIDE && abs($TxtWidth) < abs($BarWidth) ) + { + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = (($Y+$YOffset+$YSize-$YSpace)-($Y+$YOffset+$YSpace))/2 + ($Y+$YOffset+$YSpace); + + $this->drawText($CenterX,$CenterY,$Caption,array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize)); + } + else + { + if ( $Serie["Data"][$Key] >= 0 ) { $Align = TEXT_ALIGN_MIDDLELEFT; $Offset = $DisplayOffset; } else { $Align = TEXT_ALIGN_MIDDLERIGHT; $Offset = -$DisplayOffset; } + $this->drawText($X2+$Offset,$Y+$YOffset+$YSize/2,$Caption,array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align,"FontSize"=>$DisplaySize)); + } + + $this->Shadow = $RestoreShadow; + } + } + $Y = $Y + $YStep; + $ID++; + } + } + $CurrentSerie++; + } + } + } + + /* Draw a bar chart */ + function drawStackedBarChart($Format=NULL) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : FALSE; + $DisplayOrientation = isset($Format["DisplayOrientation"]) ? $Format["DisplayOrientation"] : ORIENTATION_AUTO; + $DisplayRound = isset($Format["DisplayRound"]) ? $Format["DisplayRound"] : 0; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayFont = isset($Format["DisplayFont"]) ? $Format["DisplayFont"] : $this->FontName; + $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; + $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : FALSE; + $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : FALSE; + $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; + $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; + $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : NULL; + $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; + $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; + $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $FontFactor = isset($Format["FontFactor"]) ? $Format["FontFactor"] : 8; + + $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $RestoreShadow = $this->Shadow; + + $LastX = ""; $LastY = ""; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { $DisplayR = 255; $DisplayG = 255; $DisplayB = 255; } + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + if ( $InnerSurrounding != NULL ) { $InnerBorderR = $R+$InnerSurrounding; $InnerBorderG = $G+$InnerSurrounding; $InnerBorderB = $B+$InnerSurrounding; } + if ( $InnerBorderR == -1 ) { $InnerColor = NULL; } else { $InnerColor = array("R"=>$InnerBorderR,"G"=>$InnerBorderG,"B"=>$InnerBorderB); } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { $SerieDescription = $Serie["Description"]; } else { $SerieDescription = $SerieName; } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"]),TRUE); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + $Color = array("TransCorner"=>TRUE,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; + + $XSize = ($XStep / (1+$Interleave) ); + $XOffset = -($XSize/2); + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $Height) + { + if ( $Height != VOID && $Serie["Data"][$Key] != 0 ) + { + if ( $Serie["Data"][$Key] > 0 ) { $Pos = "+"; } else { $Pos = "-"; } + + if ( !isset($LastY[$Key] ) ) { $LastY[$Key] = ""; } + if ( !isset($LastY[$Key][$Pos] ) ) { $LastY[$Key][$Pos] = $YZero; } + + $Y1 = $LastY[$Key][$Pos]; + $Y2 = $Y1 - $Height; + + if ( ($Rounded || $BorderR != -1) && ($Pos == "+" && $Y1 != $YZero) ) { $YSpaceUp = 1; } else { $YSpaceUp = 0; } + if ( ($Rounded || $BorderR != -1) && ($Pos == "-" && $Y1 != $YZero) ) { $YSpaceDown = 1; } else { $YSpaceDown = 0; } + + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X+$XOffset).",".floor($Y1-$YSpaceUp+$YSpaceDown).",".floor($X+$XOffset+$XSize).",".floor($Y2),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Rounded ) + $this->drawRoundedFilledRectangle($X+$XOffset,$Y1-$YSpaceUp+$YSpaceDown,$X+$XOffset+$XSize,$Y2,$RoundRadius,$Color); + else + { + $this->drawFilledRectangle($X+$XOffset,$Y1-$YSpaceUp+$YSpaceDown,$X+$XOffset+$XSize,$Y2,$Color); + + if ( $InnerColor != NULL ) { $RestoreShadow = $this->Shadow; $this->Shadow = FALSE; $this->drawRectangle(min($X+$XOffset+1,$X+$XOffset+$XSize),min($Y1-$YSpaceUp+$YSpaceDown,$Y2)+1,max($X+$XOffset+1,$X+$XOffset+$XSize)-1,max($Y1-$YSpaceUp+$YSpaceDown,$Y2)-1,$InnerColor); $this->Shadow = $RestoreShadow;} + + if ( $Gradient ) + { + $this->Shadow = FALSE; + + if ( $GradientMode == GRADIENT_SIMPLE ) + { + $GradientColor = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $this->drawGradientArea($X+$XOffset,$Y1-1-$YSpaceUp+$YSpaceDown,$X+$XOffset+$XSize,$Y2+1,DIRECTION_VERTICAL,$GradientColor); + } + elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) + { + $GradientColor1 = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + $GradientColor2 = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $XSpan = floor($XSize / 3); + + $this->drawGradientArea($X+$XOffset-.5,$Y1-.5-$YSpaceUp+$YSpaceDown,$X+$XOffset+$XSpan,$Y2+.5,DIRECTION_HORIZONTAL,$GradientColor1); + $this->drawGradientArea($X+$XSpan+$XOffset-.5,$Y1-.5-$YSpaceUp+$YSpaceDown,$X+$XOffset+$XSize,$Y2+.5,DIRECTION_HORIZONTAL,$GradientColor2); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $DisplayValues ) + { + $BarHeight = abs($Y2-$Y1)-2; + $BarWidth = $XSize+($XOffset/2)-$FontFactor; + + $Caption = $this->scaleFormat(round($Serie["Data"][$Key],$DisplayRound),$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); + $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); + + $XCenter = ( ($X+$XOffset+$XSize) - ($X+$XOffset) ) / 2 + $X+$XOffset; + $YCenter = ( ($Y2) - ($Y1-$YSpaceUp+$YSpaceDown) ) / 2 + $Y1-$YSpaceUp+$YSpaceDown; + + $Done = FALSE; + if ( $DisplayOrientation == ORIENTATION_HORIZONTAL || $DisplayOrientation == ORIENTATION_AUTO ) + { + if ( $TxtHeight < $BarHeight && $TxtWidth < $BarWidth ) + { + $this->drawText($XCenter,$YCenter,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize,"FontName"=>$DisplayFont)); + $Done = TRUE; + } + } + + if ( $DisplayOrientation == ORIENTATION_VERTICAL || ( $DisplayOrientation == ORIENTATION_AUTO && !$Done) ) + { + if ( $TxtHeight < $BarWidth && $TxtWidth < $BarHeight ) + $this->drawText($XCenter,$YCenter,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Angle"=>90,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize,"FontName"=>$DisplayFont)); + } + } + + $LastY[$Key][$Pos] = $Y2; + } + + $X = $X + $XStep; + } + } + else + { + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; + + $YSize = $YStep / (1+$Interleave); + $YOffset = -($YSize/2); + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + foreach($PosArray as $Key => $Width) + { + if ( $Width != VOID && $Serie["Data"][$Key] != 0 ) + { + if ( $Serie["Data"][$Key] > 0 ) { $Pos = "+"; } else { $Pos = "-"; } + + if ( !isset($LastX[$Key] ) ) { $LastX[$Key] = ""; } + if ( !isset($LastX[$Key][$Pos] ) ) { $LastX[$Key][$Pos] = $YZero; } + + $X1 = $LastX[$Key][$Pos]; + $X2 = $X1 + $Width; + + if ( ($Rounded || $BorderR != -1) && ($Pos == "+" && $X1 != $YZero) ) { $XSpaceLeft = 2; } else { $XSpaceLeft = 0; } + if ( ($Rounded || $BorderR != -1) && ($Pos == "-" && $X1 != $YZero) ) { $XSpaceRight = 2; } else { $XSpaceRight = 0; } + + if ( $RecordImageMap ) { $this->addToImageMap("RECT",floor($X1+$XSpaceLeft).",".floor($Y+$YOffset).",".floor($X2-$XSpaceRight).",".floor($Y+$YOffset+$YSize),$this->toHTMLColor($R,$G,$B),$SerieDescription,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit)); } + + if ( $Rounded ) + $this->drawRoundedFilledRectangle($X1+$XSpaceLeft,$Y+$YOffset,$X2-$XSpaceRight,$Y+$YOffset+$YSize,$RoundRadius,$Color); + else + { + $this->drawFilledRectangle($X1+$XSpaceLeft,$Y+$YOffset,$X2-$XSpaceRight,$Y+$YOffset+$YSize,$Color); + + if ( $InnerColor != NULL ) { $RestoreShadow = $this->Shadow; $this->Shadow = FALSE; $this->drawRectangle(min($X1+$XSpaceLeft,$X2-$XSpaceRight)+1,min($Y+$YOffset,$Y+$YOffset+$YSize)+1,max($X1+$XSpaceLeft,$X2-$XSpaceRight)-1,max($Y+$YOffset,$Y+$YOffset+$YSize)-1,$InnerColor); $this->Shadow = $RestoreShadow;} + + if ( $Gradient ) + { + $this->Shadow = FALSE; + + if ( $GradientMode == GRADIENT_SIMPLE ) + { + $GradientColor = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $this->drawGradientArea($X1+$XSpaceLeft,$Y+$YOffset,$X2-$XSpaceRight,$Y+$YOffset+$YSize,DIRECTION_HORIZONTAL,$GradientColor); + } + elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) + { + $GradientColor1 = array("StartR"=>$GradientEndR,"StartG"=>$GradientEndG,"StartB"=>$GradientEndB,"EndR"=>$GradientStartR,"EndG"=>$GradientStartG,"EndB"=>$GradientStartB,"Alpha"=>$GradientAlpha); + $GradientColor2 = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$GradientAlpha); + $YSpan = floor($YSize / 3); + + $this->drawGradientArea($X1+$XSpaceLeft,$Y+$YOffset,$X2-$XSpaceRight,$Y+$YOffset+$YSpan,DIRECTION_VERTICAL,$GradientColor1); + $this->drawGradientArea($X1+$XSpaceLeft,$Y+$YOffset+$YSpan,$X2-$XSpaceRight,$Y+$YOffset+$YSize,DIRECTION_VERTICAL,$GradientColor2); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $DisplayValues ) + { + $BarWidth = abs($X2-$X1)-$FontFactor; + $BarHeight = $YSize+($YOffset/2)-$FontFactor/2; + $Caption = $this->scaleFormat(round($Serie["Data"][$Key],$DisplayRound),$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); + $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); + + $XCenter = ( $X2 - $X1 ) / 2 + $X1; + $YCenter = ( ($Y+$YOffset+$YSize) - ($Y+$YOffset) ) / 2 + $Y+$YOffset; + + $Done = FALSE; + if ( $DisplayOrientation == ORIENTATION_HORIZONTAL || $DisplayOrientation == ORIENTATION_AUTO ) + { + if ( $TxtHeight < $BarHeight && $TxtWidth < $BarWidth ) + { + $this->drawText($XCenter,$YCenter,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize,"FontName"=>$DisplayFont)); + $Done = TRUE; + } + } + + if ( $DisplayOrientation == ORIENTATION_VERTICAL || ( $DisplayOrientation == ORIENTATION_AUTO && !$Done) ) + { + if ( $TxtHeight < $BarWidth && $TxtWidth < $BarHeight ) + $this->drawText($XCenter,$YCenter,$this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit),array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Angle"=>90,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontSize"=>$DisplaySize,"FontName"=>$DisplayFont)); + } + } + + $LastX[$Key][$Pos] = $X2; + } + + $Y = $Y + $YStep; + } + } + } + } + } + + /* Draw a stacked area chart */ + function drawStackedAreaChart($Format=NULL) + { + $DrawLine = isset($Format["DrawLine"]) ? $Format["DrawLine"] : FALSE; + $LineSurrounding = isset($Format["LineSurrounding"]) ? $Format["LineSurrounding"] : NULL; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : VOID; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : VOID; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : VOID; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 100; + $DrawPlot = isset($Format["DrawPlot"]) ? $Format["DrawPlot"] : FALSE; + $PlotRadius = isset($Format["PlotRadius"]) ? $Format["PlotRadius"] : 2; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : 1; + $PlotBorderSurrounding = isset($Format["PlotBorderSurrounding"]) ? $Format["PlotBorderSurrounding"] : NULL; + $PlotBorderR = isset($Format["PlotBorderR"]) ? $Format["PlotBorderR"] : 0; + $PlotBorderG = isset($Format["PlotBorderG"]) ? $Format["PlotBorderG"] : 0; + $PlotBorderB = isset($Format["PlotBorderB"]) ? $Format["PlotBorderB"] : 0; + $PlotBorderAlpha = isset($Format["PlotBorderAlpha"]) ? $Format["PlotBorderAlpha"] : 50; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : NULL; + + $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $RestoreShadow = $this->Shadow; + $this->Shadow = FALSE; + + /* Build the offset data series */ + $OffsetData = ""; + $OverallOffset = ""; + $SerieOrder = ""; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $SerieOrder[] = $SerieName; + + foreach($Serie["Data"] as $Key => $Value) + { + if ( $Value == VOID ) { $Value = 0; } + if ($Value >= 0) { $Sign = "+"; } else { $Sign = "-"; } + if ( !isset($OverallOffset[$Key]) || !isset($OverallOffset[$Key][$Sign]) ) { $OverallOffset[$Key][$Sign] = 0; } + + if ( $Sign == "+" ) + { $Data["Series"][$SerieName]["Data"][$Key] = $Value + $OverallOffset[$Key][$Sign]; } + else + { $Data["Series"][$SerieName]["Data"][$Key] = $Value - $OverallOffset[$Key][$Sign]; } + + $OverallOffset[$Key][$Sign] = $OverallOffset[$Key][$Sign] + abs($Value); + } + } + } + $SerieOrder = array_reverse($SerieOrder); + + $LastX = ""; $LastY = ""; + foreach($SerieOrder as $Key => $SerieName) + { + $Serie = $Data["Series"][$SerieName]; + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; + if ( $ForceTransparency != NULL ) { $Alpha = $ForceTransparency; } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + + if ( $LineSurrounding != NULL ) + $LineColor = array("R"=>$R+$LineSurrounding,"G"=>$G+$LineSurrounding,"B"=>$B+$LineSurrounding,"Alpha"=>$Alpha); + elseif ( $LineR != VOID ) + $LineColor = array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha); + else + $LineColor = $Color; + + if ( $PlotBorderSurrounding != NULL ) + $PlotBorderColor = array("R"=>$R+$PlotBorderSurrounding,"G"=>$G+$PlotBorderSurrounding,"B"=>$B+$PlotBorderSurrounding,"Alpha"=>$PlotBorderAlpha); + else + $PlotBorderColor = array("R"=>$PlotBorderR,"G"=>$PlotBorderG,"B"=>$PlotBorderB,"Alpha"=>$PlotBorderAlpha); + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"]),TRUE); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero < $this->GraphAreaY1+1 ) { $YZero = $this->GraphAreaY1+1; } + if ( $YZero > $this->GraphAreaY2-1 ) { $YZero = $this->GraphAreaY2-1; } + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $Plots = ""; $Plots[] = $X; $Plots[] = $YZero; + foreach($PosArray as $Key => $Height) + { + if ( $Height != VOID ) { $Plots[] = $X; $Plots[] = $YZero-$Height; } + $X = $X + $XStep; + } + $Plots[] = $X-$XStep; $Plots[] = $YZero; + + $this->drawPolygon($Plots,$Color); + + $this->Shadow = $RestoreShadow; + if ( $DrawLine ) { for($i=2; $i<=count($Plots)-6; $i=$i+2) { $this->drawLine($Plots[$i],$Plots[$i+1],$Plots[$i+2],$Plots[$i+3],$LineColor); } } + if ( $DrawPlot ) + { + for($i=2; $i<=count($Plots)-4; $i=$i+2) + { + if ( $PlotBorder != 0 ) + { $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius+$PlotBorder,$PlotBorderColor); } + + $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius,$Color); + } + } + $this->Shadow = FALSE; + } + elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + if ( $YZero < $this->GraphAreaX1+1 ) { $YZero = $this->GraphAreaX1+1; } + if ( $YZero > $this->GraphAreaX2-1 ) { $YZero = $this->GraphAreaX2-1; } + + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $Plots = ""; $Plots[] = $YZero; $Plots[] = $Y; + foreach($PosArray as $Key => $Height) + { + if ( $Height != VOID ) { $Plots[] = $YZero+$Height; $Plots[] = $Y; } + $Y = $Y + $YStep; + } + $Plots[] = $YZero; $Plots[] = $Y-$YStep; + + $this->drawPolygon($Plots,$Color); + + $this->Shadow = $RestoreShadow; + if ( $DrawLine ) { for($i=2; $i<=count($Plots)-6; $i=$i+2) { $this->drawLine($Plots[$i],$Plots[$i+1],$Plots[$i+2],$Plots[$i+3],$LineColor); } } + if ( $DrawPlot ) + { + for($i=2; $i<=count($Plots)-4; $i=$i+2) + { + if ( $PlotBorder != 0 ) + { $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius+$PlotBorder,$PlotBorderColor); } + + $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius,$Color); + } + } + $this->Shadow = FALSE; + } + } + } + $this->Shadow = $RestoreShadow; + } + + /* Returns a random color */ + function getRandomColor($Alpha=100) + { return(array("R"=>rand(0,255),"G"=>rand(0,255),"B"=>rand(0,255),"Alpha"=>$Alpha)); } + + /* Validate a palette */ + function validatePalette($Colors,$Surrounding=NULL) + { + $Result = ""; + + if ( !is_array($Colors) ) { return($this->getRandomColor()); } + + foreach($Colors as $Key => $Values) + { + if ( isset($Values["R"]) ) { $Result[$Key]["R"] = $Values["R"]; } else { $Result[$Key]["R"] = rand(0,255); } + if ( isset($Values["G"]) ) { $Result[$Key]["G"] = $Values["G"]; } else { $Result[$Key]["G"] = rand(0,255); } + if ( isset($Values["B"]) ) { $Result[$Key]["B"] = $Values["B"]; } else { $Result[$Key]["B"] = rand(0,255); } + if ( isset($Values["Alpha"]) ) { $Result[$Key]["Alpha"] = $Values["Alpha"]; } else { $Result[$Key]["Alpha"] = 100; } + + if ( $Surrounding != NULL ) + { + $Result[$Key]["BorderR"] = $Result[$Key]["R"] + $Surrounding; + $Result[$Key]["BorderG"] = $Result[$Key]["G"] + $Surrounding; + $Result[$Key]["BorderB"] = $Result[$Key]["B"] + $Surrounding; + } + else + { + if ( isset($Values["BorderR"]) ) { $Result[$Key]["BorderR"] = $Values["BorderR"]; } else { $Result[$Key]["BorderR"] = $Result[$Key]["R"]; } + if ( isset($Values["BorderG"]) ) { $Result[$Key]["BorderG"] = $Values["BorderG"]; } else { $Result[$Key]["BorderG"] = $Result[$Key]["G"]; } + if ( isset($Values["BorderB"]) ) { $Result[$Key]["BorderB"] = $Values["BorderB"]; } else { $Result[$Key]["BorderB"] = $Result[$Key]["B"]; } + if ( isset($Values["BorderAlpha"]) ) { $Result[$Key]["BorderAlpha"] = $Values["BorderAlpha"]; } else { $Result[$Key]["BorderAlpha"] = $Result[$Key]["Alpha"]; } + } + } + + return($Result); + } + + /* Draw the derivative chart associated to the data series */ + function drawDerivative($Format=NULL) + { + $Offset = isset($Format["Offset"]) ? $Format["Offset"] : 10; + $SerieSpacing = isset($Format["SerieSpacing"]) ? $Format["SerieSpacing"] : 3; + $DerivativeHeight = isset($Format["DerivativeHeight"]) ? $Format["DerivativeHeight"] : 4; + $ShadedSlopeBox = isset($Format["ShadedSlopeBox"]) ? $Format["ShadedSlopeBox"] : FALSE; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : TRUE; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 20; + $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : TRUE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : TRUE; + $CaptionHeight = isset($Format["CaptionHeight"]) ? $Format["CaptionHeight"] : 10; + $CaptionWidth = isset($Format["CaptionWidth"]) ? $Format["CaptionWidth"] : 20; + $CaptionMargin = isset($Format["CaptionMargin"]) ? $Format["CaptionMargin"] : 4; + $CaptionLine = isset($Format["CaptionLine"]) ? $Format["CaptionLine"] : FALSE; + $CaptionBox = isset($Format["CaptionBox"]) ? $Format["CaptionBox"] : FALSE; + $CaptionBorderR = isset($Format["CaptionBorderR"]) ? $Format["CaptionBorderR"] : 0; + $CaptionBorderG = isset($Format["CaptionBorderG"]) ? $Format["CaptionBorderG"] : 0; + $CaptionBorderB = isset($Format["CaptionBorderB"]) ? $Format["CaptionBorderB"] : 0; + $CaptionFillR = isset($Format["CaptionFillR"]) ? $Format["CaptionFillR"] : 255; + $CaptionFillG = isset($Format["CaptionFillG"]) ? $Format["CaptionFillG"] : 255; + $CaptionFillB = isset($Format["CaptionFillB"]) ? $Format["CaptionFillB"] : 255; + $CaptionFillAlpha = isset($Format["CaptionFillAlpha"]) ? $Format["CaptionFillAlpha"] : 80; + $PositiveSlopeStartR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 184; + $PositiveSlopeStartG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 234; + $PositiveSlopeStartB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 88; + $PositiveSlopeEndR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 239; + $PositiveSlopeEndG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 31; + $PositiveSlopeEndB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 36; + $NegativeSlopeStartR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 184; + $NegativeSlopeStartG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 234; + $NegativeSlopeStartB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 88; + $NegativeSlopeEndR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 67; + $NegativeSlopeEndG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 124; + $NegativeSlopeEndB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 227; + + $Data = $this->DataSet->getData(); + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + $YPos = $this->DataSet->Data["GraphArea"]["Y2"] + $Offset; + else + $XPos = $this->DataSet->Data["GraphArea"]["X2"] + $Offset; + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; $Alpha = $Serie["Color"]["Alpha"]; $Ticks = $Serie["Ticks"]; $Weight = $Serie["Weight"]; + + $AxisID = $Serie["Axis"]; + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $Caption ) + { + if ( $CaptionLine ) + { + $StartX = floor($this->GraphAreaX1-$CaptionWidth+$XMargin-$CaptionMargin); + $EndX = floor($this->GraphAreaX1-$CaptionMargin+$XMargin); + + $CaptionSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight); + if ( $CaptionBox ) { $this->drawFilledRectangle($StartX,$YPos,$EndX,$YPos+$CaptionHeight,array("R"=>$CaptionFillR,"G"=>$CaptionFillG,"B"=>$CaptionFillB,"BorderR"=>$CaptionBorderR,"BorderG"=>$CaptionBorderG,"BorderB"=>$CaptionBorderB,"Alpha"=>$CaptionFillAlpha)); } + $this->drawLine($StartX+2,$YPos+($CaptionHeight/2),$EndX-2,$YPos+($CaptionHeight/2),$CaptionSettings); + } + else + $this->drawFilledRectangle($this->GraphAreaX1-$CaptionWidth+$XMargin-$CaptionMargin,$YPos,$this->GraphAreaX1-$CaptionMargin+$XMargin,$YPos+$CaptionHeight,array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$CaptionBorderR,"BorderG"=>$CaptionBorderG,"BorderB"=>$CaptionBorderB)); + } + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; + + $TopY = $YPos + ($CaptionHeight/2) - ($DerivativeHeight/2); + $BottomY = $YPos + ($CaptionHeight/2) + ($DerivativeHeight/2); + + $StartX = floor($this->GraphAreaX1+$XMargin); + $EndX = floor($this->GraphAreaX2-$XMargin); + + if ( $DrawBackground ) { $this->drawFilledRectangle($StartX-1,$TopY-1,$EndX+1,$BottomY+1,array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha)); } + if ( $DrawBorder ) { $this->drawRectangle($StartX-1,$TopY-1,$EndX+1,$BottomY+1,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $RestoreShadow = $this->Shadow; + $this->Shadow = FALSE; + + /* Determine the Max slope index */ + $LastX = NULL; $LastY = NULL; $MinSlope = 0; $MaxSlope = 1; + foreach($PosArray as $Key => $Y) + { + if ( $Y != VOID && $LastX != NULL ) + { $Slope = ($LastY - $Y); if ( $Slope > $MaxSlope ) { $MaxSlope = $Slope; } if ( $Slope < $MinSlope ) { $MinSlope = $Slope; } } + + if ( $Y == VOID ) + { $LastX = NULL; $LastY = NULL; } + else + { $LastX = $X; $LastY = $Y; } + } + + $LastX = NULL; $LastY = NULL; $LastColor = NULL; + foreach($PosArray as $Key => $Y) + { + if ( $Y != VOID && $LastY != NULL ) + { + $Slope = ($LastY - $Y); + + if ( $Slope >= 0 ) + { + $SlopeIndex = (100 / $MaxSlope) * $Slope; + $R = (($PositiveSlopeEndR - $PositiveSlopeStartR)/100)*$SlopeIndex+$PositiveSlopeStartR; + $G = (($PositiveSlopeEndG - $PositiveSlopeStartG)/100)*$SlopeIndex+$PositiveSlopeStartG; + $B = (($PositiveSlopeEndB - $PositiveSlopeStartB)/100)*$SlopeIndex+$PositiveSlopeStartB; + } + elseif ( $Slope < 0 ) + { + $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); + $R = (($NegativeSlopeEndR - $NegativeSlopeStartR)/100)*$SlopeIndex+$NegativeSlopeStartR; + $G = (($NegativeSlopeEndG - $NegativeSlopeStartG)/100)*$SlopeIndex+$NegativeSlopeStartG; + $B = (($NegativeSlopeEndB - $NegativeSlopeStartB)/100)*$SlopeIndex+$NegativeSlopeStartB; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + + if ( $ShadedSlopeBox && $LastColor != NULL ) // && $Slope != 0 + { + $GradientSettings = array("StartR"=>$LastColor["R"],"StartG"=>$LastColor["G"],"StartB"=>$LastColor["B"],"EndR"=>$R,"EndG"=>$G,"EndB"=>$B); + $this->drawGradientArea($LastX,$TopY,$X,$BottomY,DIRECTION_HORIZONTAL,$GradientSettings); + } + elseif ( !$ShadedSlopeBox || $LastColor == NULL ) // || $Slope == 0 + $this->drawFilledRectangle(floor($LastX),$TopY,floor($X),$BottomY,$Color); + + $LastColor = $Color; + } + + if ( $Y == VOID ) + { $LastY = NULL; } + else + { $LastX = $X; $LastY = $Y; } + + $X = $X + $XStep; + } + + $YPos = $YPos + $CaptionHeight + $SerieSpacing; + } + else + { + if ( $Caption ) + { + $StartY = floor($this->GraphAreaY1-$CaptionWidth+$XMargin-$CaptionMargin); + $EndY = floor($this->GraphAreaY1-$CaptionMargin+$XMargin); + if ( $CaptionLine ) + { + $CaptionSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight); + if ( $CaptionBox ) { $this->drawFilledRectangle($XPos,$StartY,$XPos+$CaptionHeight,$EndY,array("R"=>$CaptionFillR,"G"=>$CaptionFillG,"B"=>$CaptionFillB,"BorderR"=>$CaptionBorderR,"BorderG"=>$CaptionBorderG,"BorderB"=>$CaptionBorderB,"Alpha"=>$CaptionFillAlpha)); } + $this->drawLine($XPos+($CaptionHeight/2),$StartY+2,$XPos+($CaptionHeight/2),$EndY-2,$CaptionSettings); + } + else + $this->drawFilledRectangle($XPos,$StartY,$XPos+$CaptionHeight,$EndY,array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$CaptionBorderR,"BorderG"=>$CaptionBorderG,"BorderB"=>$CaptionBorderB)); + } + + + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; + + $TopX = $XPos + ($CaptionHeight/2) - ($DerivativeHeight/2); + $BottomX = $XPos + ($CaptionHeight/2) + ($DerivativeHeight/2); + + $StartY = floor($this->GraphAreaY1+$XMargin); + $EndY = floor($this->GraphAreaY2-$XMargin); + + if ( $DrawBackground ) { $this->drawFilledRectangle($TopX-1,$StartY-1,$BottomX+1,$EndY+1,array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha)); } + if ( $DrawBorder ) { $this->drawRectangle($TopX-1,$StartY-1,$BottomX+1,$EndY+1,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + + $RestoreShadow = $this->Shadow; + $this->Shadow = FALSE; + + /* Determine the Max slope index */ + $LastX = NULL; $LastY = NULL; $MinSlope = 0; $MaxSlope = 1; + foreach($PosArray as $Key => $X) + { + if ( $X != VOID && $LastX != NULL ) + { $Slope = ($X - $LastX); if ( $Slope > $MaxSlope ) { $MaxSlope = $Slope; } if ( $Slope < $MinSlope ) { $MinSlope = $Slope; } } + + if ( $X == VOID ) + { $LastX = NULL; } + else + { $LastX = $X; } + } + + $LastX = NULL; $LastY = NULL; $LastColor = NULL; + foreach($PosArray as $Key => $X) + { + if ( $X != VOID && $LastX != NULL ) + { + $Slope = ($X - $LastX); + + if ( $Slope >= 0 ) + { + $SlopeIndex = (100 / $MaxSlope) * $Slope; + $R = (($PositiveSlopeEndR - $PositiveSlopeStartR)/100)*$SlopeIndex+$PositiveSlopeStartR; + $G = (($PositiveSlopeEndG - $PositiveSlopeStartG)/100)*$SlopeIndex+$PositiveSlopeStartG; + $B = (($PositiveSlopeEndB - $PositiveSlopeStartB)/100)*$SlopeIndex+$PositiveSlopeStartB; + } + elseif ( $Slope < 0 ) + { + $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); + $R = (($NegativeSlopeEndR - $NegativeSlopeStartR)/100)*$SlopeIndex+$NegativeSlopeStartR; + $G = (($NegativeSlopeEndG - $NegativeSlopeStartG)/100)*$SlopeIndex+$NegativeSlopeStartG; + $B = (($NegativeSlopeEndB - $NegativeSlopeStartB)/100)*$SlopeIndex+$NegativeSlopeStartB; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + + if ( $ShadedSlopeBox && $LastColor != NULL ) + { + $GradientSettings = array("StartR"=>$LastColor["R"],"StartG"=>$LastColor["G"],"StartB"=>$LastColor["B"],"EndR"=>$R,"EndG"=>$G,"EndB"=>$B); + + $this->drawGradientArea($TopX,$LastY,$BottomX,$Y,DIRECTION_VERTICAL,$GradientSettings); + } + elseif ( !$ShadedSlopeBox || $LastColor == NULL ) + $this->drawFilledRectangle($TopX,floor($LastY),$BottomX,floor($Y),$Color); + + $LastColor = $Color; + } + + if ( $X == VOID ) + { $LastX = NULL; } + else + { $LastX = $X; $LastY = $Y; } + + $Y = $Y + $XStep; + } + + $XPos = $XPos + $CaptionHeight + $SerieSpacing; + } + + $this->Shadow = $RestoreShadow; + } + } + } + + /* Draw the line of best fit */ + function drawBestFit($Format="") + { + $OverrideTicks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL; + $OverrideR = isset($Format["R"]) ? $Format["R"] : VOID; + $OverrideG = isset($Format["G"]) ? $Format["G"] : VOID; + $OverrideB = isset($Format["B"]) ? $Format["B"] : VOID; + $OverrideAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : VOID; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) + { + if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) + { + if ( $OverrideR != VOID && $OverrideG != VOID && $OverrideB != VOID ) { $R = $OverrideR; $G = $OverrideG; $B = $OverrideB; } else { $R = $Serie["Color"]["R"]; $G = $Serie["Color"]["G"]; $B = $Serie["Color"]["B"]; } + if ( $OverrideTicks == NULL ) { $Ticks = $Serie["Ticks"]; } else { $Ticks = $OverrideTicks; } + if ( $OverrideAlpha == VOID ) { $Alpha = $Serie["Color"]["Alpha"]; } else { $Alpha = $OverrideAlpha; } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks); + + $AxisID = $Serie["Axis"]; + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $Sxy = 0; $Sx = 0; $Sy = 0; $Sxx = 0; + foreach($PosArray as $Key => $Y) + { + if ( $Y != VOID ) + { + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $X; + $Sy = $Sy + $Y; + $Sxx = $Sxx + $X*$X; + } + + $X = $X + $XStep; + } + $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $X1 = $this->GraphAreaX1 + $XMargin; + $Y1 = $M * $X1 + $B; + $X2 = $this->GraphAreaX2 - $XMargin; + $Y2 = $M * $X2 + $B; + + if ( $Y1 < $this->GraphAreaY1 ) { $X1 = $X1 + ($this->GraphAreaY1-$Y1); $Y1 = $this->GraphAreaY1; } + if ( $Y1 > $this->GraphAreaY2 ) { $X1 = $X1 + ($Y1-$this->GraphAreaY2); $Y1 = $this->GraphAreaY2; } + if ( $Y2 < $this->GraphAreaY1 ) { $X2 = $X2 - ($this->GraphAreaY1-$Y2); $Y2 = $this->GraphAreaY1; } + if ( $Y2 > $this->GraphAreaY2 ) { $X2 = $X2 - ($Y2-$this->GraphAreaY2); $Y2 = $this->GraphAreaY2; } + + $this->drawLine($X1,$Y1,$X2,$Y2,$Color); + } + else + { + if ( $XDivs == 0 ) { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { $Value = $PosArray; $PosArray = ""; $PosArray[0] = $Value; } + $Sxy = 0; $Sx = 0; $Sy = 0; $Sxx = 0; + foreach($PosArray as $Key => $X) + { + if ( $X != VOID ) + { + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $Y; + $Sy = $Sy + $X; + $Sxx = $Sxx + $Y*$Y; + } + + $Y = $Y + $YStep; + } + $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $Y1 = $this->GraphAreaY1 + $XMargin; + $X1 = $M * $Y1 + $B; + $Y2 = $this->GraphAreaY2 - $XMargin; + $X2 = $M * $Y2 + $B; + + if ( $X1 < $this->GraphAreaX1 ) { $Y1 = $Y1 + ($this->GraphAreaX1-$X1); $X1 = $this->GraphAreaX1; } + if ( $X1 > $this->GraphAreaX2 ) { $Y1 = $Y1 + ($X1-$this->GraphAreaX2); $X1 = $this->GraphAreaX2; } + if ( $X2 < $this->GraphAreaX1 ) { $Y2 = $Y2 - ($this->GraphAreaY1-$X2); $X2 = $this->GraphAreaX1; } + if ( $X2 > $this->GraphAreaX2 ) { $Y2 = $Y2 - ($X2-$this->GraphAreaX2); $X2 = $this->GraphAreaX2; } + + $this->drawLine($X1,$Y1,$X2,$Y2,$Color); + } + } + } + } + + /* Write labels */ + function writeLabel($SeriesName,$Indexes,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : NULL; + $ForceLabels = isset($Format["ForceLabels"]) ? $Format["ForceLabels"] : NULL; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + $DrawVerticalLine = isset($Format["DrawVerticalLine"]) ? $Format["DrawVerticalLine"] : FALSE; + $VerticalLineR = isset($Format["VerticalLineR"]) ? $Format["VerticalLineR"] : 0; + $VerticalLineG = isset($Format["VerticalLineG"]) ? $Format["VerticalLineG"] : 0; + $VerticalLineB = isset($Format["VerticalLineB"]) ? $Format["VerticalLineB"] : 0; + $VerticalLineAlpha = isset($Format["VerticalLineAlpha"]) ? $Format["VerticalLineAlpha"] : 40; + $VerticalLineTicks = isset($Format["VerticalLineTicks"]) ? $Format["VerticalLineTicks"] : 2; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( !is_array($Indexes) ) { $Index = $Indexes; $Indexes = ""; $Indexes[] = $Index; } + if ( !is_array($SeriesName) ) { $SerieName = $SeriesName; $SeriesName = ""; $SeriesName[] = $SerieName; } + if ( $ForceLabels != NULL && !is_array($ForceLabels) ) { $ForceLabel = $ForceLabels; $ForceLabels = ""; $ForceLabels[] = $ForceLabel; } + + foreach ($Indexes as $Key => $Index) + { + $Series = ""; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; } else { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; } + $X = $this->GraphAreaX1 + $XMargin + $Index * $XStep; + + if ( $DrawVerticalLine ) { $this->drawLine($X,$this->GraphAreaY1+$Data["YMargin"],$X,$this->GraphAreaY2-$Data["YMargin"],array("R"=>$VerticalLineR,"G"=>$VerticalLineG,"B"=>$VerticalLineB,"Alpha"=>$VerticalLineAlpha,"Ticks"=>$VerticalLineTicks)); } + + $MinY = $this->GraphAreaY2; + foreach ($SeriesName as $iKey => $SerieName) + { + if ( isset($Data["Series"][$SerieName]["Data"][$Index]) ) + { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $XAxisMode = $Data["XAxisDisplay"]; + $XAxisFormat = $Data["XAxisFormat"]; + $XAxisUnit = $Data["XAxisUnit"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + + if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) ) + $XLabel = $this->scaleFormat($Data["Series"][$Data["Abscissa"]]["Data"][$Index],$XAxisMode,$XAxisFormat,$XAxisUnit); + else + $XLabel = ""; + + if ( $OverrideTitle != NULL) + $Description = $OverrideTitle; + elseif ( count($SeriesName) == 1 ) + { + $Description = $Data["Series"][$SerieName]["Description"]." - ".$XLabel; + } + elseif ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) ) + $Description = $XLabel; + + $Serie = ""; + $Serie["R"] = $Data["Series"][$SerieName]["Color"]["R"]; + $Serie["G"] = $Data["Series"][$SerieName]["Color"]["G"]; + $Serie["B"] = $Data["Series"][$SerieName]["Color"]["B"]; + $Serie["Alpha"] = $Data["Series"][$SerieName]["Color"]["Alpha"]; + + if ( count($SeriesName) == 1 && isset($Data["Series"][$SerieName]["XOffset"]) ) + $SerieOffset = $Data["Series"][$SerieName]["XOffset"]; + else + $SerieOffset = 0; + + $Value = $Data["Series"][$SerieName]["Data"][$Index]; + if ( $Value == VOID ) { $Value = "NaN"; } + + if ( $ForceLabels != NULL ) + $Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set"; + else + $Caption = $this->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + + if ( $this->LastChartLayout == CHART_LAST_LAYOUT_STACKED ) + { + if ( $Value >=0 ) { $LookFor = "+"; } else { $LookFor = "-"; } + + $Value = 0; $Done = FALSE; + foreach($Data["Series"] as $Name => $SerieLookup) + { + if ( $SerieLookup["isDrawable"] == TRUE && $Name != $Data["Abscissa"] && !$Done ) + { + if ( isset($Data["Series"][$Name]["Data"][$Index]) && $Data["Series"][$Name]["Data"][$Index] != VOID ) + { + if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+" ) { $Value = $Value + $Data["Series"][$Name]["Data"][$Index]; } + if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-" ) { $Value = $Value - $Data["Series"][$Name]["Data"][$Index]; } + if ($Name == $SerieName ) { $Done = TRUE; } + } + } + } + } + + $X = floor($this->GraphAreaX1 + $XMargin + $Index * $XStep + $SerieOffset); + $Y = floor($this->scaleComputeY($Value,array("AxisID"=>$AxisID))); + + if ($Y < $MinY) { $MinY = $Y; } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) + $this->drawFilledCircle($X,$Y,3,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + elseif ( $DrawPoint == LABEL_POINT_BOX ) + $this->drawFilledRectangle($X-2,$Y-2,$X+2,$Y+2,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + } + } + $this->drawLabelBox($X,$MinY-3,$Description,$Series,$Format); + + } + else + { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; } else { $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; } + $Y = $this->GraphAreaY1 + $XMargin + $Index * $XStep; + + if ( $DrawVerticalLine ) { $this->drawLine($this->GraphAreaX1+$Data["YMargin"],$Y,$this->GraphAreaX2-$Data["YMargin"],$Y,array("R"=>$VerticalLineR,"G"=>$VerticalLineG,"B"=>$VerticalLineB,"Alpha"=>$VerticalLineAlpha,"Ticks"=>$VerticalLineTicks)); } + + $MinX = $this->GraphAreaX2; + foreach ($SeriesName as $Key => $SerieName) + { + if ( isset($Data["Series"][$SerieName]["Data"][$Index]) ) + { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $XAxisMode = $Data["XAxisDisplay"]; + $XAxisFormat = $Data["XAxisFormat"]; + $XAxisUnit = $Data["XAxisUnit"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + + if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) ) + $XLabel = $this->scaleFormat($Data["Series"][$Data["Abscissa"]]["Data"][$Index],$XAxisMode,$XAxisFormat,$XAxisUnit); + else + $XLabel = ""; + + if ( $OverrideTitle != NULL) + $Description = $OverrideTitle; + elseif ( count($SeriesName) == 1 ) + { + if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) ) + $Description = $Data["Series"][$SerieName]["Description"]." - ".$XLabel; + } + elseif ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) ) + $Description = $XLabel; + + $Serie = ""; + if ( isset($Data["Extended"]["Palette"][$Index] ) ) + { + $Serie["R"] = $Data["Extended"]["Palette"][$Index]["R"]; + $Serie["G"] = $Data["Extended"]["Palette"][$Index]["G"]; + $Serie["B"] = $Data["Extended"]["Palette"][$Index]["B"]; + $Serie["Alpha"] = $Data["Extended"]["Palette"][$Index]["Alpha"]; + } + else + { + $Serie["R"] = $Data["Series"][$SerieName]["Color"]["R"]; + $Serie["G"] = $Data["Series"][$SerieName]["Color"]["G"]; + $Serie["B"] = $Data["Series"][$SerieName]["Color"]["B"]; + $Serie["Alpha"] = $Data["Series"][$SerieName]["Color"]["Alpha"]; + } + + if ( count($SeriesName) == 1 && isset($Data["Series"][$SerieName]["XOffset"]) ) + $SerieOffset = $Data["Series"][$SerieName]["XOffset"]; + else + $SerieOffset = 0; + + $Value = $Data["Series"][$SerieName]["Data"][$Index]; + if ( $ForceLabels != NULL ) + $Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set"; + else + $Caption = $this->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + if ( $Value == VOID ) { $Value = "NaN"; } + + if ( $this->LastChartLayout == CHART_LAST_LAYOUT_STACKED ) + { + if ( $Value >=0 ) { $LookFor = "+"; } else { $LookFor = "-"; } + + $Value = 0; $Done = FALSE; + foreach($Data["Series"] as $Name => $SerieLookup) + { + if ( $SerieLookup["isDrawable"] == TRUE && $Name != $Data["Abscissa"] && !$Done ) + { + if ( isset($Data["Series"][$Name]["Data"][$Index]) && $Data["Series"][$Name]["Data"][$Index] != VOID ) + { + if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+" ) { $Value = $Value + $Data["Series"][$Name]["Data"][$Index]; } + if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-" ) { $Value = $Value - $Data["Series"][$Name]["Data"][$Index]; } + if ($Name == $SerieName ) { $Done = TRUE; } + } + } + } + } + + $X = floor($this->scaleComputeY($Value,array("AxisID"=>$AxisID))); + $Y = floor($this->GraphAreaY1 + $XMargin + $Index * $XStep + $SerieOffset); + + if ($X < $MinX) { $MinX = $X; } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) + $this->drawFilledCircle($X,$Y,3,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + elseif ( $DrawPoint == LABEL_POINT_BOX ) + $this->drawFilledRectangle($X-2,$Y-2,$X+2,$Y+2,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + } + } + $this->drawLabelBox($MinX,$Y-3,$Description,$Series,$Format); + + } + } + } + + /* Draw a label box */ + function drawLabelBox($X,$Y,$Title,$Captions,$Format="") + { + $NoTitle = isset($Format["NoTitle"]) ? $Format["NoTitle"] : NULL; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 50; + $DrawSerieColor = isset($Format["DrawSerieColor"]) ? $Format["DrawSerieColor"] : TRUE; + $SerieR = isset($Format["SerieR"]) ? $Format["SerieR"] : NULL; + $SerieG = isset($Format["SerieG"]) ? $Format["SerieG"] : NULL; + $SerieB = isset($Format["SerieB"]) ? $Format["SerieB"] : NULL; + $SerieAlpha = isset($Format["SerieAlpha"]) ? $Format["SerieAlpha"] : NULL; + $SerieBoxSize = isset($Format["SerieBoxSize"]) ? $Format["SerieBoxSize"] : 6; + $SerieBoxSpacing = isset($Format["SerieBoxSpacing"]) ? $Format["SerieBoxSpacing"] : 4; + $VerticalMargin = isset($Format["VerticalMargin"]) ? $Format["VerticalMargin"] : 10; + $HorizontalMargin = isset($Format["HorizontalMargin"]) ? $Format["HorizontalMargin"] : 8; + $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->FontColorA; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $TitleMode = isset($Format["TitleMode"]) ? $Format["TitleMode"] : LABEL_TITLE_NOBACKGROUND; + $TitleR = isset($Format["TitleR"]) ? $Format["TitleR"] : $R; + $TitleG = isset($Format["TitleG"]) ? $Format["TitleG"] : $G; + $TitleB = isset($Format["TitleB"]) ? $Format["TitleB"] : $B; + $TitleAlpha = isset($Format["TitleAlpha"]) ? $Format["TitleAlpha"] : 100; + $TitleBackgroundR = isset($Format["TitleBackgroundR"]) ? $Format["TitleBackgroundR"] : 0; + $TitleBackgroundG = isset($Format["TitleBackgroundG"]) ? $Format["TitleBackgroundG"] : 0; + $TitleBackgroundB = isset($Format["TitleBackgroundB"]) ? $Format["TitleBackgroundB"] : 0; + $TitleBackgroundAlpha = isset($Format["TitleBackgroundAlpha"]) ? $Format["TitleBackgroundAlpha"] : 100; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 220; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 220; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 220; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 100; + + if ( !$DrawSerieColor ) { $SerieBoxSize = 0; $SerieBoxSpacing = 0; } + + $TxtPos = $this->getTextBox($X,$Y,$FontName,$FontSize,0,$Title); + $TitleWidth = ($TxtPos[1]["X"] - $TxtPos[0]["X"])+$VerticalMargin*2; + $TitleHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); + + if ( $NoTitle ) { $TitleWidth = 0; $TitleHeight = 0; } + + $CaptionWidth = 0; $CaptionHeight = -$HorizontalMargin; + foreach($Captions as $Key =>$Caption) + { + $TxtPos = $this->getTextBox($X,$Y,$FontName,$FontSize,0,$Caption["Caption"]); + $CaptionWidth = max($CaptionWidth,($TxtPos[1]["X"] - $TxtPos[0]["X"])+$VerticalMargin*2); + $CaptionHeight = $CaptionHeight + max(($TxtPos[0]["Y"] - $TxtPos[2]["Y"]),($SerieBoxSize+2)) + $HorizontalMargin; + } + + if ( $CaptionHeight <= 5 ) { $CaptionHeight = $CaptionHeight + $HorizontalMargin/2; } + + if ( $DrawSerieColor ) { $CaptionWidth = $CaptionWidth + $SerieBoxSize + $SerieBoxSpacing; } + + $BoxWidth = max($BoxWidth,$TitleWidth,$CaptionWidth); + + $XMin = $X - 5 - floor(($BoxWidth-10) / 2); + $XMax = $X + 5 + floor(($BoxWidth-10) / 2); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow == TRUE ) + { + $this->Shadow = FALSE; + + $Poly = ""; + $Poly[] = $X+$this->ShadowX; $Poly[] = $Y+$this->ShadowX; + $Poly[] = $X+5+$this->ShadowX; $Poly[] = $Y-5+$this->ShadowX; + $Poly[] = $XMax+$this->ShadowX; $Poly[] = $Y-5+$this->ShadowX; + + if ( $NoTitle ) + { + $Poly[] = $XMax+$this->ShadowX; $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2+$this->ShadowX; + $Poly[] = $XMin+$this->ShadowX; $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2+$this->ShadowX; + } + else + { + $Poly[] = $XMax+$this->ShadowX; $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3+$this->ShadowX; + $Poly[] = $XMin+$this->ShadowX; $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3+$this->ShadowX; + } + + $Poly[] = $XMin+$this->ShadowX; $Poly[] = $Y-5+$this->ShadowX; + $Poly[] = $X-5+$this->ShadowX; $Poly[] = $Y-5+$this->ShadowX; + $this->drawPolygon($Poly,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa)); + } + + /* Draw the background */ + $GradientSettings = array("StartR"=>$GradientStartR,"StartG"=>$GradientStartG,"StartB"=>$GradientStartB,"EndR"=>$GradientEndR,"EndG"=>$GradientEndG,"EndB"=>$GradientEndB,"Alpha"=>$BoxAlpha); + if ( $NoTitle ) + $this->drawGradientArea($XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax,$Y-6,DIRECTION_VERTICAL,$GradientSettings); + else + $this->drawGradientArea($XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-6,DIRECTION_VERTICAL,$GradientSettings); + $Poly = ""; $Poly[] = $X; $Poly[] = $Y; $Poly[] = $X-5; $Poly[] = $Y-5; $Poly[] = $X+5; $Poly[] = $Y-5; + $this->drawPolygon($Poly,array("R"=>$GradientEndR,"G"=>$GradientEndG,"B"=>$GradientEndB,"Alpha"=>$BoxAlpha,"NoBorder"=>TRUE)); + + /* Outer border */ + $OuterBorderColor = $this->allocateColor($this->Picture,100,100,100,$BoxAlpha); + imageline($this->Picture,$XMin,$Y-5,$X-5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X,$Y,$X-5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X,$Y,$X+5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X+5,$Y-5,$XMax,$Y-5,$OuterBorderColor); + if ( $NoTitle ) + { + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMin,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$OuterBorderColor); + } + else + { + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMin,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$OuterBorderColor); + } + + /* Inner border */ + $InnerBorderColor = $this->allocateColor($this->Picture,255,255,255,$BoxAlpha); + imageline($this->Picture,$XMin+1,$Y-6,$X-5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X,$Y-1,$X-5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X,$Y-1,$X+5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X+5,$Y-6,$XMax-1,$Y-6,$InnerBorderColor); + if ( $NoTitle ) + { + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMin+1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax-1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$InnerBorderColor); + } + else + { + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMin+1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax-1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$InnerBorderColor); + } + + /* Draw the separator line */ + if ( $TitleMode == LABEL_TITLE_NOBACKGROUND && !$NoTitle ) + { + $YPos = $Y-7-$CaptionHeight-$HorizontalMargin-$HorizontalMargin/2; + $XMargin = $VerticalMargin / 2; + $this->drawLine($XMin+$XMargin,$YPos+1,$XMax-$XMargin,$YPos+1,array("R"=>$GradientEndR,"G"=>$GradientEndG,"B"=>$GradientEndB,"Alpha"=>$BoxAlpha)); + $this->drawLine($XMin+$XMargin,$YPos,$XMax-$XMargin,$YPos,array("R"=>$GradientStartR,"G"=>$GradientStartG,"B"=>$GradientStartB,"Alpha"=>$BoxAlpha)); + } + elseif ( $TitleMode == LABEL_TITLE_BACKGROUND ) + { + $this->drawFilledRectangle($XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2,array("R"=>$TitleBackgroundR,"G"=>$TitleBackgroundG,"B"=>$TitleBackgroundB,"Alpha"=>$BoxAlpha)); + imageline($this->Picture,$XMin+1,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2+1,$XMax-1,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2+1,$InnerBorderColor); + } + + /* Write the description */ + if ( !$NoTitle ) + $this->drawText($XMin+$VerticalMargin,$Y-7-$CaptionHeight-$HorizontalMargin*2,$Title,array("Align"=>TEXT_ALIGN_BOTTOMLEFT,"R"=>$TitleR,"G"=>$TitleG,"B"=>$TitleB)); + + /* Write the value */ + $YPos = $Y-5-$HorizontalMargin; $XPos = $XMin+$VerticalMargin+$SerieBoxSize+$SerieBoxSpacing; + foreach($Captions as $Key => $Caption) + { + $CaptionTxt = $Caption["Caption"]; + $TxtPos = $this->getTextBox($XPos,$YPos,$FontName,$FontSize,0,$CaptionTxt); + $CaptionHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); + + /* Write the serie color if needed */ + if ( $DrawSerieColor ) + { + $BoxSettings = array("R"=>$Caption["Format"]["R"],"G"=>$Caption["Format"]["G"],"B"=>$Caption["Format"]["B"],"Alpha"=>$Caption["Format"]["Alpha"],"BorderR"=>0,"BorderG"=>0,"BorderB"=>0); + $this->drawFilledRectangle($XMin+$VerticalMargin,$YPos-$SerieBoxSize,$XMin+$VerticalMargin+$SerieBoxSize,$YPos,$BoxSettings); + } + + $this->drawText($XPos,$YPos,$CaptionTxt,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); + + $YPos = $YPos - $CaptionHeight - $HorizontalMargin; + } + + $this->Shadow = $RestoreShadow; + } + + /* Draw a basic shape */ + function drawShape($X,$Y,$Shape,$PlotSize,$PlotBorder,$BorderSize,$R,$G,$B,$Alpha,$BorderR,$BorderG,$BorderB,$BorderAlpha) + { + if ( $Shape == SERIE_SHAPE_FILLEDCIRCLE ) + { + if ( $PlotBorder ) { $this->drawFilledCircle($X,$Y,$PlotSize+$BorderSize,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + $this->drawFilledCircle($X,$Y,$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + elseif ( $Shape == SERIE_SHAPE_FILLEDSQUARE ) + { + if ( $PlotBorder ) { $this->drawFilledRectangle($X-$PlotSize-$BorderSize,$Y-$PlotSize-$BorderSize,$X+$PlotSize+$BorderSize,$Y+$PlotSize+$BorderSize,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + $this->drawFilledRectangle($X-$PlotSize,$Y-$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + elseif ( $Shape == SERIE_SHAPE_FILLEDTRIANGLE ) + { + if ( $PlotBorder ) + { + $Pos = ""; $Pos[]=$X; $Pos[]=$Y-$PlotSize-$BorderSize; $Pos[]=$X-$PlotSize-$BorderSize; $Pos[]=$Y+$PlotSize+$BorderSize; $Pos[]=$X+$PlotSize+$BorderSize; $Pos[]=$Y+$PlotSize+$BorderSize; + $this->drawPolygon($Pos,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); + } + + $Pos = ""; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X-$PlotSize; $Pos[]=$Y+$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + elseif ( $Shape == SERIE_SHAPE_TRIANGLE ) + { + $this->drawLine($X,$Y-$PlotSize,$X-$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + $this->drawLine($X-$PlotSize,$Y+$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + $this->drawLine($X+$PlotSize,$Y+$PlotSize,$X,$Y-$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + elseif ( $Shape == SERIE_SHAPE_SQUARE ) + $this->drawRectangle($X-$PlotSize,$Y-$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + elseif ( $Shape == SERIE_SHAPE_CIRCLE ) + $this->drawCircle($X,$Y,$PlotSize,$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + elseif ( $Shape == SERIE_SHAPE_DIAMOND ) + { + $Pos = ""; $Pos[]=$X-$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("NoFill"=>TRUE,"BorderR"=>$R,"BorderG"=>$G,"BorderB"=>$B,"BorderAlpha"=>$Alpha)); + } + elseif ( $Shape == SERIE_SHAPE_FILLEDDIAMOND ) + { + if ( $PlotBorder ) + { + $Pos = ""; $Pos[]=$X-$PlotSize-$BorderSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize-$BorderSize; $Pos[]=$X+$PlotSize+$BorderSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize+$BorderSize; + $this->drawPolygon($Pos,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); + } + + $Pos = ""; $Pos[]=$X-$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + } + + function drawPolygonChart($Points,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : FALSE; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha / 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : NULL; + + if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + + $RestoreShadow = $this->Shadow; + $this->Shadow = FALSE; + + $AllIntegers = TRUE; + for($i=0;$i<=count($Points)-2;$i=$i+2) + { if ( $this->getFirstDecimal($Points[$i+1]) != 0 ) { $AllIntegers = FALSE; } } + + /* Convert polygon to segments */ + $Segments = ""; + for($i=2;$i<=count($Points)-2;$i=$i+2) + { $Segments[] = array("X1"=>$Points[$i-2],"Y1"=>$Points[$i-1],"X2"=>$Points[$i],"Y2"=>$Points[$i+1]); } + $Segments[] = array("X1"=>$Points[$i-2],"Y1"=>$Points[$i-1],"X2"=>$Points[0],"Y2"=>$Points[1]); + + /* Simplify straight lines */ + $Result = ""; $inHorizon = FALSE; $LastX = VOID; + foreach($Segments as $Key => $Pos) + { + if ( $Pos["Y1"] != $Pos["Y2"] ) + { + if ( $inHorizon ) { $inHorizon = FALSE; $Result[] = array("X1"=>$LastX,"Y1"=>$Pos["Y1"],"X2"=>$Pos["X1"],"Y2"=>$Pos["Y1"]); } + + $Result[] = array("X1"=>$Pos["X1"],"Y1"=>$Pos["Y1"],"X2"=>$Pos["X2"],"Y2"=>$Pos["Y2"]); + } + else { if ( !$inHorizon ) { $inHorizon = TRUE; $LastX = $Pos["X1"];} } + } + $Segments = $Result; + + /* Do we have something to draw */ + if ( $Segments == "" ) { return(0); } + + /* For segments debugging purpose */ + //foreach($Segments as $Key => $Pos) + // echo $Pos["X1"].",".$Pos["Y1"].",".$Pos["X2"].",".$Pos["Y2"]."\r\n"; + + /* Find out the min & max Y boundaries */ + $MinY = OUT_OF_SIGHT; $MaxY = OUT_OF_SIGHT; + foreach($Segments as $Key => $Coords) + { + if ( $MinY == OUT_OF_SIGHT || $MinY > min($Coords["Y1"],$Coords["Y2"]) ) { $MinY = min($Coords["Y1"],$Coords["Y2"]); } + if ( $MaxY == OUT_OF_SIGHT || $MaxY < max($Coords["Y1"],$Coords["Y2"]) ) { $MaxY = max($Coords["Y1"],$Coords["Y2"]); } + } + + if ( $AllIntegers ) { $YStep = 1; } else { $YStep = .5; } + + $MinY = floor($MinY); $MaxY = floor($MaxY); + + /* Scan each Y lines */ + $DefaultColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + $DebugLine = 0; $DebugColor = $this->allocateColor($this->Picture,255,0,0,100); + + $MinY = floor($MinY); $MaxY = floor($MaxY); $YStep = 1; + + if ( !$NoFill ) + { + //if ( $DebugLine ) { $MinY = $DebugLine; $MaxY = $DebugLine; } + for($Y=$MinY;$Y<=$MaxY;$Y=$Y+$YStep) + { + $Intersections = ""; $LastSlope = NULL; $RestoreLast = "-"; + foreach($Segments as $Key => $Coords) + { + $X1 = $Coords["X1"]; $X2 = $Coords["X2"]; $Y1 = $Coords["Y1"]; $Y2 = $Coords["Y2"]; + + if ( min($Y1,$Y2) <= $Y && max($Y1,$Y2) >= $Y ) + { + if ( $Y1 == $Y2 ) + { $X = $X1; } + else + { $X = $X1 + ( ($Y-$Y1)*$X2 - ($Y-$Y1)*$X1 ) / ($Y2-$Y1); } + + $X = floor($X); + + if ( $X2 == $X1 ) + { $Slope = "!"; } + else + { + $SlopeC = ($Y2 - $Y1) / ($X2 - $X1); + if( $SlopeC == 0 ) + { $Slope = "="; } + elseif( $SlopeC > 0 ) + { $Slope = "+"; } + elseif ( $SlopeC < 0 ) + { $Slope = "-"; } + } + + if ( !is_array($Intersections) ) + { $Intersections[] = $X; } + elseif( !in_array($X,$Intersections) ) + { $Intersections[] = $X; } + elseif( in_array($X,$Intersections) ) + { + if ($Y == $DebugLine) { echo $Slope."/".$LastSlope."(".$X.") "; } + + if ( $Slope == "=" && $LastSlope == "-" ) { $Intersections[] = $X; } + if ( $Slope != $LastSlope && $LastSlope != "!" && $LastSlope != "=" ) { $Intersections[] = $X; } + if ( $Slope != $LastSlope && $LastSlope == "!" && $Slope == "+" ) { $Intersections[] = $X; } + } + + if ( is_array($Intersections) && in_array($X,$Intersections) && $LastSlope == "=" && ($Slope == "-" )) { $Intersections[] = $X; } + + $LastSlope = $Slope; + } + } + if ( $RestoreLast != "-" ) { $Intersections[] = $RestoreLast; echo "@".$Y."\r\n"; } + + if ( is_array($Intersections) ) + { + sort($Intersections); + + if ($Y == $DebugLine) { print_r($Intersections); } + + /* Remove NULL plots */ + $Result = ""; + for($i=0;$i<=count($Intersections)-1;$i=$i+2) + { + if ( isset($Intersections[$i+1]) ) + { if ( $Intersections[$i] != $Intersections[$i+1] ) { $Result[] = $Intersections[$i]; $Result[] = $Intersections[$i+1]; } } + } + + if ( is_array($Result) ) + { + $Intersections = $Result; + + $LastX = OUT_OF_SIGHT; + foreach($Intersections as $Key => $X) + { + if ( $LastX == OUT_OF_SIGHT ) + $LastX = $X; + elseif ( $LastX != OUT_OF_SIGHT ) + { + if ( $this->getFirstDecimal($LastX) > 1 ) { $LastX++; } + + $Color = $DefaultColor; + if ( $Threshold != NULL ) + { + foreach($Threshold as $Key => $Parameters) + { + if ( $Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) + { + if ( isset($Parameters["R"]) ) { $R = $Parameters["R"]; } else { $R = 0; } + if ( isset($Parameters["G"]) ) { $G = $Parameters["G"]; } else { $G = 0; } + if ( isset($Parameters["B"]) ) { $B = $Parameters["B"]; } else { $B = 0; } + if ( isset($Parameters["Alpha"]) ) { $Alpha = $Parameters["Alpha"]; } else { $Alpha = 100; } + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + } + } + } + + imageline($this->Picture,$LastX,$Y,$X,$Y,$Color); + + if ( $Y == $DebugLine) { imageline($this->Picture,$LastX,$Y,$X,$Y,$DebugColor); } + + $LastX = OUT_OF_SIGHT; + } + } + } + } + } + } + + /* Draw the polygon border, if required */ + if ( !$NoBorder) + { + foreach($Segments as $Key => $Coords) + $this->drawLine($Coords["X1"],$Coords["Y1"],$Coords["X2"],$Coords["Y2"],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Threshold"=>$Threshold)); + } + + $this->Shadow = $RestoreShadow; + } + + /* Return the abscissa margin */ + function getAbscissaMargin($Data) + { + foreach($Data["Axis"] as $AxisID => $Values) { if ( $Values["Identity"] == AXIS_X ) { return($Values["Margin"]); } } + return(0); + } + + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pImage.class.php b/webdata/graph/pchart/class/pImage.class.php new file mode 100644 index 0000000..a21466a --- /dev/null +++ b/webdata/graph/pchart/class/pImage.class.php @@ -0,0 +1,472 @@ +TransparentBackground = $TransparentBackground; + + if ( $DataSet != NULL ) { $this->DataSet = $DataSet; } + + $this->XSize = $XSize; + $this->YSize = $YSize; + $this->Picture = imagecreatetruecolor($XSize,$YSize); + + if ( $this->TransparentBackground ) + { + imagealphablending($this->Picture,FALSE); + imagefilledrectangle($this->Picture, 0,0,$XSize, $YSize, imagecolorallocatealpha($this->Picture, 255, 255, 255, 127)); + imagealphablending($this->Picture,TRUE); + imagesavealpha($this->Picture,true); + } + else + { + $C_White = $this->AllocateColor($this->Picture,255,255,255); + imagefilledrectangle($this->Picture,0,0,$XSize,$YSize,$C_White); + } + } + + /* Enable / Disable and set shadow properties */ + function setShadow($Enabled=TRUE,$Format="") + { + $X = isset($Format["X"]) ? $Format["X"] : 2; + $Y = isset($Format["Y"]) ? $Format["Y"] : 2; + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 10; + + $this->Shadow = $Enabled; + $this->ShadowX = $X; + $this->ShadowY = $Y; + $this->ShadowR = $R; + $this->ShadowG = $G; + $this->ShadowB = $B; + $this->Shadowa = $Alpha; + } + + /* Set the graph area position */ + function setGraphArea($X1,$Y1,$X2,$Y2) + { + if ( $X2 < $X1 || $X1 == $X2 || $Y2 < $Y1 || $Y1 == $Y2 ) { return(-1); } + + $this->GraphAreaX1 = $X1; $this->DataSet->Data["GraphArea"]["X1"] = $X1; + $this->GraphAreaY1 = $Y1; $this->DataSet->Data["GraphArea"]["Y1"] = $Y1; + $this->GraphAreaX2 = $X2; $this->DataSet->Data["GraphArea"]["X2"] = $X2; + $this->GraphAreaY2 = $Y2; $this->DataSet->Data["GraphArea"]["Y2"] = $Y2; + } + + /* Return the width of the picture */ + function getWidth() + { return($this->XSize); } + + /* Return the heigth of the picture */ + function getHeight() + { return($this->YSize); } + + /* Render the picture to a file */ + function render($FileName) + { + if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); } + imagepng($this->Picture,$FileName); + } + + /* Render the picture to a web browser stream */ + function stroke($BrowserExpire=FALSE) + { + if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); } + + if ( $BrowserExpire ) + { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Cache-Control: no-cache"); + header("Pragma: no-cache"); + } + + header('Content-type: image/png'); + imagepng($this->Picture); + } + + /* Automatic output method based on the calling interface */ + function autoOutput($FileName="output.png") + { + if (php_sapi_name() == "cli") + $this->Render($FileName); + else + $this->Stroke(); + } + + /* Return the length between two points */ + function getLength($X1,$Y1,$X2,$Y2) + { return(sqrt(pow(max($X1,$X2)-min($X1,$X2),2)+pow(max($Y1,$Y2)-min($Y1,$Y2),2))); } + + /* Return the orientation of a line */ + function getAngle($X1,$Y1,$X2,$Y2) + { + $Opposite = $Y2 - $Y1; $Adjacent = $X2 - $X1;$Angle = rad2deg(atan2($Opposite,$Adjacent)); + if ($Angle > 0) { return($Angle); } else { return(360-abs($Angle)); } + } + + /* Return the surrounding box of text area */ + function getTextBox_deprecated($X,$Y,$FontName,$FontSize,$Angle,$Text) + { + $Size = imagettfbbox($FontSize,$Angle,$FontName,$Text); + $Width = $this->getLength($Size[0],$Size[1],$Size[2],$Size[3])+1; + $Height = $this->getLength($Size[2],$Size[3],$Size[4],$Size[5])+1; + + $RealPos[0]["X"] = $X; $RealPos[0]["Y"] = $Y; + $RealPos[1]["X"] = cos((360-$Angle)*PI/180)*$Width + $RealPos[0]["X"]; $RealPos[1]["Y"] = sin((360-$Angle)*PI/180)*$Width + $RealPos[0]["Y"]; + $RealPos[2]["X"] = cos((270-$Angle)*PI/180)*$Height + $RealPos[1]["X"]; $RealPos[2]["Y"] = sin((270-$Angle)*PI/180)*$Height + $RealPos[1]["Y"]; + $RealPos[3]["X"] = cos((180-$Angle)*PI/180)*$Width + $RealPos[2]["X"]; $RealPos[3]["Y"] = sin((180-$Angle)*PI/180)*$Width + $RealPos[2]["Y"]; + + $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"]; + $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"]; + + return($RealPos); + } + + /* Return the surrounding box of text area */ + function getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text) + { + $coords = imagettfbbox($FontSize, 0, $FontName, $Text); + + $a = deg2rad($Angle); $ca = cos($a); $sa = sin($a); $RealPos = array(); + for($i = 0; $i < 7; $i += 2) + { + $RealPos[$i/2]["X"] = $X + round($coords[$i] * $ca + $coords[$i+1] * $sa); + $RealPos[$i/2]["Y"] = $Y + round($coords[$i+1] * $ca - $coords[$i] * $sa); + } + + $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"]; + $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"]; + $RealPos[TEXT_ALIGN_TOPLEFT]["X"] = $RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPLEFT]["Y"] = $RealPos[3]["Y"]; + $RealPos[TEXT_ALIGN_TOPRIGHT]["X"] = $RealPos[2]["X"]; $RealPos[TEXT_ALIGN_TOPRIGHT]["Y"] = $RealPos[2]["Y"]; + $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[0]["X"])/2+$RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[1]["Y"])/2+$RealPos[1]["Y"]; + $RealPos[TEXT_ALIGN_TOPMIDDLE]["X"] = ($RealPos[2]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPMIDDLE]["Y"] = ($RealPos[3]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"]; + $RealPos[TEXT_ALIGN_MIDDLELEFT]["X"] = ($RealPos[0]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLELEFT]["Y"] = ($RealPos[0]["Y"]-$RealPos[3]["Y"])/2+$RealPos[3]["Y"]; + $RealPos[TEXT_ALIGN_MIDDLERIGHT]["X"] = ($RealPos[1]["X"]-$RealPos[2]["X"])/2+$RealPos[2]["X"]; $RealPos[TEXT_ALIGN_MIDDLERIGHT]["Y"] = ($RealPos[1]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"]; + $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"]; + + return($RealPos); + } + + /* Set current font properties */ + function setFontProperties($Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : -1; + $G = isset($Format["G"]) ? $Format["G"] : -1; + $B = isset($Format["B"]) ? $Format["B"] : -1; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : NULL; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : NULL; + + if ( $R != -1) { $this->FontColorR = $R; } + if ( $G != -1) { $this->FontColorG = $G; } + if ( $B != -1) { $this->FontColorB = $B; } + if ( $Alpha != NULL) { $this->FontColorA = $Alpha; } + + if ( $FontName != NULL ) + $this->FontName = $FontName; + + if ( $FontSize != NULL ) + $this->FontSize = $FontSize; + } + + /* Returns the 1st decimal values (used to correct AA bugs) */ + function getFirstDecimal($Value) + { + $Values = preg_split("/\./",$Value); + if ( isset($Values[1]) ) { return(substr($Values[1],0,1)); } else { return(0); } + } + + /* Attach a dataset to your pChart Object */ + function setDataSet(&$DataSet) + { $this->DataSet = $DataSet; } + + /* Print attached dataset contents to STDOUT */ + function printDataSet() + { print_r($this->DataSet); } + + /* Initialise the image map methods */ + function initialiseImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp") + { + $this->ImageMapIndex = $Name; + $this->ImageMapStorageMode = $StorageMode; + + if ($StorageMode == IMAGE_MAP_STORAGE_SESSION) + { + if(!isset($_SESSION)) { session_start(); } + $_SESSION[$this->ImageMapIndex] = NULL; + } + elseif($StorageMode == IMAGE_MAP_STORAGE_FILE) + { + $this->ImageMapFileName = $UniqueID; + $this->ImageMapStorageFolder = $StorageFolder; + + if (file_exists($StorageFolder."/".$UniqueID.".map")) { unlink($StorageFolder."/".$UniqueID.".map"); } + } + } + + /* Add a zone to the image map */ + function addToImageMap($Type,$Plots,$Color=NULL,$Title=NULL,$Message=NULL,$HTMLEncode=FALSE) + { + if ( $this->ImageMapStorageMode == NULL ) { $this->initialiseImageMap(); } + + /* Encode the characters in the imagemap in HTML standards */ + $Title = str_replace("€","\u20AC",$Title); + $Title = htmlentities($Title,ENT_QUOTES,"ISO-8859-15"); + if ( $HTMLEncode ) + { + $Message = htmlentities($Message,ENT_QUOTES,"ISO-8859-15"); + $Message = str_replace("<","<",$Message); + $Message = str_replace(">",">",$Message); + } + + if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION ) + { + if(!isset($_SESSION)) { $this->initialiseImageMap(); } + $_SESSION[$this->ImageMapIndex][] = array($Type,$Plots,$Color,$Title,$Message); + } + elseif($this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE) + { + $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'a'); + fwrite($Handle, $Type.IMAGE_MAP_DELIMITER.$Plots.IMAGE_MAP_DELIMITER.$Color.IMAGE_MAP_DELIMITER.$Title.IMAGE_MAP_DELIMITER.$Message."\r\n"); + fclose($Handle); + } + } + + /* Remove VOID values from an imagemap custom values array */ + function removeVOIDFromArray($SerieName, $Values) + { + if ( !isset($this->DataSet->Data["Series"][$SerieName]) ) { return(-1); } + + $Result = ""; + foreach($this->DataSet->Data["Series"][$SerieName]["Data"] as $Key => $Value) + { if ( $Value != VOID && isset($Values[$Key]) ) { $Result[] = $Values[$Key]; } } + return($Result); + } + + /* Replace the title of one image map serie */ + function replaceImageMapTitle($OldTitle, $NewTitle) + { + if ( $this->ImageMapStorageMode == NULL ) { return(-1); } + + if ( is_array($NewTitle) ) { $NewTitle = $this->removeVOIDFromArray($OldTitle, $NewTitle); } + + if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION ) + { + if(!isset($_SESSION)) { return(-1); } + if ( is_array($NewTitle) ) + { $ID = 0; foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID])) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle[$ID]; $ID++; } } } + else + { foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle; } } } + } + elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE ) + { + $TempArray = ""; + $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r"); + if ($Handle) + { + while (($Buffer = fgets($Handle, 4096)) !== false) + { + $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer)); + $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]); + } + fclose($Handle); + + if ( is_array($NewTitle) ) + { $ID = 0; foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID]) ) { $TempArray[$Key][3] = $NewTitle[$ID]; $ID++; } } } + else + { foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $TempArray[$Key][3] = $NewTitle; } } } + + $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w'); + foreach($TempArray as $Key => $Settings) + { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); } + fclose($Handle); + } + } + } + + /* Replace the values of the image map contents */ + function replaceImageMapValues($Title, $Values) + { + if ( $this->ImageMapStorageMode == NULL ) { return(-1); } + + $Values = $this->removeVOIDFromArray($Title, $Values); + $ID = 0; + if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION ) + { + if(!isset($_SESSION)) { return(-1); } + foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $_SESSION[$this->ImageMapIndex][$Key][4] = $Values[$ID]; } $ID++; } } + } + elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE ) + { + $TempArray = ""; + $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r"); + if ($Handle) + { + while (($Buffer = fgets($Handle, 4096)) !== false) + { + $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer)); + $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]); + } + fclose($Handle); + + foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $TempArray[$Key][4] = $Values[$ID]; } $ID++; } } + + $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w'); + foreach($TempArray as $Key => $Settings) + { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); } + fclose($Handle); + } + } + } + + /* Dump the image map */ + function dumpImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp") + { + $this->ImageMapIndex = $Name; + $this->ImageMapStorageMode = $StorageMode; + + if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION ) + { + if(!isset($_SESSION)) { session_start(); } + if ( $_SESSION[$Name] != NULL ) + { + foreach($_SESSION[$Name] as $Key => $Params) + { echo $Params[0].IMAGE_MAP_DELIMITER.$Params[1].IMAGE_MAP_DELIMITER.$Params[2].IMAGE_MAP_DELIMITER.$Params[3].IMAGE_MAP_DELIMITER.$Params[4]."\r\n"; } + } + } + elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE ) + { + if (file_exists($StorageFolder."/".$UniqueID.".map")) + { + $Handle = @fopen($StorageFolder."/".$UniqueID.".map", "r"); + if ($Handle) { while (($Buffer = fgets($Handle, 4096)) !== false) { echo $Buffer; } } + fclose($Handle); + + if ( $this->ImageMapAutoDelete ) { unlink($StorageFolder."/".$UniqueID.".map"); } + } + } + + /* When the image map is returned to the client, the script ends */ + exit(); + } + + /* Return the HTML converted color from the RGB composite values */ + function toHTMLColor($R,$G,$B) + { + $R=intval($R); $G=intval($G); $B=intval($B); + $R=dechex($R<0?0:($R>255?255:$R)); $G=dechex($G<0?0:($G>255?255:$G));$B=dechex($B<0?0:($B>255?255:$B)); + $Color="#".(strlen($R) < 2?'0':'').$R; $Color.=(strlen($G) < 2?'0':'').$G; $Color.= (strlen($B) < 2?'0':'').$B; + return($Color); + } + + /* Reverse an array of points */ + function reversePlots($Plots) + { + $Result = ""; + for($i=count($Plots)-2;$i>=0;$i=$i-2) { $Result[] = $Plots[$i]; $Result[] = $Plots[$i+1]; } + return($Result); + } + + /* Mirror Effect */ + function drawAreaMirror($X,$Y,$Width,$Height,$Format="") + { + $StartAlpha = isset($Format["StartAlpha"]) ? $Format["StartAlpha"] : 80; + $EndAlpha = isset($Format["EndAlpha"]) ? $Format["EndAlpha"] : 0; + + $AlphaStep = ($StartAlpha-$EndAlpha)/$Height; + + $Picture = imagecreatetruecolor($this->XSize,$this->YSize); + imagecopy($Picture,$this->Picture,0,0,0,0,$this->XSize,$this->YSize); + + for($i=1;$i<=$Height;$i++) + { + if ( $Y+($i-1) < $this->YSize && $Y-$i > 0 ) { imagecopymerge($Picture,$this->Picture,$X,$Y+($i-1),$X,$Y-$i,$Width,1,$StartAlpha-$AlphaStep*$i); } + } + + imagecopy($this->Picture,$Picture,0,0,0,0,$this->XSize,$this->YSize); + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pIndicator.class.php b/webdata/graph/pchart/class/pIndicator.class.php new file mode 100644 index 0000000..1040af8 --- /dev/null +++ b/webdata/graph/pchart/class/pIndicator.class.php @@ -0,0 +1,241 @@ +pChartObject = $pChartObject; + } + + /* Draw an indicator */ + function draw($X,$Y,$Width,$Height,$Format="") + { + $Values = isset($Format["Values"]) ? $Format["Values"] : VOID; + $IndicatorSections = isset($Format["IndicatorSections"]) ? $Format["IndicatorSections"] : NULL; + $ValueDisplay = isset($Format["ValueDisplay"]) ? $Format["ValueDisplay"] : INDICATOR_VALUE_BUBBLE; + $SectionsMargin = isset($Format["SectionsMargin"]) ? $Format["SectionsMargin"] : 4; + $DrawLeftHead = isset($Format["DrawLeftHead"]) ? $Format["DrawLeftHead"] : TRUE; + $DrawRightHead = isset($Format["DrawRightHead"]) ? $Format["DrawRightHead"] : TRUE; + $HeadSize = isset($Format["HeadSize"]) ? $Format["HeadSize"] : floor($Height/4); + $TextPadding = isset($Format["TextPadding"]) ? $Format["TextPadding"] : 4; + $CaptionLayout = isset($Format["CaptionLayout"]) ? $Format["CaptionLayout"] : INDICATOR_CAPTION_EXTENDED; + $CaptionPosition = isset($Format["CaptionPosition"]) ? $Format["CaptionPosition"] : INDICATOR_CAPTION_INSIDE; + $CaptionColorFactor = isset($Format["CaptionColorFactor"]) ? $Format["CaptionColorFactor"] : NULL; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $SubCaptionColorFactor = isset($Format["SubCaptionColorFactor"]) ? $Format["SubCaptionColorFactor"] : NULL; + $SubCaptionR = isset($Format["SubCaptionR"]) ? $Format["SubCaptionR"] : 50; + $SubCaptionG = isset($Format["SubCaptionG"]) ? $Format["SubCaptionG"] : 50; + $SubCaptionB = isset($Format["SubCaptionB"]) ? $Format["SubCaptionB"] : 50; + $SubCaptionAlpha = isset($Format["SubCaptionAlpha"]) ? $Format["SubCaptionAlpha"] : 100; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $CaptionFontName = isset($Format["CaptionFontName"]) ? $Format["CaptionFontName"] : $this->pChartObject->FontName; + $CaptionFontSize = isset($Format["CaptionFontSize"]) ? $Format["CaptionFontSize"] : $this->pChartObject->FontSize; + $Unit = isset($Format["Unit"]) ? $Format["Unit"] : ""; + + /* Convert the Values to display to an array if needed */ + if ( !is_array($Values) ) { $Value = $Values; $Values = ""; $Values[] = $Value; } + + /* No section, let's die */ + if ( $IndicatorSections == NULL ) { return(0); } + + /* Determine indicator visual configuration */ + $OverallMin = $IndicatorSections[0]["End"]; $OverallMax = $IndicatorSections[0]["Start"]; + foreach ($IndicatorSections as $Key => $Settings) + { + if ( $Settings["End"] > $OverallMax ) { $OverallMax = $Settings["End"]; } + if ( $Settings["Start"] < $OverallMin ) { $OverallMin = $Settings["Start"]; } + } + $RealWidth = $Width - (count($IndicatorSections)-1)*$SectionsMargin; + $XScale = $RealWidth / ($OverallMax-$OverallMin); + + $X1 = $X; $ValuesPos = ""; + foreach ($IndicatorSections as $Key => $Settings) + { + $Color = array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]); + $Caption = $Settings["Caption"]; + $SubCaption = $Settings["Start"]." - ".$Settings["End"]; + + $X2 = $X1 + ($Settings["End"] - $Settings["Start"]) * $XScale; + + if ( $Key == 0 && $DrawLeftHead ) + { + $Poly = ""; $Poly[] = $X1-1; $Poly[] = $Y; $Poly[] = $X1-1; $Poly[] = $Y+$Height; $Poly[] = $X1-1-$HeadSize; $Poly[] = $Y+($Height/2); + $this->pChartObject->drawPolygon($Poly,$Color); + $this->pChartObject->drawLine($X1-2,$Y,$X1-2-$HeadSize,$Y+($Height/2),$Color); + $this->pChartObject->drawLine($X1-2,$Y+$Height,$X1-2-$HeadSize,$Y+($Height/2),$Color); + } + + /* Determine the position of the breaks */ + $Break = ""; + foreach($Values as $iKey => $Value) + { + if ( $Value >= $Settings["Start"] && $Value <= $Settings["End"] ) + { + $XBreak = $X1 + ($Value - $Settings["Start"]) * $XScale; + $ValuesPos[$Value] = $XBreak; + $Break[] = floor($XBreak); + } + } + + if ( $ValueDisplay == INDICATOR_VALUE_LABEL ) + { + if ( $Break == "" ) + $this->pChartObject->drawFilledRectangle($X1,$Y,$X2,$Y+$Height,$Color); + else + { + sort($Break); + $Poly = ""; $Poly[] = $X1; $Poly[] = $Y; $LastPointWritten = FALSE; + foreach($Break as $iKey => $Value) + { + if ( $Value-5 >= $X1 ) + { $Poly[] = $Value-5; $Poly[] = $Y; } + elseif ($X1 - ($Value-5) > 0 ) + { + $Offset = $X1 - ($Value-5); + $Poly = ""; $Poly[] = $X1; $Poly[] = $Y + $Offset; + } + + $Poly[] = $Value; $Poly[] = $Y+5; + + if ( $Value+5 <= $X2 ) + { $Poly[] = $Value+5; $Poly[] = $Y; } + elseif (($Value+5) > $X2 ) + { + $Offset = ($Value+5) - $X2; + $Poly[] = $X2; $Poly[] = $Y + $Offset; + $LastPointWritten = TRUE; + } + + } + if ( !$LastPointWritten ) { $Poly[] = $X2; $Poly[] = $Y; } + $Poly[] = $X2; $Poly[] = $Y+$Height; + $Poly[] = $X1; $Poly[] = $Y+$Height; + + $this->pChartObject->drawPolygon($Poly,$Color); + } + } + else + $this->pChartObject->drawFilledRectangle($X1,$Y,$X2,$Y+$Height,$Color); + + if ( $Key == count($IndicatorSections)-1 && $DrawRightHead ) + { + $Poly = ""; $Poly[] = $X2+1; $Poly[] = $Y; $Poly[] = $X2+1; $Poly[] = $Y+$Height; $Poly[] = $X2+1+$HeadSize; $Poly[] = $Y+($Height/2); + $this->pChartObject->drawPolygon($Poly,$Color); + $this->pChartObject->drawLine($X2+1,$Y,$X2+1+$HeadSize,$Y+($Height/2),$Color); + $this->pChartObject->drawLine($X2+1,$Y+$Height,$X2+1+$HeadSize,$Y+($Height/2),$Color); + } + + if ( $CaptionPosition == INDICATOR_CAPTION_INSIDE ) + { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$Caption); + $YOffset = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding; + + if ( $CaptionLayout == INDICATOR_CAPTION_EXTENDED ) + { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$SubCaption); + $YOffset = $YOffset + ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding*2; + } + + $XOffset = $TextPadding; + } + else + { $YOffset = 0; $XOffset = 0; } + + if ( $CaptionColorFactor == NULL ) + { $CaptionColor = array("Align"=>TEXT_ALIGN_TOPLEFT,"FontName"=>$CaptionFontName,"FontSize"=>$CaptionFontSize,"R"=>$CaptionR,"G"=>$CaptionG,"B"=>$CaptionB,"Alpha"=>$CaptionAlpha); } + else + { $CaptionColor = array("Align"=>TEXT_ALIGN_TOPLEFT,"FontName"=>$CaptionFontName,"FontSize"=>$CaptionFontSize,"R"=>$Settings["R"]+$CaptionColorFactor,"G"=>$Settings["G"]+$CaptionColorFactor,"B"=>$Settings["B"]+$CaptionColorFactor); } + + if ( $SubCaptionColorFactor == NULL ) + $SubCaptionColor = array("Align"=>TEXT_ALIGN_TOPLEFT,"FontName"=>$CaptionFontName,"FontSize"=>$CaptionFontSize,"R"=>$SubCaptionR,"G"=>$SubCaptionG,"B"=>$SubCaptionB,"Alpha"=>$SubCaptionAlpha); + else + $SubCaptionColor = array("Align"=>TEXT_ALIGN_TOPLEFT,"FontName"=>$CaptionFontName,"FontSize"=>$CaptionFontSize,"R"=>$Settings["R"]+$SubCaptionColorFactor,"G"=>$Settings["G"]+$SubCaptionColorFactor,"B"=>$Settings["B"]+$SubCaptionColorFactor); + + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = FALSE; + + if ( $CaptionLayout == INDICATOR_CAPTION_DEFAULT ) + $this->pChartObject->drawText($X1,$Y+$Height+$TextPadding,$Caption,$CaptionColor); + elseif ( $CaptionLayout == INDICATOR_CAPTION_EXTENDED ) + { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$Caption); + $CaptionHeight = $TxtPos[0]["Y"] - $TxtPos[2]["Y"]; + + $this->pChartObject->drawText($X1+$XOffset,$Y+$Height-$YOffset+$TextPadding,$Caption,$CaptionColor); + $this->pChartObject->drawText($X1+$XOffset,$Y+$Height-$YOffset+$CaptionHeight+$TextPadding*2,$SubCaption,$SubCaptionColor); + } + + $this->pChartObject->Shadow = $RestoreShadow; + + $X1 = $X2 + $SectionsMargin; + } + + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = FALSE; + + foreach($Values as $Key => $Value) + { + if ( $Value >= $OverallMin && $Value <= $OverallMax ) + { + foreach ($IndicatorSections as $Key => $Settings) + { + if ( $Value >= $Settings["Start"] && $Value <= $Settings["End"] ) + { + $X1 = $ValuesPos[$Value]; //$X + $Key*$SectionsMargin + ($Value - $OverallMin) * $XScale; + + if ( $ValueDisplay == INDICATOR_VALUE_BUBBLE ) + { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y,$ValueFontName,$ValueFontSize,0,$Value.$Unit); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $TextPadding*4)/2); + + $this->pChartObject->drawFilledCircle($X1,$Y,$Radius+4,array("R"=>$Settings["R"]+20,"G"=>$Settings["G"]+20,"B"=>$Settings["B"]+20)); + $this->pChartObject->drawFilledCircle($X1,$Y,$Radius,array("R"=>255,"G"=>255,"B"=>255)); + + $TextSettings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontName"=>$ValueFontName,"FontSize"=>$ValueFontSize); + $this->pChartObject->drawText($X1-1,$Y-1,$Value.$Unit,$TextSettings); + } + elseif( $ValueDisplay == INDICATOR_VALUE_LABEL ) + { + $Caption = ""; + $Caption[] = array("Format"=>array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"],"Alpha"=>100),"Caption"=>$Value.$Unit); + $this->pChartObject->drawLabelBox(floor($X1),floor($Y)+2,"Value - ".$Settings["Caption"],$Caption); + } + } + $X1 = $X2 + $SectionsMargin; + } + } + } + $this->pChartObject->Shadow = $RestoreShadow; + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pPie.class.php b/webdata/graph/pchart/class/pPie.class.php new file mode 100644 index 0000000..209b749 --- /dev/null +++ b/webdata/graph/pchart/class/pPie.class.php @@ -0,0 +1,1500 @@ +pChartObject = $Object; + + /* Cache the pData object reference */ + $this->pDataObject = $pDataObject; + } + + /* Draw a pie chart */ + function draw2DPie($X,$Y,$Format="") + { + $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0; + $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0; + $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) + { + $this->pChartObject->Shadow = FALSE; + + $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE; + $this->draw2DPie($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat); + } + + /* Draw the polygon pie elements */ + $Step = 360 / (2 * PI * $Radius); + $Offset = 0; $ID = 0; + foreach($Values as $Key => $Value) + { + if ( $Shadow ) + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); + else + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + } + + if ( !$SecondPass && !$Shadow ) + { + if ( !$Border ) + $Settings["Surrounding"] = 10; + else + { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; } + } + + $Plots = ""; + $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + if ($DataGapAngle == 0) + { $X0 = $X; $Y0 = $Y; } + else + { + $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; + $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y; + } + + $Plots[] = $X0; $Plots[] = $Y0; + + + for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * $Radius + $X; + $Yc = sin(($i-90)*PI/180) * $Radius + $Y; + + if ( $SecondPass && ( $i<90 )) { $Yc++; } + if ( $SecondPass && ( $i>180 && $i<270 )) { $Xc++; } + if ( $SecondPass && ( $i>=270 )) { $Xc++; $Yc++; } + + $Plots[] = $Xc; $Plots[] = $Yc; + } + + $this->pChartObject->drawPolygon($Plots,$Settings); + if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } + + if ( $DrawLabels && !$Shadow && !$SecondPass ) + { + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y; + + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius); + else + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); + } + + $Offset = $i + $DataGapAngle; $ID++; + } + + /* Second pass to smooth the angles */ + if ( $SecondPass ) + { + $Step = 360 / (2 * PI * $Radius); + $Offset = 0; $ID = 0; + foreach($Values as $Key => $Value) + { + $FirstPoint = TRUE; + if ( $Shadow ) + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); + else + { + if ( $Border ) + $Settings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB); + else + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + } + + $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } + + if ($DataGapAngle == 0) + { $X0 = $X; $Y0 = $Y; } + else + { + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; + $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y; + } + $Plots[] = $X0; $Plots[] = $Y0; + + for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * $Radius + $X; + $Yc = sin(($i-90)*PI/180) * $Radius + $Y; + + if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; } + + $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); + } + $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); + + if ( $DrawLabels && !$Shadow ) + { + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y; + + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius); + else + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); + } + + $Offset = $i + $DataGapAngle; $ID++; + } + } + + if ( $WriteValues != NULL && !$Shadow ) + { + $Step = 360 / (2 * PI * $Radius); + $Offset = 0; $ID = count($Values)-1; + $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha); + foreach($Values as $Key => $Value) + { + $EndAngle = ($Value*$ScaleFactor) + $Offset; if ( (int)$EndAngle > 360 ) { $EndAngle = 0; } + $Angle = ($EndAngle - $Offset)/2 + $Offset; + + if ( $ValuePosition == PIE_VALUE_OUTSIDE ) + { + $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X; + $Yc = sin(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $Y; + } + else + { + $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X; + $Yc = sin(($Angle-90)*PI/180) * ($Radius)/2 + $Y; + } + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Display = $Value.$ValueSuffix; + + $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings); + + $Offset = $EndAngle + $DataGapAngle; $ID--; + } + } + + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Draw a 3D pie chart */ + function draw3DPie($X,$Y,$Format="") + { + /* Rendering layout */ + $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .5; + $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20; + $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0; + $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0; + $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Error correction for overlaying rounded corners */ + if ( $SkewFactor < .5 ) { $SkewFactor = .5; } + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } + + /* Draw the polygon pie elements */ + $Step = 360 / (2 * PI * $Radius); + $Offset = 360; $ID = count($Values)-1; + $Values = array_reverse($Values); + $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = ""; + foreach($Values as $Key => $Value) + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + + $SliceColors[$Slice] = $Settings; + + $StartAngle = $Offset; + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; } + if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; } + + if ($DataGapAngle == 0) + { $X0 = $X; $Y0 = $Y; } + else + { + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; + $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y; + } + $Slices[$Slice][] = $X0; $Slices[$Slice][] = $Y0; $SliceAngle[$Slice][] = 0; + + for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * $Radius + $X; + $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y; + + if ( ($SecondPass || $RestoreShadow ) && ( $i<90 )) { $Yc++; } + if ( ($SecondPass || $RestoreShadow ) && ( $i>90 && $i<180 )) { $Xc++; } + if ( ($SecondPass || $RestoreShadow ) && ( $i>180 && $i<270 )) { $Xc++; } + if ( ($SecondPass || $RestoreShadow ) && ( $i>=270 )) { $Xc++; $Yc++; } + + $Slices[$Slice][] = $Xc; $Slices[$Slice][] = $Yc; $SliceAngle[$Slice][] = $i; + } + + $Offset = $i - $DataGapAngle; $ID--; $Slice++; + } + + /* Draw the bottom shadow if needed */ + if ( $RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY !=0 )) + { + foreach($Slices as $SliceID => $Plots) + { + $ShadowPie = ""; + for($i=0;$ipChartObject->ShadowX; $ShadowPie[] = $Plots[$i+1]+$this->pChartObject->ShadowY; } + + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa,"NoBorder"=>TRUE); + $this->pChartObject->drawPolygon($ShadowPie,$Settings); + } + + $Step = 360 / (2 * PI * $Radius); + $Offset = 360; + foreach($Values as $Key => $Value) + { + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * $Radius + $X + $this->pChartObject->ShadowX; + $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y + $this->pChartObject->ShadowY; + + $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); + } + + $Offset = $i - $DataGapAngle; $ID--; + } + } + + /* Draw the bottom pie splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $this->pChartObject->drawPolygon($Plots,$Settings); + + if ( $SecondPass ) + { + $Settings = $SliceColors[$SliceID]; + if ( $Border ) + { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30;; } + + if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */ + { + $Angle = $SliceAngle[$SliceID][1]; + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings); + + $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1]; + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings); + } + } + } + + /* Draw the two vertical edges */ + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; + $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; + + if ( $Visible[$SliceID]["Start"] && isset($Plots[2])) /* Empty error handling */ + { + $this->pChartObject->drawLine($Plots[2],$Plots[3],$Plots[2],$Plots[3]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"])); + $Border = ""; + $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight; + $Border[] = $Plots[2]; $Border[] = $Plots[3] - $SliceHeight; $Border[] = $Plots[2]; $Border[] = $Plots[3]; + $this->pChartObject->drawPolygon($Border,$Settings); + } + } + + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; + $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; + if ( $Visible[$SliceID]["End"] ) + { + $this->pChartObject->drawLine($Plots[count($Plots)-2],$Plots[count($Plots)-1],$Plots[count($Plots)-2],$Plots[count($Plots)-1]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"])); + + $Border = ""; + $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight; + $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1] - $SliceHeight; $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1]; + $this->pChartObject->drawPolygon($Border,$Settings); + } + } + + /* Draw the rounded edges */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; + $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; + + for ($j=2;$j 90 ) + { + $Border = ""; + $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1]; + $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3]; + $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3] - $SliceHeight; + $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1] - $SliceHeight; + $this->pChartObject->drawPolygon($Border,$Settings); + } + } + + if ( $SecondPass ) + { + $Settings = $SliceColors[$SliceID]; + if ( $Border ) + { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30; } + + if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */ + { + $Angle = $SliceAngle[$SliceID][1]; + if ( $Angle < 270 && $Angle > 90 ) + { + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); + } + } + + $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1]; + if ( $Angle < 270 && $Angle > 90 ) + { + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); + } + + if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 270 ) + { + $Xc = cos((270-90)*PI/180) * $Radius + $X; + $Yc = sin((270-90)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); + } + + if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 90 ) + { + $Xc = cos((0)*PI/180) * $Radius + $X; + $Yc = sin((0)*PI/180) * $Radius*$SkewFactor + $Y; + $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); + } + + } + } + + /* Draw the top splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; + $Settings["R"]+= 20; $Settings["G"]+= 20; $Settings["B"]+= 20; + + $Top = ""; + for($j=0;$jpChartObject->drawPolygon($Top,$Settings); + + if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Top),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][count($Slices)-$SliceID-1],$Values[$SliceID]); } + } + + + /* Second pass to smooth the angles */ + if ( $SecondPass ) + { + $Step = 360 / (2 * PI * $Radius); + $Offset = 360; $ID = count($Values)-1; + foreach($Values as $Key => $Value) + { + $FirstPoint = TRUE; + if ( $Shadow ) + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); + else + { + if ( $Border ) + { $Settings = array("R"=>$Palette[$ID]["R"]+30,"G"=>$Palette[$ID]["G"]+30,"B"=>$Palette[$ID]["B"]+30,"Alpha"=>$Palette[$ID]["Alpha"]); } + else + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + } + + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ($DataGapAngle == 0) + { $X0 = $X; $Y0 = $Y- $SliceHeight; } + else + { + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; + $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y - $SliceHeight; + } + $Plots[] = $X0; $Plots[] = $Y0; + + for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * $Radius + $X; + $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight; + + if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; } + + $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); + if ($i < 270 && $i > 90 ) { $this->pChartObject->drawAntialiasPixel($Xc,$Yc+$SliceHeight,$Settings); } + } + $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); + + $Offset = $i - $DataGapAngle; $ID--; + } + } + + if ( $WriteValues != NULL ) + { + $Step = 360 / (2 * PI * $Radius); + $Offset = 360; $ID = count($Values)-1; + $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha); + foreach($Values as $Key => $Value) + { + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + + if ( $ValuePosition == PIE_VALUE_OUTSIDE ) + { + $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X; + $Yc = sin(($Angle-90)*PI/180) * (($Radius*$SkewFactor)+$ValuePadding) + $Y - $SliceHeight; + } + else + { + $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X; + $Yc = sin(($Angle-90)*PI/180) * ($Radius*$SkewFactor)/2 + $Y - $SliceHeight; + } + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Display = $Value.$ValueSuffix; + + $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings); + + $Offset = $EndAngle - $DataGapAngle; $ID--; + } + } + + if ( $DrawLabels ) + { + $Step = 360 / (2 * PI * $Radius); + $Offset = 360; $ID = count($Values)-1; + foreach($Values as $Key => $Value) + { + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; + $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight; + + if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID]) ) + { + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID]; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius,TRUE); + else + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); + } + + $Offset = $EndAngle - $DataGapAngle; $ID--; + } + } + + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Draw the legend of pie chart */ + function drawPieLegend($X,$Y,$Format="") + { + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR; + $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG; + $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB; + $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $R = isset($Format["R"]) ? $Format["R"] : 200; + $G = isset($Format["G"]) ? $Format["G"] : 200; + $B = isset($Format["B"]) ? $Format["B"] : 200; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + + $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5; + $XStep = $BoxSize + 5; + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; + foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) + { + $BoxArray = $this->pChartObject->getTextBox($vX+$BoxSize+4,$vY+$BoxSize/2,$FontName,$FontSize,0,$Value); + + if ( $Mode == LEGEND_VERTICAL ) + { + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; } + $vY=$vY+$YStep; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; } + $vX=$Boundaries["R"]+$XStep; + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; } + + if ( $Style == LEGEND_ROUND ) + $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + elseif ( $Style == LEGEND_BOX ) + $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + + $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE; + foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) + { + $R = $Palette[$Key]["R"]; $G = $Palette[$Key]["G"]; $B = $Palette[$Key]["B"]; + + $this->pChartObject->drawFilledRectangle($X+1,$Y+1,$X+$BoxSize+1,$Y+$BoxSize+1,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); + $this->pChartObject->drawFilledRectangle($X,$Y,$X+$BoxSize,$Y+$BoxSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); + if ( $Mode == LEGEND_VERTICAL ) + { + $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize)); + $Y=$Y+$YStep; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $BoxArray = $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize)); + $X=$BoxArray[1]["X"]+2+$XStep; + } + } + + $this->Shadow = $RestoreShadow; + } + + /* Set the color of the specified slice */ + function setSliceColor($SliceID,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + + $this->pDataObject->Palette[$SliceID]["R"] = $R; + $this->pDataObject->Palette[$SliceID]["G"] = $G; + $this->pDataObject->Palette[$SliceID]["B"] = $B; + $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha; + } + + /* Internally used compute the label positions */ + function writePieLabel($X,$Y,$Label,$Angle,$Settings,$Stacked,$Xc=0,$Yc=0,$Radius=0,$Reversed=FALSE) + { + $LabelOffset = 30; + $FontName = $this->pChartObject->FontName; + $FontSize = $this->pChartObject->FontSize; + + if ( !$Stacked ) + { + $Settings["Angle"] = 360-$Angle; + $Settings["Length"] = 25; + $Settings["Size"] = 8; + + $this->pChartObject->drawArrowLabel($X,$Y," ".$Label." ",$Settings); + } + else + { + $X2 = cos(deg2rad($Angle-90))*20+$X; + $Y2 = sin(deg2rad($Angle-90))*20+$Y; + + $TxtPos = $this->pChartObject->getTextBox($X,$Y,$FontName,$FontSize,0,$Label); + $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"]; + $YTop = $Y2 - $Height/2 - 2; + $YBottom = $Y2 + $Height/2 + 2; + + if ( $this->LabelPos != "" ) + { + $Done = FALSE; + foreach($this->LabelPos as $Key => $Settings) + { + if ( !$Done ) + { + if ( $Angle <= 90 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 90 && $Angle <= 180 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 180 && $Angle <= 270 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } + if ( $Angle > 270 && $Angle <= 360 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) + { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } + } + } + } + + $LabelSettings = array("YTop"=>$YTop,"YBottom"=>$YBottom,"Label"=>$Label,"Angle"=>$Angle,"X1"=>$X,"Y1"=>$Y,"X2"=>$X2,"Y2"=>$Y2); + if ( $Angle <= 180 ) { $LabelSettings["X3"] = $Xc+$Radius+$LabelOffset; } + if ( $Angle > 180 ) { $LabelSettings["X3"] = $Xc-$Radius-$LabelOffset; } + $this->LabelPos[] = $LabelSettings; + } + } + + /* Internally used to shift label positions */ + function shift($StartAngle,$EndAngle,$Offset,$Reversed) + { + if ( $Reversed ) { $Offset = -$Offset; } + foreach($this->LabelPos as $Key => $Settings) + { + if ( $Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle ) { $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset; $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset; $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset; } + } + } + + /* Internally used to write the re-computed labels */ + function writeShiftedLabels() + { + if ( $this->LabelPos == "" ) { return(0); } + foreach($this->LabelPos as $Key => $Settings) + { + $X1 = $Settings["X1"]; $Y1 = $Settings["Y1"]; + $X2 = $Settings["X2"]; $Y2 = $Settings["Y2"]; + $X3 = $Settings["X3"]; + $Angle = $Settings["Angle"]; + $Label = $Settings["Label"]; + + $this->pChartObject->drawArrow($X2,$Y2,$X1,$Y1,array("Size"=>8)); + if ( $Angle <= 180 ) + { + $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); + $this->pChartObject->drawText($X3+2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + else + { + $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); + $this->pChartObject->drawText($X3-2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + } + } + } + + /* Draw a ring chart */ + function draw2DRing($X,$Y,$Format="") + { + $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $InnerRadius = isset($Format["Radius"]) ? $Format["Radius"] : 30; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = 0; } // count($Values) + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) + { + $this->pChartObject->Shadow = FALSE; + + $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE; + $this->draw2DRing($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat); + } + + /* Draw the polygon pie elements */ + $Step = 360 / (2 * PI * $OuterRadius); + $Offset = 0; $ID = 0; + foreach($Values as $Key => $Value) + { + if ( $Shadow ) + { + $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); + $BorderColor = $Settings; + } + else + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + + if ( $Border ) + $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + else + $BorderColor = $Settings; + } + + $Plots = ""; $Boundaries = ""; $AAPixels = ""; + $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } + for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * $OuterRadius + $X; + $Yc = sin(($i-90)*PI/180) * $OuterRadius + $Y; + + if ( !isset($Boundaries[0]["X1"]) ) { $Boundaries[0]["X1"] = $Xc; $Boundaries[0]["Y1"] = $Yc; } + $AAPixels[] = array($Xc,$Yc); + + if ( $i<90 ) { $Yc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Plots[] = $Xc; $Plots[] = $Yc; + } + $Boundaries[1]["X1"] = $Xc; $Boundaries[1]["Y1"] = $Yc; + $Lasti = $EndAngle; + + for($i=$EndAngle;$i>=$Offset;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * ($InnerRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius-1) + $Y; + + if ( !isset($Boundaries[1]["X2"]) ) { $Boundaries[1]["X2"] = $Xc; $Boundaries[1]["Y2"] = $Yc; } + $AAPixels[] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * $InnerRadius + $X; + $Yc = sin(($i-90)*PI/180) * $InnerRadius + $Y; + + if ( $i<90 ) { $Yc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Plots[] = $Xc; $Plots[] = $Yc; + } + $Boundaries[0]["X2"] = $Xc; $Boundaries[0]["Y2"] = $Yc; + + /* Draw the polygon */ + $this->pChartObject->drawPolygon($Plots,$Settings); + if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } + + /* Smooth the edges using AA */ + foreach($AAPixels as $iKey => $Pos ) { $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$BorderColor); } + $this->pChartObject->drawLine($Boundaries[0]["X1"],$Boundaries[0]["Y1"],$Boundaries[0]["X2"],$Boundaries[0]["Y2"],$BorderColor); + $this->pChartObject->drawLine($Boundaries[1]["X1"],$Boundaries[1]["Y1"],$Boundaries[1]["X2"],$Boundaries[1]["Y2"],$BorderColor); + + if ( $DrawLabels && !$Shadow ) + { + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * $OuterRadius + $X; + $Yc = sin(($Angle-90)*PI/180) * $OuterRadius + $Y; + + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); + else + $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); + } + + $Offset = $Lasti; $ID++; + } + + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + if ( $WriteValues && !$Shadow ) + { + $Step = 360 / (2 * PI * $OuterRadius); + $Offset = 0; + foreach($Values as $Key => $Value) + { + $EndAngle = $Offset+($Value*$ScaleFactor); + if ( $EndAngle > 360 ) { $EndAngle = 360; } + + $Angle = $Offset+($Value*$ScaleFactor)/2; + if ( $ValuePosition == PIE_VALUE_OUTSIDE ) + { + $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $X; + $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $Y; + if ( $Angle >=0 && $Angle <= 90 ) { $Align = TEXT_ALIGN_BOTTOMLEFT; } + if ( $Angle > 90 && $Angle <= 180 ) { $Align = TEXT_ALIGN_TOPLEFT; } + if ( $Angle > 180 && $Angle <= 270 ) { $Align = TEXT_ALIGN_TOPRIGHT; } + if ( $Angle > 270 ) { $Align = TEXT_ALIGN_BOTTOMRIGHT; } + } + else + { + $Xc = cos(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $X; + $Yc = sin(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $Y; + $Align = TEXT_ALIGN_MIDDLEMIDDLE; + } + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Display = $Value.$ValueSuffix; + else + $Label = ""; + + $this->pChartObject->drawText($Xc,$Yc,$Display,array("Align"=>$Align,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB)); + $Offset = $EndAngle; + } + } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Draw a 3D ring chart */ + function draw3DRing($X,$Y,$Format="") + { + $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100; + $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; + $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30; + $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .6; + $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10; + $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10; + $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; + $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; + $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; + $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; + $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; + $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; + $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; + $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; + $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15; + $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; + $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; + $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; + $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; + $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; + $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Error correction for overlaying rounded corners */ + if ( $SkewFactor < .5 ) { $SkewFactor = .5; } + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + /* Do we have an abscissa serie defined? */ + if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } + + /* Try to find the data serie */ + $DataSerie = ""; + foreach ($Data["Series"] as $SerieName => $SerieData) + { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } + + /* Do we have data to compute? */ + if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } + + /* Remove unused data */ + list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); + + /* Compute the pie sum */ + $SerieSum = $this->pDataObject->getSum($DataSerie); + + /* Do we have data to draw? */ + if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } + + /* Dump the real number of data to draw */ + $Values = ""; + foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { if ($Value != 0) { $Values[] = $Value; } } + + /* Compute the wasted angular space between series */ + if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } + + /* Compute the scale */ + $ScaleFactor = (360 - $WastedAngular) / $SerieSum; + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } + + /* Draw the polygon ring elements */ + $Offset = 360; $ID = count($Values)-1; + $Values = array_reverse($Values); + $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = ""; + foreach($Values as $Key => $Value) + { + if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } + $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); + + $SliceColors[$Slice] = $Settings; + + $StartAngle = $Offset; + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; } + if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; } + + $Step = (360 / (2 * PI * $OuterRadius))/2; + $OutX1 = VOID; $OutY1 = VOID; + for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) + { + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; + $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; + $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); + + if ( $OutX1 == VOID ) { $OutX1 = $Xc; $OutY1 = $Yc; } + + if ( $i<90 ) { $Yc++; } + if ( $i>90 && $i<180 ) { $Xc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); + $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; + $Slices[$Slice]["Angle"][] = $i; + } + $OutX2 = $Xc; $OutY2 = $Yc; + + $Slices[$Slice]["Angle"][] = VOID; + $Lasti = $i; + + $Step = (360 / (2 * PI * $InnerRadius))/2; + $InX1 = VOID; $InY1 = VOID; + for($i=$EndAngle;$i<=$Offset;$i=$i+$Step) + { + $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius) + $X; + $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius)*$SkewFactor + $Y; + $Slices[$Slice]["AA"][] = array($Xc,$Yc); + + if ( $InX1 == VOID ) { $InX1 = $Xc; $InY1 = $Yc; } + + if ( $i<90 ) { $Yc++; } + if ( $i>90 && $i<180 ) { $Xc++; } + if ( $i>180 && $i<270 ) { $Xc++; } + if ( $i>=270 ) { $Xc++; $Yc++; } + + $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); + $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; + $Slices[$Slice]["Angle"][] = $i; + } + $InX2 = $Xc; $InY2 = $Yc; + + $Slices[$Slice]["InX1"] = $InX1; $Slices[$Slice]["InY1"] = $InY1; + $Slices[$Slice]["InX2"] = $InX2; $Slices[$Slice]["InY2"] = $InY2; + $Slices[$Slice]["OutX1"] = $OutX1; $Slices[$Slice]["OutY1"] = $OutY1; + $Slices[$Slice]["OutX2"] = $OutX2; $Slices[$Slice]["OutY2"] = $OutY2; + + $Offset = $Lasti - $DataGapAngle; $ID--; $Slice++; + } + + /* Draw the bottom pie splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $this->pChartObject->drawPolygon($Plots["BottomPoly"],$Settings); + + foreach($Plots["AA"] as $Key => $Pos) + $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["OutX2"],$Plots["OutY2"],$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["OutX1"],$Plots["OutY1"],$Settings); + } + + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + + /* Draw the vertical edges (semi-visible) */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle >= 270 || $StartAngle <= 90 ) + $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + if ( $StartAngle >= 270 || $StartAngle <= 90 ) + $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Settings); + } + + /* Draw the inner vertical slices */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $Outer = TRUE; $Inner = FALSE; + $InnerPlotsA = ""; $InnerPlotsB = ""; + foreach($Plots["Angle"] as $ID => $Angle) + { + if ( $Angle == VOID ) + { $Outer = FALSE; $Inner = TRUE; } + elseif( $Inner ) + { + if (( $Angle < 90 || $Angle > 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) + { + $Xo = $Plots["BottomPoly"][$ID*2]; + $Yo = $Plots["BottomPoly"][$ID*2+1]; + + $InnerPlotsA[] = $Xo; $InnerPlotsA[] = $Yo; + $InnerPlotsB[] = $Xo; $InnerPlotsB[] = $Yo-$SliceHeight; + } + } + } + + if ( $InnerPlotsA != "" ) + { $InnerPlots = array_merge($InnerPlotsA,$this->arrayReverse($InnerPlotsB)); $this->pChartObject->drawPolygon($InnerPlots,$Settings); } + } + + /* Draw the splice top and left poly */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf*1.5; $Settings["G"] = $Settings["G"]+$Cf*1.5; $Settings["B"] = $Settings["B"]+$Cf*1.5; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle < 180 ) + { + $Points = ""; + $Points[] = $Plots["InX2"]; + $Points[] = $Plots["InY2"]; + $Points[] = $Plots["InX2"]; + $Points[] = $Plots["InY2"]-$SliceHeight; + $Points[] = $Plots["OutX1"]; + $Points[] = $Plots["OutY1"]-$SliceHeight; + $Points[] = $Plots["OutX1"]; + $Points[] = $Plots["OutY1"]; + + $this->pChartObject->drawPolygon($Points,$Settings); + } + + if ( $EndAngle > 180 ) + { + $Points = ""; + $Points[] = $Plots["InX1"]; + $Points[] = $Plots["InY1"]; + $Points[] = $Plots["InX1"]; + $Points[] = $Plots["InY1"]-$SliceHeight; + $Points[] = $Plots["OutX2"]; + $Points[] = $Plots["OutY2"]-$SliceHeight; + $Points[] = $Plots["OutX2"]; + $Points[] = $Plots["OutY2"]; + + $this->pChartObject->drawPolygon($Points,$Settings); + } + } + + + /* Draw the vertical edges (visible) */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $StartAngle = $Plots["Angle"][0]; + foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } + + if ( $StartAngle <= 270 && $StartAngle >= 90 ) + $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + if ( $EndAngle <= 270 && $EndAngle >= 90 ) + $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + } + + + /* Draw the outer vertical slices */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; + + $Outer = TRUE; $Inner = FALSE; + $OuterPlotsA = ""; $OuterPlotsB = ""; $InnerPlotsA = ""; $InnerPlotsB = ""; + foreach($Plots["Angle"] as $ID => $Angle) + { + if ( $Angle == VOID ) + { $Outer = FALSE; $Inner = TRUE; } + elseif( $Outer ) + { + if ( ( $Angle > 90 && $Angle < 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) + { + $Xo = $Plots["BottomPoly"][$ID*2]; + $Yo = $Plots["BottomPoly"][$ID*2+1]; + + $OuterPlotsA[] = $Xo; $OuterPlotsA[] = $Yo; + $OuterPlotsB[] = $Xo; $OuterPlotsB[] = $Yo-$SliceHeight; + } + } + } + if ( $OuterPlotsA != "" ) + { $OuterPlots = array_merge($OuterPlotsA,$this->arrayReverse($OuterPlotsB)); $this->pChartObject->drawPolygon($OuterPlots,$Settings); } + } + + $Slices = array_reverse($Slices); + $SliceColors = array_reverse($SliceColors); + + + /* Draw the top pie splice */ + foreach($Slices as $SliceID => $Plots) + { + $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; + $Settings["R"] = $Settings["R"]+$Cf*2; $Settings["G"] = $Settings["G"]+$Cf*2; $Settings["B"] = $Settings["B"]+$Cf*2; + + $this->pChartObject->drawPolygon($Plots["TopPoly"],$Settings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots["TopPoly"]),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$SliceID],$Data["Series"][$DataSerie]["Data"][count($Slices)-$SliceID-1]); } + + foreach($Plots["AA"] as $Key => $Pos) + $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1]-$SliceHeight,$Settings); + + $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); + $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); + } + + if ( $DrawLabels ) + { + $Offset = 360; + foreach($Values as $Key => $Value) + { + $StartAngle = $Offset; + $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } + + if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) + { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} + else + { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } + + $Angle = ($EndAngle - $Offset)/2 + $Offset; + $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; + $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; + + if ( $WriteValues == PIE_VALUE_PERCENTAGE ) + $Label = $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; + elseif ( $WriteValues == PIE_VALUE_NATURAL ) + $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; + else + $Label = ""; + + if ( $LabelStacked ) + $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); + else + $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,FALSE); + + $Offset = $EndAngle - $DataGapAngle; $ID--; $Slice++; + } + } + if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } + + $this->pChartObject->Shadow = $RestoreShadow; + + return(PIE_RENDERED); + } + + /* Serialize an array */ + function arraySerialize($Data) + { + $Result = ""; + foreach($Data as $Key => $Value) + { if ($Result == "") { $Result = floor($Value); } else { $Result = $Result.",".floor($Value); } } + + return($Result); + } + + /* Reverse an array */ + function arrayReverse($Plots) + { + $Result = ""; + + for($i=count($Plots)-1;$i>=0;$i=$i-2) + { $Result[] = $Plots[$i-1]; $Result[] = $Plots[$i]; } + + return($Result); + } + + /* Remove unused series & values */ + function clean0Values($Data,$Palette,$DataSerie,$AbscissaSerie) + { + $NewPalette = ""; $NewData = ""; $NewAbscissa = ""; + + /* Remove unused series */ + foreach($Data["Series"] as $SerieName => $SerieSettings) + { if ( $SerieName != $DataSerie && $SerieName != $AbscissaSerie ) { unset($Data["Series"][$SerieName]); } } + + /* Remove NULL values */ + foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { + if ($Value != 0 ) + { + $NewData[] = $Value; + $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key]; + if ( isset($Palette[$Key]) ) { $NewPalette[] = $Palette[$Key]; } + } + } + $Data["Series"][$DataSerie]["Data"] = $NewData; + $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa; + + return(array($Data,$NewPalette)); + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pRadar.class.php b/webdata/graph/pchart/class/pRadar.class.php new file mode 100644 index 0000000..fd1aa27 --- /dev/null +++ b/webdata/graph/pchart/class/pRadar.class.php @@ -0,0 +1,681 @@ +pChartObject = $Object; + + $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID; + $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60; + $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60; + $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50; + $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : 0; + $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : TRUE; + $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2; + $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : TRUE; + $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : TRUE; + $AxisFontName = isset($Format["AxisFontName"]) ? $Format["AxisFontName"] : $this->pChartObject->FontName; + $AxisFontSize = isset($Format["AxisFontSize"]) ? $Format["AxisFontSize"] : $this->pChartObject->FontSize; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : FALSE; + $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : TRUE; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4; + $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2; + $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID; + $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID; + $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID; + $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100; + $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255; + $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255; + $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255; + $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : TRUE; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50; + $BackgroundGradient= isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : NULL; + $Layout = isset($Format["Layout"]) ? $Format["Layout"] : RADAR_LAYOUT_STAR; + $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4; + $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : TRUE; + $SkipLabels = isset($Format["SkipLabels"]) ? $Format["SkipLabels"] : 1; + $LabelMiddle = isset($Format["LabelMiddle"]) ? $Format["LabelMiddle"] : FALSE; + $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : TRUE; + $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255; + $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255; + $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255; + $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED; + $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4; + $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : TRUE; + $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4; + $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30; + $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : TRUE; + $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : TRUE; + $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : FALSE; + $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : 40; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + /* Cancel default tick length if ticks not enabled */ + if ( $DrawTicks == FALSE ) { $TicksLength = 0; } + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + /* Catch the number of required axis */ + $LabelSerie = $Data["Abscissa"]; + if ( $LabelSerie != "" ) + { $Points = count($Data["Series"][$LabelSerie]["Data"]); } + else + { + $Points = 0; + foreach($Data["Series"] as $SerieName => $DataArray) + { if ( count($DataArray["Data"]) > $Points ) { $Points = count($DataArray["Data"]); } } + } + + /* Draw the axis */ + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $EdgeHeight = min(($X2-$X1)/2,($Y2-$Y1)/2); + if ( $WriteLabels ) + $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength; + + /* Determine the scale if set to automatic */ + if ( $SegmentHeight == SEGMENT_HEIGHT_AUTO) + { + if ( $FixedMax != VOID ) + $Max = $FixedMax; + else + { + $Max = 0; + foreach($Data["Series"] as $SerieName => $DataArray) + { + if ( $SerieName != $LabelSerie ) + { + if ( max($DataArray["Data"]) > $Max ) { $Max = max($DataArray["Data"]); } + } + } + } + $MaxSegments = $EdgeHeight/20; + $Scale = $Object->computeScale(0,$Max,$MaxSegments,array(1,2,5)); + + $Segments = $Scale["Rows"]; + $SegmentHeight = $Scale["RowHeight"]; + } + + if ( $LabelMiddle && $SkipLabels == 1 ) + { $Axisoffset = (360/$Points)/2; } + elseif ( $LabelMiddle && $SkipLabels != 1 ) + { $Axisoffset = (360/($Points/$SkipLabels))/2; } + elseif ( !$LabelMiddle ) + { $Axisoffset = 0; } + + /* Background processing */ + if ( $DrawBackground ) + { + $RestoreShadow = $Object->Shadow; + $Object->Shadow = FALSE; + + if ($BackgroundGradient == NULL) + { + if ( $Layout == RADAR_LAYOUT_STAR ) + { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $PointArray = ""; + for($i=0;$i<=360;$i=$i+(360/$Points)) + { + $PointArray[] = cos(deg2rad($i+$AxisRotation)) * $EdgeHeight + $CenterX; + $PointArray[] = sin(deg2rad($i+$AxisRotation)) * $EdgeHeight + $CenterY; + } + $Object->drawPolygon($PointArray,$Color); + } + elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) + { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $Object->drawFilledCircle($CenterX,$CenterY,$EdgeHeight,$Color); + } + } + else + { + $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments; + $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments; + $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments; + $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"]) / $Segments; + + if ( $Layout == RADAR_LAYOUT_STAR ) + { + for($j=$Segments;$j>=1;$j--) + { + $Color = array("R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j,"G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j,"B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j,"Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j); + $PointArray = ""; + + for($i=0;$i<=360;$i=$i+(360/$Points)) + { + $PointArray[] = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $PointArray[] = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + } + $Object->drawPolygon($PointArray,$Color); + } + } + elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) + { + for($j=$Segments;$j>=1;$j--) + { + $Color = array("R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j,"G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j,"B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j,"Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j); + $Object->drawFilledCircle($CenterX,$CenterY,($EdgeHeight/$Segments)*$j,$Color); + } + } + } + $Object->Shadow = $RestoreShadow; + } + + /* Axis to axis lines */ + $Color = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha); + $ColorDotted = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha*.8, "Ticks"=>2); + if ( $Layout == RADAR_LAYOUT_STAR ) + { + for($j=1;$j<=$Segments;$j++) + { + for($i=0;$i<360;$i=$i+(360/$Points)) + { + $EdgeX1 = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $EdgeX2 = cos(deg2rad($i+$AxisRotation+(360/$Points))) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY2 = sin(deg2rad($i+$AxisRotation+(360/$Points))) * ($EdgeHeight/$Segments)*$j + $CenterY; + + $Object->drawLine($EdgeX1,$EdgeY1,$EdgeX2,$EdgeY2,$Color); + } + } + } + elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) + { + for($j=1;$j<=$Segments;$j++) + { + $Radius = ($EdgeHeight/$Segments)*$j; + $Object->drawCircle($CenterX,$CenterY,$Radius,$Radius,$Color); + } + } + + if ( $DrawAxisValues ) + { + if ( $LabelsBackground ) + $Options = array("DrawBox"=>TRUE, "Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"BoxR"=>$LabelsBGR,"BoxG"=>$LabelsBGG,"BoxB"=>$LabelsBGB,"BoxAlpha"=>$LabelsBGAlpha); + else + $Options = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE); + + if ( $AxisBoxRounded ) { $Options["BoxRounded"] = TRUE; } + + $Options["FontName"] = $AxisFontName; + $Options["FontSize"] = $AxisFontSize; + + $Angle = 360 / ($Points*2); + for($j=1;$j<=$Segments;$j++) + { + $Label = $j * $SegmentHeight; + + if ( $Layout == RADAR_LAYOUT_CIRCLE ) + { + $EdgeX1 = cos(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + } + elseif ( $Layout == RADAR_LAYOUT_STAR ) + { + $EdgeX1 = cos(deg2rad($AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $EdgeX2 = cos(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY2 = sin(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + + $EdgeX1 = ($EdgeX2 - $EdgeX1)/2 + $EdgeX1; + $EdgeY1 = ($EdgeY2 - $EdgeY1)/2 + $EdgeY1; + } + + $Object->drawText($EdgeX1,$EdgeY1,$Label,$Options); + } + } + + /* Axis lines */ + $ID = 0; + for($i=0;$i<360;$i=$i+(360/$Points)) + { + $EdgeX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterX; + $EdgeY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterY; + + if ($ID % $SkipLabels == 0) + { $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$Color); } + else + { $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$ColorDotted); } + + if ( $WriteLabels ) + { + $LabelX = cos(deg2rad($i+$AxisRotation+$Axisoffset)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterX; + $LabelY = sin(deg2rad($i+$AxisRotation+$Axisoffset)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterY; + + if ( $LabelSerie != "" ) + { $Label = isset($Data["Series"][$LabelSerie]["Data"][$ID]) ? $Data["Series"][$LabelSerie]["Data"][$ID] : ""; } + else + $Label = $ID; + + if ($ID % $SkipLabels == 0) + { + if ( $LabelPos == RADAR_LABELS_ROTATED ) + $Object->drawText($LabelX,$LabelY,$Label,array("Angle"=>(360-($i+$AxisRotation+$Axisoffset))-90,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + else + { + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPLEFT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPRIGHT)); } + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPMIDDLE)); } + } + } + } + $ID++; + } + + /* Compute the plots position */ + $ID = 0; $Plot = ""; + foreach($Data["Series"] as $SerieName => $DataS) + { + if ( $SerieName != $LabelSerie ) + { + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + foreach($DataS["Data"] as $Key => $Value) + { + $Angle = (360/$Points) * $Key; + $Length = ($EdgeHeight/($Segments*$SegmentHeight))*$Value; + + $X = cos(deg2rad($Angle+$AxisRotation)) * $Length + $CenterX; + $Y = sin(deg2rad($Angle+$AxisRotation)) * $Length + $CenterY; + + $Plot[$ID][] = array($X,$Y,$Value); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($PointRadius),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$DataS["Description"],$Data["Series"][$LabelSerie]["Data"][$Key]." = ".$Value); } + } + $ID++; + } + } + + /* Draw all that stuff! */ + foreach($Plot as $ID => $Points) + { + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + + /* Draw the polygons */ + if ( $DrawPoly ) + { + if ($PolyAlpha != NULL) + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$PolyAlpha,"Surrounding"=>$PointSurrounding); + + $PointsArray = ""; + for($i=0; $idrawPolygon($PointsArray,$Color); + } + + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + + /* Bubble and labels settings */ + $TextSettings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontName"=>$ValueFontName,"FontSize"=>$ValueFontSize,"R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"]); + $InnerColor = array("R"=>$InnerBubbleR,"G"=>$InnerBubbleG,"B"=>$InnerBubbleB,"Alpha"=>$InnerBubbleAlpha); + if ( $OuterBubbleR != VOID ) + $OuterColor = array("R"=>$OuterBubbleR,"G"=>$OuterBubbleG,"B"=>$OuterBubbleB,"Alpha"=>$OuterBubbleAlpha); + else + $OuterColor = array("R"=>$Palette[$ID]["R"]+20,"G"=>$Palette[$ID]["G"]+20,"B"=>$Palette[$ID]["B"]+20,"Alpha"=>$Palette[$ID]["Alpha"]); + + /* Loop to the starting points if asked */ + if ( $LineLoopStart && $DrawLines ) + $Object->drawLine($Points[count($Points)-1][0],$Points[count($Points)-1][1],$Points[0][0],$Points[0][1],$Color); + + /* Draw the lines & points */ + for($i=0; $idrawLine($Points[$i][0],$Points[$i][1],$Points[$i+1][0],$Points[$i+1][1],$Color); + + if ( $DrawPoints ) + $Object->drawFilledCircle($Points[$i][0],$Points[$i][1],$PointRadius,$Color); + + if ( $WriteValuesInBubble && $WriteValues ) + { + $TxtPos = $this->pChartObject->getTextBox($Points[$i][0],$Points[$i][1],$ValueFontName,$ValueFontSize,0,$Points[$i][2]); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding*2)/2); + + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius+$OuterBubbleRadius,$OuterColor); + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius,$InnerColor); + } + + if ( $WriteValues ) + $this->pChartObject->drawText($Points[$i][0]-1,$Points[$i][1]-1,$Points[$i][2],$TextSettings); + } + } + } + + + + /* Draw a radar chart */ + function drawPolar($Object,$Values,$Format="") + { + $this->pChartObject = $Object; + + $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID; + $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60; + $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60; + $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50; + $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : -90; + $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : TRUE; + $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2; + $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : TRUE; + $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : TRUE; + $AxisFontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $AxisFontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : FALSE; + $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : TRUE; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4; + $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2; + $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID; + $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID; + $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID; + $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100; + $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255; + $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255; + $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255; + $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : TRUE; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50; + $BackgroundGradient= isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : NULL; + $AxisSteps = isset($Format["AxisSteps"]) ? $Format["AxisSteps"] : 20; + $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4; + $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : TRUE; + $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : TRUE; + $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255; + $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255; + $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255; + $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED; + $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4; + $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : TRUE; + $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4; + $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30; + $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : TRUE; + $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : FALSE; + $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : FALSE; + $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : NULL; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + + if ( $AxisBoxRounded ) { $DrawAxisValues = TRUE; } + + /* Cancel default tick length if ticks not enabled */ + if ( $DrawTicks == FALSE ) { $TicksLength = 0; } + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + /* Catch the number of required axis */ + $LabelSerie = $Data["Abscissa"]; + if ( $LabelSerie != "" ) + { $Points = count($Data["Series"][$LabelSerie]["Data"]); } + else + { + $Points = 0; + foreach($Data["Series"] as $SerieName => $DataArray) + { if ( count($DataArray["Data"]) > $Points ) { $Points = count($DataArray["Data"]); } } + } + + /* Draw the axis */ + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $EdgeHeight = min(($X2-$X1)/2,($Y2-$Y1)/2); + if ( $WriteLabels ) + $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength; + + /* Determine the scale if set to automatic */ + if ( $SegmentHeight == SEGMENT_HEIGHT_AUTO) + { + if ( $FixedMax != VOID ) + $Max = $FixedMax; + else + { + $Max = 0; + foreach($Data["Series"] as $SerieName => $DataArray) + { + if ( $SerieName != $LabelSerie ) + { + if ( max($DataArray["Data"]) > $Max ) { $Max = max($DataArray["Data"]); } + } + } + } + $MaxSegments = $EdgeHeight/20; + $Scale = $Object->computeScale(0,$Max,$MaxSegments,array(1,2,5)); + + $Segments = $Scale["Rows"]; + $SegmentHeight = $Scale["RowHeight"]; + } + + + /* Background processing */ + if ( $DrawBackground ) + { + $RestoreShadow = $Object->Shadow; + $Object->Shadow = FALSE; + + if ($BackgroundGradient == NULL) + { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $Object->drawFilledCircle($CenterX,$CenterY,$EdgeHeight,$Color); + } + else + { + $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments; + $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments; + $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments; + $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"]) / $Segments; + + for($j=$Segments;$j>=1;$j--) + { + $Color = array("R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j,"G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j,"B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j,"Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j); + $Object->drawFilledCircle($CenterX,$CenterY,($EdgeHeight/$Segments)*$j,$Color); + } + } + $Object->Shadow = $RestoreShadow; + } + + /* Axis to axis lines */ + $Color = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha); + for($j=1;$j<=$Segments;$j++) + { + $Radius = ($EdgeHeight/$Segments)*$j; + $Object->drawCircle($CenterX,$CenterY,$Radius,$Radius,$Color); + } + + if ( $DrawAxisValues ) + { + if ( $LabelsBackground ) + $Options = array("DrawBox"=>TRUE, "Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"BoxR"=>$LabelsBGR,"BoxG"=>$LabelsBGG,"BoxB"=>$LabelsBGB,"BoxAlpha"=>$LabelsBGAlpha); + else + $Options = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE); + + if ( $AxisBoxRounded ) { $Options["BoxRounded"] = TRUE; } + + $Options["FontName"] = $AxisFontName; + $Options["FontSize"] = $AxisFontSize; + + $Angle = 360 / ($Points*2); + for($j=1;$j<=$Segments;$j++) + { + $EdgeX1 = cos(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $Label = $j*$SegmentHeight; + + $Object->drawText($EdgeX1,$EdgeY1,$Label,$Options); + } + } + + /* Axis lines */ + $ID = 0; + for($i=0;$i<=359;$i=$i+$AxisSteps) + { + $EdgeX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterX; + $EdgeY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterY; + + $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$Color); + + if ( $WriteLabels ) + { + $LabelX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterX; + $LabelY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterY; + $Label = $i."°"; + + if ( $LabelPos == RADAR_LABELS_ROTATED ) + $Object->drawText($LabelX,$LabelY,$Label,array("Angle"=>(360-$i),"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + else + { + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPLEFT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPRIGHT)); } + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPMIDDLE)); } + } + } + $ID++; + } + + /* Compute the plots position */ + $ID = 0; $Plot = ""; + foreach($Data["Series"] as $SerieName => $DataSet) + { + if ( $SerieName != $LabelSerie ) + { + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + foreach($DataSet["Data"] as $Key => $Value) + { + $Angle = $Data["Series"][$LabelSerie]["Data"][$Key]; + $Length = ($EdgeHeight/($Segments*$SegmentHeight))*$Value; + + $X = cos(deg2rad($Angle+$AxisRotation)) * $Length + $CenterX; + $Y = sin(deg2rad($Angle+$AxisRotation)) * $Length + $CenterY; + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($PointRadius),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$DataSet["Description"],$Data["Series"][$LabelSerie]["Data"][$Key]."° = ".$Value); } + + $Plot[$ID][] = array($X,$Y,$Value); + } + $ID++; + } + } + + /* Draw all that stuff! */ + foreach($Plot as $ID => $Points) + { + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + + /* Draw the polygons */ + if ( $DrawPoly ) + { + if ($PolyAlpha != NULL) + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$PolyAlpha,"Surrounding"=>$PointSurrounding); + + $PointsArray = ""; + for($i=0; $idrawPolygon($PointsArray,$Color); + } + + $Color = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"],"Surrounding"=>$PointSurrounding); + + /* Bubble and labels settings */ + $TextSettings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontName"=>$ValueFontName,"FontSize"=>$ValueFontSize,"R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"]); + $InnerColor = array("R"=>$InnerBubbleR,"G"=>$InnerBubbleG,"B"=>$InnerBubbleB,"Alpha"=>$InnerBubbleAlpha); + if ( $OuterBubbleR != VOID ) + $OuterColor = array("R"=>$OuterBubbleR,"G"=>$OuterBubbleG,"B"=>$OuterBubbleB,"Alpha"=>$OuterBubbleAlpha); + else + $OuterColor = array("R"=>$Palette[$ID]["R"]+20,"G"=>$Palette[$ID]["G"]+20,"B"=>$Palette[$ID]["B"]+20,"Alpha"=>$Palette[$ID]["Alpha"]); + + /* Loop to the starting points if asked */ + if ( $LineLoopStart && $DrawLines ) + $Object->drawLine($Points[count($Points)-1][0],$Points[count($Points)-1][1],$Points[0][0],$Points[0][1],$Color); + + /* Draw the lines & points */ + for($i=0; $idrawLine($Points[$i][0],$Points[$i][1],$Points[$i+1][0],$Points[$i+1][1],$Color); + + if ( $DrawPoints ) + $Object->drawFilledCircle($Points[$i][0],$Points[$i][1],$PointRadius,$Color); + + if ( $WriteValuesInBubble && $WriteValues ) + { + $TxtPos = $this->pChartObject->getTextBox($Points[$i][0],$Points[$i][1],$ValueFontName,$ValueFontSize,0,$Points[$i][2]); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding*2)/2); + + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius+$OuterBubbleRadius,$OuterColor); + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius,$InnerColor); + } + + if ( $WriteValues ) + $this->pChartObject->drawText($Points[$i][0]-1,$Points[$i][1]-1,$Points[$i][2],$TextSettings); + } + } + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pScatter.class.php b/webdata/graph/pchart/class/pScatter.class.php new file mode 100644 index 0000000..6129fc8 --- /dev/null +++ b/webdata/graph/pchart/class/pScatter.class.php @@ -0,0 +1,1158 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /* Prepare the scale */ + function drawScatterScale($Format="") + { + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : SCALE_MODE_FLOATING; + $Floating = isset($Format["Floating"]) ? $Format["Floating"] : FALSE; + $XLabelsRotation = isset($Format["XLabelsRotation"]) ? $Format["XLabelsRotation"] : 90; + $MinDivHeight = isset($Format["MinDivHeight"]) ? $Format["MinDivHeight"] : 20; + $Factors = isset($Format["Factors"]) ? $Format["Factors"] : array(1,2,5); + $ManualScale = isset($Format["ManualScale"]) ? $Format["ManualScale"] : array("0"=>array("Min"=>-100,"Max"=>100)); + $XMargin = isset($Format["XMargin"]) ? $Format["XMargin"] : 0; + $YMargin = isset($Format["YMargin"]) ? $Format["YMargin"] : 0; + $ScaleSpacing = isset($Format["ScaleSpacing"]) ? $Format["ScaleSpacing"] : 15; + $InnerTickWidth = isset($Format["InnerTickWidth"]) ? $Format["InnerTickWidth"] : 2; + $OuterTickWidth = isset($Format["OuterTickWidth"]) ? $Format["OuterTickWidth"] : 2; + $DrawXLines = isset($Format["DrawXLines"]) ? $Format["DrawXLines"] : ALL; + $DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL; + $GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4; + $GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255; + $GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255; + $GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255; + $GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40; + $AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0; + $AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0; + $AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 100; + $TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0; + $TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0; + $TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0; + $TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100; + $DrawSubTicks = isset($Format["DrawSubTicks"]) ? $Format["DrawSubTicks"] : FALSE; + $InnerSubTickWidth = isset($Format["InnerSubTickWidth"]) ? $Format["InnerSubTickWidth"] : 0; + $OuterSubTickWidth = isset($Format["OuterSubTickWidth"]) ? $Format["OuterSubTickWidth"] : 2; + $SubTickR = isset($Format["SubTickR"]) ? $Format["SubTickR"] : 255; + $SubTickG = isset($Format["SubTickG"]) ? $Format["SubTickG"] : 0; + $SubTickB = isset($Format["SubTickB"]) ? $Format["SubTickB"] : 0; + $SubTickAlpha = isset($Format["SubTickAlpha"]) ? $Format["SubTickAlpha"] : 100; + $XReleasePercent = isset($Format["XReleasePercent"]) ? $Format["XReleasePercent"] : 1; + $DrawArrows = isset($Format["DrawArrows"]) ? $Format["DrawArrows"] : FALSE; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 8; + $CycleBackground = isset($Format["CycleBackground"]) ? $Format["CycleBackground"] : FALSE; + $BackgroundR1 = isset($Format["BackgroundR1"]) ? $Format["BackgroundR1"] : 255; + $BackgroundG1 = isset($Format["BackgroundG1"]) ? $Format["BackgroundG1"] : 255; + $BackgroundB1 = isset($Format["BackgroundB1"]) ? $Format["BackgroundB1"] : 255; + $BackgroundAlpha1 = isset($Format["BackgroundAlpha1"]) ? $Format["BackgroundAlpha1"] : 10; + $BackgroundR2 = isset($Format["BackgroundR2"]) ? $Format["BackgroundR2"] : 230; + $BackgroundG2 = isset($Format["BackgroundG2"]) ? $Format["BackgroundG2"] : 230; + $BackgroundB2 = isset($Format["BackgroundB2"]) ? $Format["BackgroundB2"] : 230; + $BackgroundAlpha2 = isset($Format["BackgroundAlpha2"]) ? $Format["BackgroundAlpha2"] : 10; + + /* Check if we have at least both one X and Y axis */ + $GotXAxis = FALSE; $GotYAxis = FALSE; + foreach($this->pDataObject->Data["Axis"] as $AxisID => $AxisSettings) + { + if ( $AxisSettings["Identity"] == AXIS_X ) { $GotXAxis = TRUE; } + if ( $AxisSettings["Identity"] == AXIS_Y ) { $GotYAxis = TRUE; } + } + if ( !$GotXAxis ) { return(SCATTER_MISSING_X_SERIE); } + if ( !$GotYAxis ) { return(SCATTER_MISSING_Y_SERIE); } + + /* Skip a NOTICE event in case of an empty array */ + if ( $DrawYLines == NONE ) { $DrawYLines = array("zarma"=>"31"); } + + $Data = $this->pDataObject->getData(); + + foreach($Data["Axis"] as $AxisID => $AxisSettings) + { + if ( $AxisSettings["Identity"] == AXIS_X) + { $Width = $this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1 - $XMargin*2; } + else + { $Width = $this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1 - $YMargin*2; } + + $AxisMin = ABSOLUTE_MAX; $AxisMax = OUT_OF_SIGHT; + if ( $Mode == SCALE_MODE_FLOATING ) + { + foreach($Data["Series"] as $SerieID => $SerieParameter) + { + if ( $SerieParameter["Axis"] == $AxisID && $Data["Series"][$SerieID]["isDrawable"] ) + { + $AxisMax = max($AxisMax,$Data["Series"][$SerieID]["Max"]); + $AxisMin = min($AxisMin,$Data["Series"][$SerieID]["Min"]); + } + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + } + elseif ( $Mode == SCALE_MODE_MANUAL ) + { + if ( isset($ManualScale[$AxisID]["Min"]) && isset($ManualScale[$AxisID]["Max"]) ) + { + $Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"]; + $Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"]; + } + else + { echo "Manual scale boundaries not set."; exit(); } + } + + /* Full manual scale */ + if ( isset($ManualScale[$AxisID]["Rows"]) && isset($ManualScale[$AxisID]["RowHeight"]) ) + $Scale = array("Rows"=>$ManualScale[$AxisID]["Rows"],"RowHeight"=>$ManualScale[$AxisID]["RowHeight"],"XMin"=>$ManualScale[$AxisID]["Min"],"XMax"=>$ManualScale[$AxisID]["Max"]); + else + { + $MaxDivs = floor($Width/$MinDivHeight); + $Scale = $this->pChartObject->computeScale($Data["Axis"][$AxisID]["Min"],$Data["Axis"][$AxisID]["Max"],$MaxDivs,$Factors,$AxisID); + } + + $Data["Axis"][$AxisID]["Margin"] = $AxisSettings["Identity"] == AXIS_X ? $XMargin : $YMargin; + $Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"]; + $Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"]; + $Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"]; + $Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"]; + + if ( isset($Scale["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = $Scale["Format"]; } + + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { $Data["Axis"][$AxisID]["Display"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = NULL; } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { $Data["Axis"][$AxisID]["Unit"] = NULL; } + } + + /* Get the default font color */ + $FontColorRo = $this->pChartObject->FontColorR; $FontColorGo = $this->pChartObject->FontColorG; $FontColorBo = $this->pChartObject->FontColorB; + + /* Set the original boundaries */ + $AxisPos["L"] = $this->pChartObject->GraphAreaX1; $AxisPos["R"] = $this->pChartObject->GraphAreaX2; $AxisPos["T"] = $this->pChartObject->GraphAreaY1; $AxisPos["B"] = $this->pChartObject->GraphAreaY2; + + foreach($Data["Axis"] as $AxisID => $AxisSettings) + { + if ( isset($AxisSettings["Color"]) ) + { + $AxisR = $AxisSettings["Color"]["R"]; $AxisG = $AxisSettings["Color"]["G"]; $AxisB = $AxisSettings["Color"]["B"]; + $TickR = $AxisSettings["Color"]["R"]; $TickG = $AxisSettings["Color"]["G"]; $TickB = $AxisSettings["Color"]["B"]; + $this->pChartObject->setFontProperties(array("R"=>$AxisSettings["Color"]["R"],"G"=>$AxisSettings["Color"]["G"],"B"=>$AxisSettings["Color"]["B"])); + } + else + { + $AxisR = $AxisRo; $AxisG = $AxisGo; $AxisB = $AxisBo; + $TickR = $TickRo; $TickG = $TickGo; $TickB = $TickBo; + $this->pChartObject->setFontProperties(array("R"=>$FontColorRo,"G"=>$FontColorGo,"B"=>$FontColorBo)); + } + + $LastValue = "w00t"; $ID = 1; + if ( $AxisSettings["Identity"] == AXIS_X ) + { + if ( $AxisSettings["Position"] == AXIS_POSITION_BOTTOM ) + { + if ( $XLabelsRotation == 0 ) { $LabelAlign = TEXT_ALIGN_TOPMIDDLE; $LabelOffset = 2; } + if ( $XLabelsRotation > 0 && $XLabelsRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $LabelOffset = 5; } + if ( $XLabelsRotation == 180 ) { $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; $LabelOffset = 5; } + if ( $XLabelsRotation > 180 && $XLabelsRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $LabelOffset = 2; } + + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1+$AxisSettings["Margin"],$AxisPos["B"],$this->pChartObject->GraphAreaX2-$AxisSettings["Margin"],$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1,$AxisPos["B"],$this->pChartObject->GraphAreaX2,$AxisPos["B"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->pChartObject->drawArrow($this->pChartObject->GraphAreaX2-$AxisSettings["Margin"],$AxisPos["B"],$this->pChartObject->GraphAreaX2+($ArrowSize*2),$AxisPos["B"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Width = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) - $AxisSettings["Margin"]*2; + $Step = $Width / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MaxBottom = $AxisPos["B"]; + $LastX = NULL; + for($i=0;$i<=$AxisSettings["Rows"];$i++) + { + $XPos = $this->pChartObject->GraphAreaX1 + $AxisSettings["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + $Value = $this->pChartObject->scaleFormat($AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i,$AxisSettings["Display"],$AxisSettings["Format"],$AxisSettings["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastX != NULL && $CycleBackground && ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) )) { $this->pChartObject->drawFilledRectangle($LastX,$this->pChartObject->GraphAreaY1+$FloatingOffset,$XPos,$this->pChartObject->GraphAreaY2-$FloatingOffset,$BGColor); } + + if ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) { $this->pChartObject->drawLine($XPos,$this->pChartObject->GraphAreaY1+$FloatingOffset,$XPos,$this->pChartObject->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) + $this->pChartObject->drawLine($XPos+$SubTicksSize,$YPos-$InnerSubTickWidth,$XPos+$SubTicksSize,$YPos+$OuterSubTickWidth,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->pChartObject->drawLine($XPos,$YPos-$InnerTickWidth,$XPos,$YPos+$OuterTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->pChartObject->drawText($XPos,$YPos+$OuterTickWidth+$LabelOffset,$Value,array("Angle"=>$XLabelsRotation,"Align"=>$LabelAlign)); + $TxtBottom = $YPos+2+$OuterTickWidth+2+($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtBottom); + + $LastX = $XPos; + } + + if ( isset($AxisSettings["Name"]) ) + { + $YPos = $MaxBottom+2; + $XPos = $this->pChartObject->GraphAreaX1+($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1)/2; + $Bounds = $this->pChartObject->drawText($XPos,$YPos,$AxisSettings["Name"],array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + $MaxBottom = $Bounds[0]["Y"]; + + $this->pDataObject->Data["GraphArea"]["Y2"] = $MaxBottom + $this->pChartObject->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } + elseif ( $AxisSettings["Position"] == AXIS_POSITION_TOP ) + { + if ( $XLabelsRotation == 0 ) { $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; $LabelOffset = 2; } + if ( $XLabelsRotation > 0 && $XLabelsRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $LabelOffset = 2; } + if ( $XLabelsRotation == 180 ) { $LabelAlign = TEXT_ALIGN_TOPMIDDLE; $LabelOffset = 5; } + if ( $XLabelsRotation > 180 && $SLabelxRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $LabelOffset = 5; } + + if ( $Floating ) + { $FloatingOffset = $YMargin; $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1+$AxisSettings["Margin"],$AxisPos["T"],$this->pChartObject->GraphAreaX2-$AxisSettings["Margin"],$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1,$AxisPos["T"],$this->pChartObject->GraphAreaX2,$AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->pChartObject->drawArrow($this->pChartObject->GraphAreaX2-$AxisSettings["Margin"],$AxisPos["T"],$this->pChartObject->GraphAreaX2+($ArrowSize*2),$AxisPos["T"],array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Width = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) - $AxisSettings["Margin"]*2; + $Step = $Width / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MinTop = $AxisPos["T"]; + $LastX = NULL; + for($i=0;$i<=$AxisSettings["Rows"];$i++) + { + $XPos = $this->pChartObject->GraphAreaX1 + $AxisSettings["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + $Value = $this->pChartObject->scaleFormat($AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i,$AxisSettings["Display"],$AxisSettings["Format"],$AxisSettings["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastX != NULL && $CycleBackground && ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) )) { $this->pChartObject->drawFilledRectangle($LastX,$this->pChartObject->GraphAreaY1+$FloatingOffset,$XPos,$this->pChartObject->GraphAreaY2-$FloatingOffset,$BGColor); } + + if ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) { $this->pChartObject->drawLine($XPos,$this->pChartObject->GraphAreaY1+$FloatingOffset,$XPos,$this->pChartObject->GraphAreaY2-$FloatingOffset,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) + $this->pChartObject->drawLine($XPos+$SubTicksSize,$YPos-$OuterSubTickWidth,$XPos+$SubTicksSize,$YPos+$InnerSubTickWidth,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->pChartObject->drawLine($XPos,$YPos-$OuterTickWidth,$XPos,$YPos+$InnerTickWidth,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->pChartObject->drawText($XPos,$YPos-$OuterTickWidth-$LabelOffset,$Value,array("Angle"=>$XLabelsRotation,"Align"=>$LabelAlign)); + $TxtBox = $YPos-$OuterTickWidth-4-($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtBox); + + $LastX = $XPos; + } + + if ( isset($AxisSettings["Name"]) ) + { + $YPos = $MinTop-2; + $XPos = $this->pChartObject->GraphAreaX1+($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1)/2; + $Bounds = $this->pChartObject->drawText($XPos,$YPos,$AxisSettings["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + $MinTop = $Bounds[2]["Y"]; + + $this->pDataObject->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } + } + elseif ( $AxisSettings["Identity"] == AXIS_Y ) + { + if ( $AxisSettings["Position"] == AXIS_POSITION_LEFT ) + { + + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->pChartObject->drawLine($AxisPos["L"],$this->pChartObject->GraphAreaY1+$AxisSettings["Margin"],$AxisPos["L"],$this->pChartObject->GraphAreaY2-$AxisSettings["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->pChartObject->drawLine($AxisPos["L"],$this->pChartObject->GraphAreaY1,$AxisPos["L"],$this->pChartObject->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->pChartObject->drawArrow($AxisPos["L"],$this->pChartObject->GraphAreaY1+$AxisSettings["Margin"],$AxisPos["L"],$this->pChartObject->GraphAreaY1-($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Height = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) - $AxisSettings["Margin"]*2; + $Step = $Height / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MinLeft = $AxisPos["L"]; + $LastY = NULL; + for($i=0;$i<=$AxisSettings["Rows"];$i++) + { + $YPos = $this->pChartObject->GraphAreaY2 - $AxisSettings["Margin"] - $Step*$i; + $XPos = $AxisPos["L"]; + $Value = $this->pChartObject->scaleFormat($AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i,$AxisSettings["Display"],$AxisSettings["Format"],$AxisSettings["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastY != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->pChartObject->drawFilledRectangle($this->pChartObject->GraphAreaX1+$FloatingOffset,$LastY,$this->pChartObject->GraphAreaX2-$FloatingOffset,$YPos,$BGColor); } + + if ( ($YPos != $this->pChartObject->GraphAreaY1 && $YPos != $this->pChartObject->GraphAreaY2) && ($DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1+$FloatingOffset,$YPos,$this->pChartObject->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) + $this->pChartObject->drawLine($XPos-$OuterSubTickWidth,$YPos-$SubTicksSize,$XPos+$InnerSubTickWidth,$YPos-$SubTicksSize,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->pChartObject->drawLine($XPos-$OuterTickWidth,$YPos,$XPos+$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->pChartObject->drawText($XPos-$OuterTickWidth-2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + $TxtLeft = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($AxisSettings["Name"]) ) + { + $XPos = $MinLeft-2; + $YPos = $this->pChartObject->GraphAreaY1+($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1)/2; + $Bounds = $this->pChartObject->drawText($XPos,$YPos,$AxisSettings["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>90)); + $MinLeft = $Bounds[2]["X"]; + + $this->pDataObject->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } + elseif ( $AxisSettings["Position"] == AXIS_POSITION_RIGHT ) + { + + if ( $Floating ) + { $FloatingOffset = $XMargin; $this->pChartObject->drawLine($AxisPos["R"],$this->pChartObject->GraphAreaY1+$AxisSettings["Margin"],$AxisPos["R"],$this->pChartObject->GraphAreaY2-$AxisSettings["Margin"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + else + { $FloatingOffset = 0; $this->pChartObject->drawLine($AxisPos["R"],$this->pChartObject->GraphAreaY1,$AxisPos["R"],$this->pChartObject->GraphAreaY2,array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha)); } + + if ( $DrawArrows ) { $this->pChartObject->drawArrow($AxisPos["R"],$this->pChartObject->GraphAreaY1+$AxisSettings["Margin"],$AxisPos["R"],$this->pChartObject->GraphAreaY1-($ArrowSize*2),array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize)); } + + $Height = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) - $AxisSettings["Margin"]*2; + $Step = $Height / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MaxLeft = $AxisPos["R"]; + $LastY = NULL; + for($i=0;$i<=$AxisSettings["Rows"];$i++) + { + $YPos = $this->pChartObject->GraphAreaY2 - $AxisSettings["Margin"] - $Step*$i; + $XPos = $AxisPos["R"]; + $Value = $this->pChartObject->scaleFormat($AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i,$AxisSettings["Display"],$AxisSettings["Format"],$AxisSettings["Unit"]); + + if ( $i%2 == 1 ) { $BGColor = array("R"=>$BackgroundR1,"G"=>$BackgroundG1,"B"=>$BackgroundB1,"Alpha"=>$BackgroundAlpha1); } else { $BGColor = array("R"=>$BackgroundR2,"G"=>$BackgroundG2,"B"=>$BackgroundB2,"Alpha"=>$BackgroundAlpha2); } + if ( $LastY != NULL && $CycleBackground && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) )) { $this->pChartObject->drawFilledRectangle($this->pChartObject->GraphAreaX1+$FloatingOffset,$LastY,$this->pChartObject->GraphAreaX2-$FloatingOffset,$YPos,$BGColor); } + + if ( ($YPos != $this->pChartObject->GraphAreaY1 && $YPos != $this->pChartObject->GraphAreaY2) && ($DrawYLines == ALL || in_array($AxisID,$DrawYLines)) ) { $this->pChartObject->drawLine($this->pChartObject->GraphAreaX1+$FloatingOffset,$YPos,$this->pChartObject->GraphAreaX2-$FloatingOffset,$YPos,array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks)); } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) + $this->pChartObject->drawLine($XPos-$InnerSubTickWidth,$YPos-$SubTicksSize,$XPos+$OuterSubTickWidth,$YPos-$SubTicksSize,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + + $this->pChartObject->drawLine($XPos-$InnerTickWidth,$YPos,$XPos+$OuterTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->pChartObject->drawText($XPos+$OuterTickWidth+2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + $TxtLeft = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxLeft = max($MaxLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($AxisSettings["Name"]) ) + { + $XPos = $MaxLeft+6; + $YPos = $this->pChartObject->GraphAreaY1+($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1)/2; + $Bounds = $this->pChartObject->drawText($XPos,$YPos,$AxisSettings["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270)); + $MaxLeft = $Bounds[2]["X"]; + + $this->pDataObject->Data["GraphArea"]["X2"] = $MaxLeft + $this->pChartObject->FontSize; + } + + $AxisPos["R"] = $MaxLeft + $ScaleSpacing; + } + } + } + + $this->pDataObject->saveAxisConfig($Data["Axis"]); + } + + /* Draw a scatter plot chart */ + function drawScatterPlotChart($Format=NULL) + { + $PlotSize = isset($Format["PlotSize"]) ? $Format["PlotSize"] : 3; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 250; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 250; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 250; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $BorderSize = isset($Format["BorderSize"]) ? $Format["BorderSize"] : 1; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : NULL; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + $SerieX = $Series["X"]; $SerieValuesX = $Data["Series"][$SerieX]["Data"]; $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; $SerieValuesY = $Data["Series"][$SerieY]["Data"]; $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + if ( $ImageMapTitle == NULL ) { $Description = $Data["Series"][$Series["X"]]["Description"]." / ".$Data["Series"][$Series["Y"]]["Description"]; } else { $Description = $ImageMapTitle; } + + if ( isset($Series["Picture"]) && $Series["Picture"] != "" ) + { $Picture = $Series["Picture"]; list($PicWidth,$PicHeight,$PicType) = $this->pChartObject->getPicInfo($Picture); } + else + { $Picture = NULL; } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { $Value = $PosArrayX; $PosArrayX = ""; $PosArrayX[0] = $Value; } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { $Value = $PosArrayY; $PosArrayY = ""; $PosArrayY[0] = $Value; } + + $Color = array("R"=>$Series["Color"]["R"],"G"=>$Series["Color"]["G"],"B"=>$Series["Color"]["B"],"Alpha"=>$Series["Color"]["Alpha"]); + + foreach($PosArrayX as $Key => $Value) + { + $X = $Value; $Y = $PosArrayY[$Key]; + + if ( $X != VOID && $Y != VOID ) + { + $RealValue = round($Data["Series"][$Series["X"]]["Data"][$Key],2)." / ".round($Data["Series"][$Series["Y"]]["Data"][$Key],2); + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($PlotSize+$BorderSize),$this->pChartObject->toHTMLColor($Series["Color"]["R"],$Series["Color"]["G"],$Series["Color"]["B"]),$Description,$RealValue); } + + if( isset($Series["Shape"]) ) + { $this->pChartObject->drawShape($X,$Y,$Series["Shape"],$PlotSize,$PlotBorder,$BorderSize,$Series["Color"]["R"],$Series["Color"]["G"],$Series["Color"]["B"],$Series["Color"]["Alpha"],$BorderR,$BorderG,$BorderB,$BorderAlpha); } + elseif ( $Picture == NULL ) + { + if ( $PlotBorder ) { $this->pChartObject->drawFilledCircle($X,$Y,$PlotSize+$BorderSize,$BorderColor); } + $this->pChartObject->drawFilledCircle($X,$Y,$PlotSize,$Color); + } + else + { $this->pChartObject->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); } + } + } + } + } + } + + /* Draw a scatter line chart */ + function drawScatterLineChart($Format=NULL) + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : NULL; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 10; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + /* Parse all the series to draw */ + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + $SerieX = $Series["X"]; $SerieValuesX = $Data["Series"][$SerieX]["Data"]; $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; $SerieValuesY = $Data["Series"][$SerieY]["Data"]; $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + $Ticks = $Series["Ticks"]; + $Weight = $Series["Weight"]; + + if ( $ImageMapTitle == NULL ) { $Description = $Data["Series"][$Series["X"]]["Description"]." / ".$Data["Series"][$Series["Y"]]["Description"]; } else { $Description = $ImageMapTitle; } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { $Value = $PosArrayX; $PosArrayX = ""; $PosArrayX[0] = $Value; } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { $Value = $PosArrayY; $PosArrayY = ""; $PosArrayY[0] = $Value; } + + $Color = array("R"=>$Series["Color"]["R"],"G"=>$Series["Color"]["G"],"B"=>$Series["Color"]["B"],"Alpha"=>$Series["Color"]["Alpha"]); + if ( $Ticks != 0 ) { $Color["Ticks"] = $Ticks; } + if ( $Weight != 0 ) { $Color["Weight"] = $Weight; } + + $LastX = VOID; $LastY = VOID; + foreach($PosArrayX as $Key => $Value) + { + $X = $Value; $Y = $PosArrayY[$Key]; + + if ( $X != VOID && $Y != VOID ) + { + $RealValue = round($Data["Series"][$Series["X"]]["Data"][$Key],2)." / ".round($Data["Series"][$Series["Y"]]["Data"][$Key],2); + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->pChartObject->toHTMLColor($Series["Color"]["R"],$Series["Color"]["G"],$Series["Color"]["B"]),$Description,$RealValue); } + } + + if ( $X != VOID && $Y != VOID && $LastX != VOID && $LastY != VOID) + $this->pChartObject->drawLine($LastX,$LastY,$X,$Y,$Color); + + $LastX = $X; $LastY = $Y; + } + } + } + } + + /* Draw a scatter spline chart */ + function drawScatterSplineChart($Format=NULL) + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : NULL; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 10; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + $SerieX = $Series["X"]; $SerieValuesX = $Data["Series"][$SerieX]["Data"]; $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; $SerieValuesY = $Data["Series"][$SerieY]["Data"]; $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + $Ticks = $Series["Ticks"]; + $Weight = $Series["Weight"]; + + if ( $ImageMapTitle == NULL ) { $Description = $Data["Series"][$Series["X"]]["Description"]." / ".$Data["Series"][$Series["Y"]]["Description"]; } else { $Description = $ImageMapTitle; } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { $Value = $PosArrayX; $PosArrayX = ""; $PosArrayX[0] = $Value; } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { $Value = $PosArrayY; $PosArrayY = ""; $PosArrayY[0] = $Value; } + + $SplineSettings = array("R"=>$Series["Color"]["R"],"G"=>$Series["Color"]["G"],"B"=>$Series["Color"]["B"],"Alpha"=>$Series["Color"]["Alpha"]); + if ( $Ticks != 0 ) { $SplineSettings["Ticks"] = $Ticks; } + if ( $Weight != 0 ) { $SplineSettings["Weight"] = $Weight; } + + $LastX = VOID; $LastY = VOID; $WayPoints = ""; $Forces = ""; + foreach($PosArrayX as $Key => $Value) + { + $X = $Value; $Y = $PosArrayY[$Key]; + $Force = $this->pChartObject->getLength($LastX,$LastY,$X,$Y)/5; + + if ( $X != VOID && $Y != VOID ) + { + $RealValue = round($Data["Series"][$Series["X"]]["Data"][$Key],2)." / ".round($Data["Series"][$Series["Y"]]["Data"][$Key],2); + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".$ImageMapPlotSize,$this->pChartObject->toHTMLColor($Series["Color"]["R"],$Series["Color"]["G"],$Series["Color"]["B"]),$Description,$RealValue); } + } + + if ( $X != VOID && $Y != VOID ) + { $WayPoints[] = array($X,$Y); $Forces[] = $Force; } + + if ( $Y == VOID || $X == VOID ) + { $SplineSettings["Forces"] = $Forces; $this->pChartObject->drawSpline($WayPoints,$SplineSettings); $WayPoints = ""; $Forces = "";} + + $LastX = $X; $LastY = $Y; + } + $SplineSettings["Forces"] = $Forces; + $this->pChartObject->drawSpline($WayPoints,$SplineSettings); + } + } + } + + /* Return the scaled plot position */ + function getPosArray($Values,$AxisID) + { + $Data = $this->pDataObject->getData(); + + if ( !is_array($Values) ) { $Values = array($Values); } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) + { + $Height = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + $Result = ""; + foreach($Values as $Key => $Value) + { + if ( $Value == VOID ) + $Result[] = VOID; + else + $Result[] = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + + if ( count($Result) == 1 ) { return($Result[0]); } else { return($Result); } + } + else + { + $Height = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + $Result = ""; + foreach($Values as $Key => $Value) + { + if ( $Value == VOID ) + $Result[] = VOID; + else + $Result[] = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] - ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + + if ( count($Result) == 1 ) { return($Result[0]); } else { return($Result); } + } + } + + /* Draw the legend of the active series */ + function drawScatterLegend($X,$Y,$Format="") + { + $Family = isset($Format["Family"]) ? $Format["Family"] : LEGEND_FAMILY_BOX; + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR; + $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG; + $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $R = isset($Format["R"]) ? $Format["R"] : 200; + $G = isset($Format["G"]) ? $Format["G"] : 200; + $B = isset($Format["B"]) ? $Format["B"] : 200; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE && isset($Series["Picture"])) + { + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Series["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->pChartObject->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + if ( $Mode == LEGEND_VERTICAL ) + { + $BoxArray = $this->pChartObject->getTextBox($vX+$IconAreaWidth+4,$vY+$IconAreaHeight/2,$FontName,$FontSize,0,$Series["Description"]); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Lines = preg_split("/\n/",$Series["Description"]); + $vY = $vY + max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->pChartObject->getTextBox($vX+$IconAreaWidth+6,$Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key),$FontName,$FontSize,0,$Value); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { $Boundaries["B"] = $vY+$IconAreaHeight+$TopOffset; } + + if ( $Style == LEGEND_ROUND ) + $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + elseif ( $Style == LEGEND_BOX ) + $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); + + $RestoreShadow = $this->pChartObject->Shadow; $this->Shadow = FALSE; + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + $R = $Series["Color"]["R"]; $G = $Series["Color"]["G"]; $B = $Series["Color"]["B"]; + $Ticks = $Series["Ticks"]; $Weight = $Series["Weight"]; + + if ( isset($Series["Picture"]) ) + { + $Picture = $Series["Picture"]; + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Picture); + $PicX = $X+$IconAreaWidth/2; $PicY = $Y+$IconAreaHeight/2; + + $this->pChartObject->drawFromPNG($PicX-$PicWidth/2,$PicY-$PicHeight/2,$Picture); + } + else + { + if ( $Family == LEGEND_FAMILY_BOX ) + { + if ( $BoxWidth != $IconAreaWidth ) { $XOffset = floor(($IconAreaWidth-$BoxWidth)/2); } else { $XOffset = 0; } + if ( $BoxHeight != $IconAreaHeight ) { $YOffset = floor(($IconAreaHeight-$BoxHeight)/2); } else { $YOffset = 0; } + + $this->pChartObject->drawFilledRectangle($X+1+$XOffset,$Y+1+$YOffset,$X+$BoxWidth+$XOffset+1,$Y+$BoxHeight+1+$YOffset,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); + $this->pChartObject->drawFilledRectangle($X+$XOffset,$Y+$YOffset,$X+$BoxWidth+$XOffset,$Y+$BoxHeight+$YOffset,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); + } + elseif ( $Family == LEGEND_FAMILY_CIRCLE ) + { + $this->pChartObject->drawFilledCircle($X+1+$IconAreaWidth/2,$Y+1+$IconAreaHeight/2,min($IconAreaHeight/2,$IconAreaWidth/2),array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); + $this->pChartObject->drawFilledCircle($X+$IconAreaWidth/2,$Y+$IconAreaHeight/2,min($IconAreaHeight/2,$IconAreaWidth/2),array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); + } + elseif ( $Family == LEGEND_FAMILY_LINE ) + { + $this->pChartObject->drawLine($X+1,$Y+1+$IconAreaHeight/2,$X+1+$IconAreaWidth,$Y+1+$IconAreaHeight/2,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20,"Ticks"=>$Ticks,"Weight"=>$Weight)); + $this->pChartObject->drawLine($X,$Y+$IconAreaHeight/2,$X+$IconAreaWidth,$Y+$IconAreaHeight/2,array("R"=>$R,"G"=>$G,"B"=>$B,"Ticks"=>$Ticks,"Weight"=>$Weight)); + } + } + + if ( $Mode == LEGEND_VERTICAL ) + { + $Lines = preg_split("/\n/",$Series["Description"]); + foreach($Lines as $Key => $Value) + $this->pChartObject->drawText($X+$IconAreaWidth+4,$Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key),$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT)); + + $Y=$Y+max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->pChartObject->drawText($X+$IconAreaWidth+4,$Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key),$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT)); + $Width[] = $BoxArray[1]["X"]; + } + $X=max($Width)+2+$XStep; + } + } + } + + $this->Shadow = $RestoreShadow; + } + + /* Get the legend box size */ + function getScatterLegendSize($Format="") + { + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + + $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5; + $XStep = $BoxSize + 5; + + $X=100; $Y=100; + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE && isset($Series["Picture"])) + { + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Series["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->pChartObject->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + if ( $Mode == LEGEND_VERTICAL ) + { + $BoxArray = $this->pChartObject->getTextBox($vX+$IconAreaWidth+4,$vY+$IconAreaHeight/2,$FontName,$FontSize,0,$Series["Description"]); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Lines = preg_split("/\n/",$Series["Description"]); + $vY = $vY + max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } + elseif ( $Mode == LEGEND_HORIZONTAL ) + { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) + { + $BoxArray = $this->pChartObject->getTextBox($vX+$IconAreaWidth+6,$Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key),$FontName,$FontSize,0,$Value); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; } + + $Width = ($Boundaries["R"]+$Margin) - ($Boundaries["L"]-$Margin); + $Height = ($Boundaries["B"]+$Margin) - ($Boundaries["T"]-$Margin); + + return(array("Width"=>$Width,"Height"=>$Height)); + } + + /* Draw the line of best fit */ + function drawScatterBestFit($Format="") + { + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 0; + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) + { + if ( $Series["isDrawable"] == TRUE ) + { + $SerieX = $Series["X"]; $SerieValuesX = $Data["Series"][$SerieX]["Data"]; $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; $SerieValuesY = $Data["Series"][$SerieY]["Data"]; $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + $Color = array("R"=>$Series["Color"]["R"],"G"=>$Series["Color"]["G"],"B"=>$Series["Color"]["B"],"Alpha"=>$Series["Color"]["Alpha"]); + $Color["Ticks"] = $Ticks; + + $PosArrayX = $Data["Series"][$Series["X"]]["Data"]; + $PosArrayY = $Data["Series"][$Series["Y"]]["Data"]; + + $Sxy = 0; $Sx = 0; $Sy = 0; $Sxx = 0; + foreach($PosArrayX as $Key => $Value) + { + $X = $Value; $Y = $PosArrayY[$Key]; + + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $X; + $Sy = $Sy + $Y; + $Sxx = $Sxx + $X*$X; + } + + $n = count($PosArrayX); + + if ((($n*$Sxx) == ($Sx*$Sx))) + { + $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"],$SerieXAxis); + $X2 = $X1; + $Y1 = $this->pChartObject->GraphAreaY1; + $Y2 = $this->pChartObject->GraphAreaY2; + } + else + { + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"],$SerieXAxis); + $Y1 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMin"] + $B,$SerieYAxis); + $X2 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMax"],$SerieXAxis); + $Y2 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMax"] + $B,$SerieYAxis); + + $RealM = -($Y2-$Y1)/($X2-$X1); + + if ( $Y1 < $this->pChartObject->GraphAreaY1 ) { $X1 = $X1 + ($this->pChartObject->GraphAreaY1-$Y1/$RealM); $Y1 = $this->pChartObject->GraphAreaY1; } + if ( $Y1 > $this->pChartObject->GraphAreaY2 ) { $X1 = $X1 + ($Y1-$this->pChartObject->GraphAreaY2)/$RealM; $Y1 = $this->pChartObject->GraphAreaY2; } + if ( $Y2 < $this->pChartObject->GraphAreaY1 ) { $X2 = $X2 - ($this->pChartObject->GraphAreaY1-$Y2)/$RealM; $Y2 = $this->pChartObject->GraphAreaY1; } + if ( $Y2 > $this->pChartObject->GraphAreaY2 ) { $X2 = $X2 - ($Y2-$this->pChartObject->GraphAreaY2)/$RealM; $Y2 = $this->pChartObject->GraphAreaY2; } + } + + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y2,$Color); + } + } + } + + function writeScatterLabel($ScatterSerieID,$Points,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : NULL; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + $Decimals = isset($Format["Decimals"]) ? $Format["Decimals"] : NULL; + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( !is_array($Points) ) { $Point = $Points; $Points = ""; $Points[0] = $Point; } + + if ( !isset($Data["ScatterSeries"][$ScatterSerieID]) ) + return(0); + + $Series = $Data["ScatterSeries"][$ScatterSerieID]; + $SerieX = $Series["X"]; $SerieValuesX = $Data["Series"][$SerieX]["Data"]; $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; $SerieValuesY = $Data["Series"][$SerieY]["Data"]; $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { $Value = $PosArrayX; $PosArrayX = ""; $PosArrayX[0] = $Value; } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { $Value = $PosArrayY; $PosArrayY = ""; $PosArrayY[0] = $Value; } + + foreach($Points as $Key => $Point) + { + if ( isset($PosArrayX[$Point]) && isset($PosArrayY[$Point]) ) + { + $X = floor($PosArrayX[$Point]); + $Y = floor($PosArrayY[$Point]); + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) + $this->pChartObject->drawFilledCircle($X,$Y,3,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + elseif ( $DrawPoint == LABEL_POINT_BOX ) + $this->pChartObject->drawFilledRectangle($X-2,$Y-2,$X+2,$Y+2,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); + + $Serie = ""; + $Serie["R"] = $Series["Color"]["R"]; + $Serie["G"] = $Series["Color"]["G"]; + $Serie["B"] = $Series["Color"]["B"]; + $Serie["Alpha"] = $Series["Color"]["Alpha"]; + + $XAxisMode = $Data["Axis"][$SerieXAxis]["Display"]; + $XAxisFormat = $Data["Axis"][$SerieXAxis]["Format"]; + $XAxisUnit = $Data["Axis"][$SerieXAxis]["Unit"]; + if ( $Decimals == NULL ) { $XValue = $SerieValuesX[$Point]; } else { $XValue = round($SerieValuesX[$Point],$Decimals); } + $XValue = $this->pChartObject->scaleFormat($XValue,$XAxisMode,$XAxisFormat,$XAxisUnit); + + $YAxisMode = $Data["Axis"][$SerieYAxis]["Display"]; + $YAxisFormat = $Data["Axis"][$SerieYAxis]["Format"]; + $YAxisUnit = $Data["Axis"][$SerieYAxis]["Unit"]; + if ( $Decimals == NULL ) { $YValue = $SerieValuesY[$Point]; } else { $YValue = round($SerieValuesY[$Point],$Decimals); } + $YValue = $this->pChartObject->scaleFormat($YValue,$YAxisMode,$YAxisFormat,$YAxisUnit); + + $Caption = $XValue." / ".$YValue; + + if ( isset($Series["Description"]) ) + $Description = $Series["Description"]; + else + $Description = "No description"; + + $Series = ""; + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + + $this->pChartObject->drawLabelBox($X,$Y-3,$Description,$Series,$Format); + } + } + } + + /* Draw a Scatter threshold */ + function drawScatterThreshold($Value,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 3; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : FALSE; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : FALSE; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : NULL; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 10; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : TRUE; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : FALSE; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : TRUE; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + + $CaptionSettings = array("DrawBox"=>$DrawBox,"DrawBoxBorder"=>$DrawBoxBorder,"BorderOffset"=>$BorderOffset,"BoxRounded"=>$BoxRounded,"RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR,"BoxG"=>$BoxG,"BoxB"=>$BoxB,"BoxAlpha"=>$BoxAlpha,"BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR,"BoxBorderG"=>$BoxBorderG,"BoxBorderB"=>$BoxBorderB,"BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR,"G"=>$CaptionG,"B"=>$CaptionB,"Alpha"=>$CaptionAlpha); + + if ( $Caption == NULL ) { $Caption = $Value; } + + $Data = $this->pDataObject->getData(); + + if ( !isset($Data["Axis"][$AxisID]) ) { return(-1); } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_Y ) + { + $X1 = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; + $X2 = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; + $Y = $this->getPosArray($Value,$AxisID); + + $this->pChartObject->drawLine($X1,$Y,$X2,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->pChartObject->drawLine($X1,$Y-1,$X2,$Y-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->pChartObject->drawLine($X1,$Y+1,$X2,$Y+1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $X = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + else + { $X = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"] - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + + $this->pChartObject->drawText($X,$Y,$Caption,$CaptionSettings); + } + + return(array("Y"=>$Y)); + } + elseif ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) + { + $X = $this->getPosArray($Value,$AxisID); + $Y1 = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; + $Y2 = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; + + $this->pChartObject->drawLine($X,$Y1,$X,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight)); + + if ( $Wide ) + { + $this->pChartObject->drawLine($X-1,$Y1,$X-1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + $this->pChartObject->drawLine($X+1,$Y1,$X+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks)); + } + + if ( $WriteCaption ) + { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) + { $Y = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"] + $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; } + else + { $Y = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] - $CaptionOffset; $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; } + + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + $this->pChartObject->drawText($X,$Y,$Caption,$CaptionSettings); + } + + return(array("X"=>$X)); + } + } + + /* Draw a Scatter threshold area */ + function drawScatterThresholdArea($Value1,$Value2,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : TRUE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : "La ouate de phoque"; //NULL; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : TRUE; + + if ($Value1 > $Value2) { list($Value1, $Value2) = array($Value2, $Value1); } + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $DisableShadowOnArea && $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } + + if ($BorderAlpha >100) { $BorderAlpha = 100;} + + $Data = $this->pDataObject->getData(); + + if ( !isset($Data["Axis"][$AxisID]) ) { return(-1); } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) + { + $Y1 = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; + $Y2 = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; + $X1 = $this->getPosArray($Value1,$AxisID); + $X2 = $this->getPosArray($Value2,$AxisID); + + if ( $X1 <= $this->pChartObject->GraphAreaX1 ) { $X1 = $this->pChartObject->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; } + if ( $X2 >= $this->pChartObject->GraphAreaX2 ) { $X2 = $this->pChartObject->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; } + + $this->pChartObject->drawFilledRectangle($X1,$Y1,$X2,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + if ( $Border ) + { + $this->pChartObject->drawLine($X1,$Y1,$X1,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->pChartObject->drawLine($X2,$Y1,$X2,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($X2-$X1)/2 + $X1; + $YPos = ($Y2-$Y1)/2 + $Y1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) + { + $TxtPos = $this->pChartObject->getTextBox($XPos,$YPos,$this->pChartObject->FontName,$this->pChartObject->FontSize,0,$AreaName); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if ( abs($X2 - $X1) > $TxtWidth ) { $NameAngle = 0; } else { $NameAngle = 90; } + } + $this->pChartObject->Shadow = $RestoreShadow; + $this->pChartObject->drawText($XPos,$YPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>$NameAngle,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->pChartObject->Shadow = FALSE; } + } + + $this->pChartObject->Shadow = $RestoreShadow; + return(array("X1"=>$X1,"X2"=>$X2)); + } + elseif ( $Data["Axis"][$AxisID]["Identity"] == AXIS_Y ) + { + $X1 = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; + $X2 = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; + $Y1 = $this->getPosArray($Value1,$AxisID); + $Y2 = $this->getPosArray($Value2,$AxisID); + + if ( $Y1 >= $this->pChartObject->GraphAreaY2 ) { $Y1 = $this->pChartObject->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; } + if ( $Y2 <= $this->pChartObject->GraphAreaY1 ) { $Y2 = $this->pChartObject->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; } + + $this->pChartObject->drawFilledRectangle($X1,$Y1,$X2,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + if ( $Border ) + { + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y1,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + $this->pChartObject->drawLine($X1,$Y2,$X2,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks)); + } + + if ( $AreaName != NULL ) + { + $XPos = ($X2-$X1)/2 + $X1; + $YPos = ($Y2-$Y1)/2 + $Y1; + + $this->pChartObject->Shadow = $RestoreShadow; + $this->pChartObject->drawText($YPos,$XPos,$AreaName,array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>0,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + if ( $DisableShadowOnArea ) { $this->Shadow = FALSE; } + } + + $this->pChartObject->Shadow = $RestoreShadow; + return(array("Y1"=>$Y1,"Y2"=>$Y2)); + } + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pSplit.class.php b/webdata/graph/pchart/class/pSplit.class.php new file mode 100644 index 0000000..3043603 --- /dev/null +++ b/webdata/graph/pchart/class/pSplit.class.php @@ -0,0 +1,131 @@ +pChartObject = $Object; + + $Spacing = isset($Format["Spacing"]) ? $Format["Spacing"] : 20; + $TextPadding = isset($Format["TextPadding"]) ? $Format["TextPadding"] : 2; + $TextPos = isset($Format["TextPos"]) ? $Format["TextPos"] : TEXT_POS_TOP; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $Force = isset($Format["Force"]) ? $Format["Force"] : 70; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 15; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + $LabelSerie = $Data["Abscissa"]; + $DataSerie = ""; + + foreach($Data["Series"] as $SerieName => $Value) + { if ( $SerieName != $LabelSerie && $DataSerie == "" ) { $DataSerie = $SerieName; } } + + $DataSerieSum = array_sum($Data["Series"][$DataSerie]["Data"]); + $DataSerieCount = count($Data["Series"][$DataSerie]["Data"]); + + /* Scale Processing */ + if ( $TextPos == TEXT_POS_RIGHT ) + $YScale = (($Y2-$Y1) - (($DataSerieCount+1)*$Spacing)) / $DataSerieSum; + else + $YScale = (($Y2-$Y1) - ($DataSerieCount*$Spacing)) / $DataSerieSum; + $LeftHeight = $DataSerieSum * $YScale; + + /* Re-compute graph width depending of the text mode choosen */ + if ( $TextPos == TEXT_POS_RIGHT ) + { + $MaxWidth = 0; + foreach($Data["Series"][$LabelSerie]["Data"] as $Key => $Label) + { + $Boundardies = $Object->getTextBox(0,0,$Object->FontName,$Object->FontSize,0,$Label); + if ( $Boundardies[1]["X"] > $MaxWidth ) { $MaxWidth = $Boundardies[1]["X"] + $TextPadding*2; } + } + $X2 = $X2 - $MaxWidth; + } + + /* Drawing */ + $LeftY = ((($Y2-$Y1) / 2) + $Y1) - ($LeftHeight/2); + $RightY = $Y1; + $VectorX = (($X2-$X1) / 2); + + foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value) + { + if ( isset($Data["Series"][$LabelSerie]["Data"][$Key]) ) + $Label = $Data["Series"][$LabelSerie]["Data"][$Key]; + else + $Label = "-"; + + $LeftY1 = $LeftY; + $LeftY2 = $LeftY + $Value * $YScale; + + $RightY1 = $RightY + $Spacing; + $RightY2 = $RightY + $Spacing + $Value * $YScale;; + + $Settings = array("R"=>$Palette[$Key]["R"],"G"=>$Palette[$Key]["G"],"B"=>$Palette[$Key]["B"],"Alpha"=>$Palette[$Key]["Alpha"],"NoDraw"=>TRUE,"Segments"=>$Segments,"Surrounding"=>$Surrounding); + + $PolyGon = ""; + + $Angle = $Object->getAngle($X2,$RightY1,$X1,$LeftY1); + $VectorX1 = cos(deg2rad($Angle+90)) * $Force + ($X2-$X1)/2 + $X1; + $VectorY1 = sin(deg2rad($Angle+90)) * $Force + ($RightY1-$LeftY1)/2 + $LeftY1; + $VectorX2 = cos(deg2rad($Angle-90)) * $Force + ($X2-$X1)/2 + $X1; + $VectorY2 = sin(deg2rad($Angle-90)) * $Force + ($RightY1-$LeftY1)/2 + $LeftY1; + + $Points = $Object->drawBezier($X1,$LeftY1,$X2,$RightY1,$VectorX1,$VectorY1,$VectorX2,$VectorY2,$Settings); + foreach($Points as $Key => $Pos) { $PolyGon[] = $Pos["X"]; $PolyGon[] = $Pos["Y"]; } + + + $Angle = $Object->getAngle($X2,$RightY2,$X1,$LeftY2); + $VectorX1 = cos(deg2rad($Angle+90)) * $Force + ($X2-$X1)/2 +$X1; + $VectorY1 = sin(deg2rad($Angle+90)) * $Force + ($RightY2-$LeftY2)/2 + $LeftY2; + $VectorX2 = cos(deg2rad($Angle-90)) * $Force + ($X2-$X1)/2 +$X1; + $VectorY2 = sin(deg2rad($Angle-90)) * $Force + ($RightY2-$LeftY2)/2 + $LeftY2; + + $Points = $Object->drawBezier($X1,$LeftY2,$X2,$RightY2,$VectorX1,$VectorY1,$VectorX2,$VectorY2,$Settings); + $Points = array_reverse($Points); + foreach($Points as $Key => $Pos) { $PolyGon[] = $Pos["X"]; $PolyGon[] = $Pos["Y"]; } + + $Object->drawPolygon($PolyGon,$Settings); + + if ( $TextPos == TEXT_POS_RIGHT ) + $Object->drawText($X2+$TextPadding,($RightY2-$RightY1)/2+$RightY1,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + else + $Object->drawText($X2,$RightY1-$TextPadding,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); + + $LeftY = $LeftY2; + $RightY = $RightY2; + } + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pSpring.class.php b/webdata/graph/pchart/class/pSpring.class.php new file mode 100644 index 0000000..65b9cb6 --- /dev/null +++ b/webdata/graph/pchart/class/pSpring.class.php @@ -0,0 +1,868 @@ +Data = ""; + $this->Links = ""; + + /* Set nodes defaults */ + $this->Default["R"] = 255; + $this->Default["G"] = 255; + $this->Default["B"] = 255; + $this->Default["Alpha"] = 100; + $this->Default["BorderR"] = 0; + $this->Default["BorderG"] = 0; + $this->Default["BorderB"] = 0; + $this->Default["BorderAlpha"] = 100; + $this->Default["Surrounding"] = NULL; + $this->Default["BackgroundR"] = 255; + $this->Default["BackgroundG"] = 255; + $this->Default["BackgroundB"] = 255; + $this->Default["BackgroundAlpha"] = 0; + $this->Default["Force"] = 1; + $this->Default["NodeType"] = NODE_TYPE_FREE; + $this->Default["Size"] = 5; + $this->Default["Shape"] = NODE_SHAPE_CIRCLE; + $this->Default["FreeZone"] = 40; + $this->Default["LinkR"] = 0; + $this->Default["LinkG"] = 0; + $this->Default["LinkB"] = 0; + $this->Default["LinkAlpha"] = 0; + + $this->Labels["Type"] = LABEL_CLASSIC; + $this->Labels["R"] = 0; + $this->Labels["G"] = 0; + $this->Labels["B"] = 0; + $this->Labels["Alpha"] = 100; + + $this->AutoComputeFreeZone = FALSE; + } + + /* Set default links options */ + function setLinkDefaults($Settings="") + { + if ( isset($Settings["R"]) ) { $this->Default["LinkR"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Default["LinkG"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Default["LinkB"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Default["LinkAlpha"] = $Settings["Alpha"]; } + } + + /* Set default links options */ + function setLabelsSettings($Settings="") + { + if ( isset($Settings["Type"]) ) { $this->Labels["Type"] = $Settings["Type"]; } + if ( isset($Settings["R"]) ) { $this->Labels["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Labels["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Labels["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Labels["Alpha"] = $Settings["Alpha"]; } + } + + /* Auto compute the FreeZone size based on the number of connections */ + function autoFreeZone() + { + /* Check connections reciprocity */ + foreach($this->Data as $Key => $Settings) + { + if ( isset($Settings["Connections"]) ) + { $this->Data[$Key]["FreeZone"] = count($Settings["Connections"])*10 + 20; } + else + { $this->Data[$Key]["FreeZone"] = 20; } + } + + } + + /* Set link properties */ + function linkProperties($FromNode,$ToNode,$Settings) + { + if ( !isset($this->Data[$FromNode]) ) { return(0); } + if ( !isset($this->Data[$ToNode]) ) { return(0); } + + $R = isset($Settings["R"]) ? $Settings["R"] : 0; + $G = isset($Settings["G"]) ? $Settings["G"] : 0; + $B = isset($Settings["B"]) ? $Settings["B"] : 0; + $Alpha = isset($Settings["Alpha"]) ? $Settings["Alpha"] : 100; + $Name = isset($Settings["Name"]) ? $Settings["Name"] : NULL; + $Ticks = isset($Settings["Ticks"]) ? $Settings["Ticks"] : NULL; + + $this->Links[$FromNode][$ToNode]["R"] = $R; $this->Links[$ToNode][$FromNode]["R"] = $R; + $this->Links[$FromNode][$ToNode]["G"] = $G; $this->Links[$ToNode][$FromNode]["G"] = $G; + $this->Links[$FromNode][$ToNode]["B"] = $B; $this->Links[$ToNode][$FromNode]["B"] = $B; + $this->Links[$FromNode][$ToNode]["Alpha"] = $Alpha; $this->Links[$ToNode][$FromNode]["Alpha"] = $Alpha; + $this->Links[$FromNode][$ToNode]["Name"] = $Name; $this->Links[$ToNode][$FromNode]["Name"] = $Name; + $this->Links[$FromNode][$ToNode]["Ticks"] = $Ticks; $this->Links[$ToNode][$FromNode]["Ticks"] = $Ticks; + } + + function setNodeDefaults($Settings="") + { + if ( isset($Settings["R"]) ) { $this->Default["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Default["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Default["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Default["Alpha"] = $Settings["Alpha"]; } + if ( isset($Settings["BorderR"]) ) { $this->Default["BorderR"] = $Settings["BorderR"]; } + if ( isset($Settings["BorderG"]) ) { $this->Default["BorderG"] = $Settings["BorderG"]; } + if ( isset($Settings["BorderB"]) ) { $this->Default["BorderB"] = $Settings["BorderB"]; } + if ( isset($Settings["BorderAlpha"]) ) { $this->Default["BorderAlpha"] = $Settings["BorderAlpha"]; } + if ( isset($Settings["Surrounding"]) ) { $this->Default["Surrounding"] = $Settings["Surrounding"]; } + if ( isset($Settings["BackgroundR"]) ) { $this->Default["BackgroundR"] = $Settings["BackgroundR"]; } + if ( isset($Settings["BackgroundG"]) ) { $this->Default["BackgroundG"] = $Settings["BackgroundG"]; } + if ( isset($Settings["BackgroundB"]) ) { $this->Default["BackgroundB"] = $Settings["BackgroundB"]; } + if ( isset($Settings["BackgroundAlpha"]) ) { $this->Default["BackgroundAlpha"] = $Settings["BackgroundAlpha"]; } + if ( isset($Settings["NodeType"]) ) { $this->Default["NodeType"] = $Settings["NodeType"]; } + if ( isset($Settings["Size"]) ) { $this->Default["Size"] = $Settings["Size"]; } + if ( isset($Settings["Shape"]) ) { $this->Default["Shape"] = $Settings["Shape"]; } + if ( isset($Settings["FreeZone"]) ) { $this->Default["FreeZone"] = $Settings["FreeZone"]; } + } + + /* Add a node */ + function addNode($NodeID,$Settings="") + { + /* if the node already exists, ignore */ + if (isset($this->Data[$NodeID])) { return(0); } + + $Name = isset($Settings["Name"]) ? $Settings["Name"] : "Node ".$NodeID; + $Connections = isset($Settings["Connections"]) ? $Settings["Connections"] : NULL; + + $R = isset($Settings["R"]) ? $Settings["R"] : $this->Default["R"]; + $G = isset($Settings["G"]) ? $Settings["G"] : $this->Default["G"]; + $B = isset($Settings["B"]) ? $Settings["B"] : $this->Default["B"]; + $Alpha = isset($Settings["Alpha"]) ? $Settings["Alpha"] : $this->Default["Alpha"]; + $BorderR = isset($Settings["BorderR"]) ? $Settings["BorderR"] : $this->Default["BorderR"]; + $BorderG = isset($Settings["BorderG"]) ? $Settings["BorderG"] : $this->Default["BorderG"]; + $BorderB = isset($Settings["BorderB"]) ? $Settings["BorderB"] : $this->Default["BorderB"]; + $BorderAlpha = isset($Settings["BorderAlpha"]) ? $Settings["BorderAlpha"] : $this->Default["BorderAlpha"]; + $Surrounding = isset($Settings["Surrounding"]) ? $Settings["Surrounding"] : $this->Default["Surrounding"]; + $BackgroundR = isset($Settings["BackgroundR"]) ? $Settings["BackgroundR"] : $this->Default["BackgroundR"]; + $BackgroundG = isset($Settings["BackgroundG"]) ? $Settings["BackgroundG"] : $this->Default["BackgroundG"]; + $BackgroundB = isset($Settings["BackgroundB"]) ? $Settings["BackgroundB"] : $this->Default["BackgroundB"]; + $BackgroundAlpha = isset($Settings["BackgroundAlpha"]) ? $Settings["BackgroundAlpha"] : $this->Default["BackgroundAlpha"]; + $Force = isset($Settings["Force"]) ? $Settings["Force"] : $this->Default["Force"]; + $NodeType = isset($Settings["NodeType"]) ? $Settings["NodeType"] : $this->Default["NodeType"]; + $Size = isset($Settings["Size"]) ? $Settings["Size"] : $this->Default["Size"]; + $Shape = isset($Settings["Shape"]) ? $Settings["Shape"] : $this->Default["Shape"]; + $FreeZone = isset($Settings["FreeZone"]) ? $Settings["FreeZone"] : $this->Default["FreeZone"]; + + if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } + + $this->Data[$NodeID]["R"] = $R; $this->Data[$NodeID]["G"] = $G; $this->Data[$NodeID]["B"] = $B; $this->Data[$NodeID]["Alpha"] = $Alpha; + $this->Data[$NodeID]["BorderR"] = $BorderR; $this->Data[$NodeID]["BorderG"] = $BorderG; $this->Data[$NodeID]["BorderB"] = $BorderB; $this->Data[$NodeID]["BorderAlpha"] = $BorderAlpha; + $this->Data[$NodeID]["BackgroundR"] = $BackgroundR; $this->Data[$NodeID]["BackgroundG"] = $BackgroundG; $this->Data[$NodeID]["BackgroundB"] = $BackgroundB; $this->Data[$NodeID]["BackgroundAlpha"] = $BackgroundAlpha; + $this->Data[$NodeID]["Name"] = $Name; + $this->Data[$NodeID]["Force"] = $Force; + $this->Data[$NodeID]["Type"] = $NodeType; + $this->Data[$NodeID]["Size"] = $Size; + $this->Data[$NodeID]["Shape"] = $Shape; + $this->Data[$NodeID]["FreeZone"] = $FreeZone; + if ( $Connections != NULL ) + { + if ( is_array($Connections ) ) + { + foreach($Connections as $Key => $Value) + $this->Data[$NodeID]["Connections"][] = $Value; + } + else + $this->Data[$NodeID]["Connections"][] = $Connections; + } + } + + /* Set color attribute for a list of nodes */ + function setNodesColor($Nodes,$Settings="") + { + if ( is_array($Nodes) ) + { + foreach ($Nodes as $Key => $NodeID) + { + if (isset($this->Data[$NodeID]) ) + { + if ( isset($Settings["R"]) ) { $this->Data[$NodeID]["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Data[$NodeID]["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Data[$NodeID]["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Data[$NodeID]["Alpha"] = $Settings["Alpha"]; } + if ( isset($Settings["BorderR"]) ) { $this->Data[$NodeID]["BorderR"] = $Settings["BorderR"]; } + if ( isset($Settings["BorderG"]) ) { $this->Data[$NodeID]["BorderG"] = $Settings["BorderG"]; } + if ( isset($Settings["BorderB"]) ) { $this->Data[$NodeID]["BorderB"] = $Settings["BorderB"]; } + if ( isset($Settings["BorderAlpha"]) ) { $this->Data[$NodeID]["BorderAlpha"] = $Settings["BorderAlpha"]; } + if ( isset($Settings["Surrounding"]) ) { $this->Data[$NodeID]["BorderR"] = $this->Data[$NodeID]["R"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderG"] = $this->Data[$NodeID]["G"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderB"] = $this->Data[$NodeID]["B"] + $Settings["Surrounding"]; } + } + } + } + else + { + if ( isset($Settings["R"]) ) { $this->Data[$Nodes]["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Data[$Nodes]["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Data[$Nodes]["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Data[$Nodes]["Alpha"] = $Settings["Alpha"]; } + if ( isset($Settings["BorderR"]) ) { $this->Data[$Nodes]["BorderR"] = $Settings["BorderR"]; } + if ( isset($Settings["BorderG"]) ) { $this->Data[$Nodes]["BorderG"] = $Settings["BorderG"]; } + if ( isset($Settings["BorderB"]) ) { $this->Data[$Nodes]["BorderB"] = $Settings["BorderB"]; } + if ( isset($Settings["BorderAlpha"]) ) { $this->Data[$Nodes]["BorderAlpha"] = $Settings["BorderAlpha"]; } + if ( isset($Settings["Surrounding"]) ) { $this->Data[$Nodes]["BorderR"] = $this->Data[$NodeID]["R"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderG"] = $this->Data[$NodeID]["G"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderB"] = $this->Data[$NodeID]["B"] + $Settings["Surrounding"]; } + } + } + + /* Returns all the nodes details */ + function dumpNodes() + { return($this->Data); } + + /* Check if a connection exists and create it if required */ + function checkConnection($SourceID, $TargetID) + { + if ( isset($this->Data[$SourceID]["Connections"]) ) + { + foreach ($this->Data[$SourceID]["Connections"] as $Key => $ConnectionID) + { if ( $TargetID == $ConnectionID ) { return(TRUE); } } + } + $this->Data[$SourceID]["Connections"][] = $TargetID; + } + /* Get the median linked nodes position */ + function getMedianOffset($Key,$X,$Y) + { + $Cpt = 1; + if ( isset($this->Data[$Key]["Connections"]) ) + { + foreach($this->Data[$Key]["Connections"] as $ID => $NodeID) + { + if ( isset($this->Data[$NodeID]["X"]) && isset($this->Data[$NodeID]["Y"]) ) + { + $X = $X + $this->Data[$NodeID]["X"]; + $Y = $Y + $this->Data[$NodeID]["Y"]; + $Cpt++; + } + } + } + return(array("X"=>$X/$Cpt,"Y"=>$Y/$Cpt)); + } + + /* Return the ID of the attached partner with the biggest weight */ + function getBiggestPartner($Key) + { + if ( !isset($this->Data[$Key]["Connections"]) ) { return(""); } + + $MaxWeight = 0; $Result = ""; + foreach($this->Data[$Key]["Connections"] as $Key => $PeerID) + { + if ( $this->Data[$PeerID]["Weight"] > $MaxWeight ) + { $MaxWeight = $this->Data[$PeerID]["Weight"]; $Result = $PeerID; } + } + return($Result); + } + + /* Do the initial node positions computing pass */ + function firstPass($Algorithm) + { + $CenterX = ($this->X2 - $this->X1) / 2 + $this->X1; + $CenterY = ($this->Y2 - $this->Y1) / 2 + $this->Y1; + + /* Check connections reciprocity */ + foreach($this->Data as $Key => $Settings) + { + if ( isset($Settings["Connections"]) ) + { + foreach($Settings["Connections"] as $ID => $ConnectionID) + $this->checkConnection($ConnectionID,$Key); + } + } + + if ( $this->AutoComputeFreeZone ) { $this->autoFreeZone(); } + + /* Get the max number of connections */ + $MaxConnections = 0; + foreach($this->Data as $Key => $Settings) + { if ( isset($Settings["Connections"]) ) { if ( $MaxConnections < count($Settings["Connections"] ) ) { $MaxConnections = count($Settings["Connections"]); } } } + + if ( $Algorithm == ALGORITHM_WEIGHTED ) + { + foreach($this->Data as $Key => $Settings) + { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { $this->Data[$Key]["X"] = $CenterX; $this->Data[$Key]["Y"] = $CenterY; } + if ( $Settings["Type"] == NODE_TYPE_FREE ) + { + if ( isset($Settings["Connections"]) ) + { $Connections = count($Settings["Connections"]); } + else + { $Connections = 0; } + + $Ring = $MaxConnections - $Connections; + $Angle = rand(0,360); + + $this->Data[$Key]["X"] = cos(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterX; + $this->Data[$Key]["Y"] = sin(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterY; + } + } + } + elseif ( $Algorithm == ALGORITHM_CENTRAL ) + { + /* Put a weight on each nodes */ + foreach($this->Data as $Key => $Settings) + { + if ( isset($Settings["Connections"]) ) + $this->Data[$Key]["Weight"] = count($Settings["Connections"]); + else + $this->Data[$Key]["Weight"] = 0; + } + + $MaxConnections = $MaxConnections + 1; + for($i=$MaxConnections;$i>=0;$i--) + { + foreach($this->Data as $Key => $Settings) + { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { $this->Data[$Key]["X"] = $CenterX; $this->Data[$Key]["Y"] = $CenterY; } + if ( $Settings["Type"] == NODE_TYPE_FREE ) + { + if ( isset($Settings["Connections"]) ) + { $Connections = count($Settings["Connections"]); } + else + { $Connections = 0; } + + if ( $Connections == $i ) + { + $BiggestPartner = $this->getBiggestPartner($Key); + if ( $BiggestPartner != "" ) + { + $Ring = $this->Data[$BiggestPartner]["FreeZone"]; + $Weight = $this->Data[$BiggestPartner]["Weight"]; + $AngleDivision = 360 / $this->Data[$BiggestPartner]["Weight"]; + $Done = FALSE; $Tries = 0; + while (!$Done && $Tries <= $Weight*2) + { + $Tries++; + $Angle = floor(rand(0,$Weight)*$AngleDivision); + if ( !isset($this->Data[$BiggestPartner]["Angular"][$Angle]) || !isset($this->Data[$BiggestPartner]["Angular"]) ) + { + $this->Data[$BiggestPartner]["Angular"][$Angle] = $Angle; + $Done = TRUE; + } + } + if ( !$Done ) + { $Angle = rand(0,360); $this->Data[$BiggestPartner]["Angular"][$Angle] = $Angle; } + + $X = cos(deg2rad($Angle)) * ($Ring) + $this->Data[$BiggestPartner]["X"]; + $Y = sin(deg2rad($Angle)) * ($Ring) + $this->Data[$BiggestPartner]["Y"]; + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + } + } + } + } + } + elseif ( $Algorithm == ALGORITHM_CIRCULAR ) + { + $MaxConnections = $MaxConnections + 1; + for($i=$MaxConnections;$i>=0;$i--) + { + foreach($this->Data as $Key => $Settings) + { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { $this->Data[$Key]["X"] = $CenterX; $this->Data[$Key]["Y"] = $CenterY; } + if ( $Settings["Type"] == NODE_TYPE_FREE ) + { + if ( isset($Settings["Connections"]) ) + { $Connections = count($Settings["Connections"]); } + else + { $Connections = 0; } + + if ( $Connections == $i ) + { + $Ring = $MaxConnections - $Connections; + $Angle = rand(0,360); + + $X = cos(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterX; + $Y = sin(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterY; + + $MedianOffset = $this->getMedianOffset($Key,$X,$Y); + + $this->Data[$Key]["X"] = $MedianOffset["X"]; + $this->Data[$Key]["Y"] = $MedianOffset["Y"]; + } + } + } + } + } + elseif ( $Algorithm == ALGORITHM_RANDOM ) + { + foreach($this->Data as $Key => $Settings) + { + if ( $Settings["Type"] == NODE_TYPE_FREE ) + { + $this->Data[$Key]["X"] = $CenterX + rand(-20,20); + $this->Data[$Key]["Y"] = $CenterY + rand(-20,20); + } + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { $this->Data[$Key]["X"] = $CenterX; $this->Data[$Key]["Y"] = $CenterY; } + } + } + } + + /* Compute one pass */ + function doPass() + { + /* Compute vectors */ + foreach($this->Data as $Key => $Settings) + { + if ( $Settings["Type"] != NODE_TYPE_CENTRAL ) + { + unset($this->Data[$Key]["Vectors"]); + + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + /* Repulsion vectors */ + foreach($this->Data as $Key2 => $Settings2) + { + if ( $Key != $Key2 ) + { + $X2 = $this->Data[$Key2]["X"]; + $Y2 = $this->Data[$Key2]["Y"]; + $FreeZone = $this->Data[$Key2]["FreeZone"]; + + $Distance = $this->getDistance($X1,$Y1,$X2,$Y2); + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2) + 180; + + /* Nodes too close, repulsion occurs */ + if ( $Distance < $FreeZone ) + { + $Force = log(pow(2,$FreeZone-$Distance)); + if ( $Force > 1 ) + { $this->Data[$Key]["Vectors"][] = array("Type"=>"R","Angle"=>$Angle % 360,"Force"=>$Force); } + } + } + } + + /* Attraction vectors */ + if ( isset($Settings["Connections"]) ) + { + foreach($Settings["Connections"] as $ID => $NodeID) + { + if ( isset($this->Data[$NodeID]) ) + { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + $FreeZone = $this->Data[$Key2]["FreeZone"]; + + $Distance = $this->getDistance($X1,$Y1,$X2,$Y2); + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + + if ( $Distance > $FreeZone ) + $Force = log(($Distance-$FreeZone)+1); + else + { $Force = log(($FreeZone-$Distance)+1); ($Angle = $Angle + 180); } + + if ( $Force > 1 ) + $this->Data[$Key]["Vectors"][] = array("Type"=>"A","Angle"=>$Angle % 360,"Force"=>$Force); + } + } + } + } + } + + /* Move the nodes accoding to the vectors */ + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( isset($Settings["Vectors"]) && $Settings["Type"] != NODE_TYPE_CENTRAL ) + { + foreach($Settings["Vectors"] as $ID => $Vector) + { + $Type = $Vector["Type"]; + $Force = $Vector["Force"]; + $Angle = $Vector["Angle"]; + $Factor = $Type == "A" ? $this->MagneticForceA : $this->MagneticForceR; + + $X = cos(deg2rad($Angle)) * $Force * $Factor + $X; + $Y = sin(deg2rad($Angle)) * $Force * $Factor + $Y; + } + } + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + } + + function lastPass() + { + /* Put everything inside the graph area */ + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( $X < $this->X1 ) { $X = $this->X1; } + if ( $X > $this->X2 ) { $X = $this->X2; } + if ( $Y < $this->Y1 ) { $Y = $this->Y1; } + if ( $Y > $this->Y2 ) { $Y = $this->Y2; } + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + + /* Dump all links */ + $Links = ""; + foreach($this->Data as $Key => $Settings) + { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) + { + foreach ($Settings["Connections"] as $ID => $NodeID) + { + if ( isset($this->Data[$NodeID]) ) + { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + + $Links[] = array("X1"=>$X1,"Y1"=>$Y1,"X2"=>$X2,"Y2"=>$Y2,"Source"=>$Settings["Name"],"Destination"=>$this->Data[$NodeID]["Name"]); + } + } + } + } + + /* Check collisions */ + $Conflicts = 0; + foreach($this->Data as $Key => $Settings) + { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) + { + foreach ($Settings["Connections"] as $ID => $NodeID) + { + if ( isset($this->Data[$NodeID]) ) + { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + + foreach($Links as $IDLinks => $Link) + { + $X3 = $Link["X1"]; $Y3 = $Link["Y1"]; $X4 = $Link["X2"]; $Y4 = $Link["Y2"]; + + if ( !($X1 == $X3 && $X2 == $X4 && $Y1 == $Y3 && $Y2 == $Y4 ) ) + { + if ( $this->intersect($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4) ) + { + if ( $Link["Source"] != $Settings["Name"] && $Link["Source"] != $this->Data[$NodeID]["Name"] && $Link["Destination"] != $Settings["Name"] && $Link["Destination"] != $this->Data[$NodeID]["Name"] ) + { $Conflicts++; } + } + } + } + } + } + } + } + return($Conflicts/2); + } + + /* Center the graph */ + function center() + { + /* Determine the real center */ + $TargetCenterX = ($this->X2 - $this->X1) / 2 + $this->X1; + $TargetCenterY = ($this->Y2 - $this->Y1) / 2 + $this->Y1; + + /* Get current boundaries */ + $XMin = $this->X2; $XMax = $this->X1; + $YMin = $this->Y2; $YMax = $this->Y1; + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( $X < $XMin) { $XMin = $X; } + if ( $X > $XMax) { $XMax = $X; } + if ( $Y < $YMin) { $YMin = $Y; } + if ( $Y > $YMax) { $YMax = $Y; } + } + $CurrentCenterX = ($XMax - $XMin) / 2 + $XMin; + $CurrentCenterY = ($YMax - $YMin) / 2 + $YMin; + + /* Compute the offset to apply */ + $XOffset = $TargetCenterX - $CurrentCenterX; + $YOffset = $TargetCenterY - $CurrentCenterY; + + /* Correct the points position */ + foreach($this->Data as $Key => $Settings) + { + $this->Data[$Key]["X"] = $Settings["X"] + $XOffset; + $this->Data[$Key]["Y"] = $Settings["Y"] + $YOffset; + } + } + + /* Create the encoded string */ + function drawSpring($Object,$Settings="") + { + $this->pChartObject = $Object; + + $Pass = isset($Settings["Pass"]) ? $Settings["Pass"] : 50; + $Retries = isset($Settings["Retry"]) ? $Settings["Retry"] : 10; + $this->MagneticForceA = isset($Settings["MagneticForceA"]) ? $Settings["MagneticForceA"] : 1.5; + $this->MagneticForceR = isset($Settings["MagneticForceR"]) ? $Settings["MagneticForceR"] : 2; + $this->RingSize = isset($Settings["RingSize"]) ? $Settings["RingSize"] : 40; + $DrawVectors = isset($Settings["DrawVectors"]) ? $Settings["DrawVectors"] : FALSE; + $DrawQuietZone = isset($Settings["DrawQuietZone"]) ? $Settings["DrawQuietZone"] : FALSE; + $CenterGraph = isset($Settings["CenterGraph"]) ? $Settings["CenterGraph"] : TRUE; + $TextPadding = isset($Settings["TextPadding"]) ? $Settings["TextPadding"] : 4; + $Algorithm = isset($Settings["Algorithm"]) ? $Settings["Algorithm"] : ALGORITHM_WEIGHTED; + + $FontSize = $Object->FontSize; + $this->X1 = $Object->GraphAreaX1; + $this->Y1 = $Object->GraphAreaY1; + $this->X2 = $Object->GraphAreaX2; + $this->Y2 = $Object->GraphAreaY2; + + $Conflicts = 1; $Jobs = 0; $this->History["MinimumConflicts"] = -1; + while ($Conflicts != 0 && $Jobs < $Retries ) + { + $Jobs++; + + /* Compute the initial settings */ + $this->firstPass($Algorithm); + + /* Apply the vectors */ + if ( $Pass > 0 ) + { + for ($i=0; $i<=$Pass; $i++) { $this->doPass(); } + } + + $Conflicts = $this->lastPass(); + if ( $this->History["MinimumConflicts"] == -1 || $Conflicts < $this->History["MinimumConflicts"] ) + { $this->History["MinimumConflicts"] = $Conflicts; $this->History["Result"] = $this->Data; } + } + + $Conflicts = $this->History["MinimumConflicts"]; + $this->Data = $this->History["Result"]; + + if ( $CenterGraph ) { $this->center(); } + + /* Draw the connections */ + $Drawn = ""; + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) + { + foreach ($Settings["Connections"] as $ID => $NodeID) + { + if ( !isset($Drawn[$Key]) ) { $Drawn[$Key] = ""; } + if ( !isset($Drawn[$NodeID]) ) { $Drawn[$NodeID] = ""; } + + if ( isset($this->Data[$NodeID]) && !isset($Drawn[$Key][$NodeID]) && !isset($Drawn[$NodeID][$Key]) ) + { + $Color = array("R"=>$this->Default["LinkR"],"G"=>$this->Default["LinkG"],"B"=>$this->Default["LinkB"],"Alpha"=>$this->Default["Alpha"]); + + if ( $this->Links != "" ) + { + if ( isset($this->Links[$Key][$NodeID]["R"]) ) + { $Color = array("R"=>$this->Links[$Key][$NodeID]["R"],"G"=>$this->Links[$Key][$NodeID]["G"],"B"=>$this->Links[$Key][$NodeID]["B"],"Alpha"=>$this->Links[$Key][$NodeID]["Alpha"]); } + + if ( isset($this->Links[$Key][$NodeID]["Ticks"]) ) + { $Color["Ticks"] = $this->Links[$Key][$NodeID]["Ticks"]; } + } + + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + $this->pChartObject->drawLine($X,$Y,$X2,$Y2,$Color); + $Drawn[$Key][$NodeID] = TRUE; + + if ( isset($this->Links) && $this->Links != "" ) + { + if ( isset($this->Links[$Key][$NodeID]["Name"]) || isset($this->Links[$NodeID][$Key]["Name"]) ) + { + $Name = isset($this->Links[$Key][$NodeID]["Name"]) ? $this->Links[$Key][$NodeID]["Name"] : $this->Links[$NodeID][$Key]["Name"]; + $TxtX = ($X2 - $X)/2 + $X; + $TxtY = ($Y2 - $Y)/2 + $Y; + + if ( $X <= $X2 ) + $Angle = (360-$this->getAngle($X,$Y,$X2,$Y2)) % 360; + else + $Angle = (360-$this->getAngle($X2,$Y2,$X,$Y)) % 360; + + $Settings = $Color; + $Settings["Angle"] = $Angle; + $Settings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; + $this->pChartObject->drawText($TxtX,$TxtY,$Name,$Settings); + } + } + } + } + } + } + + /* Draw the quiet zones */ + if ( $DrawQuietZone ) + { + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + $FreeZone = $Settings["FreeZone"]; + + $this->pChartObject->drawFilledCircle($X,$Y,$FreeZone,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>2)); + } + } + + + /* Draw the nodes */ + foreach($this->Data as $Key => $Settings) + { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + $Name = $Settings["Name"]; + $FreeZone = $Settings["FreeZone"]; + $Shape = $Settings["Shape"]; + $Size = $Settings["Size"]; + + $Color = array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"],"Alpha"=>$Settings["Alpha"],"BorderR"=>$Settings["BorderR"],"BorderG"=>$Settings["BorderG"],"BorderB"=>$Settings["BorderB"],"BorderApha"=>$Settings["BorderAlpha"]); + + if ( $Shape == NODE_SHAPE_CIRCLE ) + { + $this->pChartObject->drawFilledCircle($X,$Y,$Size,$Color); + } + elseif ( $Shape == NODE_SHAPE_TRIANGLE ) + { + $Points = ""; + $Points[] = cos(deg2rad(270)) * $Size + $X; $Points[] = sin(deg2rad(270)) * $Size + $Y; + $Points[] = cos(deg2rad(45)) * $Size + $X; $Points[] = sin(deg2rad(45)) * $Size + $Y; + $Points[] = cos(deg2rad(135)) * $Size + $X; $Points[] = sin(deg2rad(135)) * $Size + $Y; + $this->pChartObject->drawPolygon($Points,$Color); + } + elseif ( $Shape == NODE_SHAPE_SQUARE ) + { + $Offset = $Size/2; $Size = $Size / 2; + $this->pChartObject->drawFilledRectangle($X-$Offset,$Y-$Offset,$X+$Offset,$Y+$Offset,$Color); + } + + if ( $Name != "" ) + { + $LabelOptions = array("R"=>$this->Labels["R"],"G"=>$this->Labels["G"],"B"=>$this->Labels["B"],"Alpha"=>$this->Labels["Alpha"]); + + if ( $this->Labels["Type"] == LABEL_LIGHT ) + { + $LabelOptions["Align"] = TEXT_ALIGN_BOTTOMLEFT; + $this->pChartObject->drawText($X,$Y,$Name,$LabelOptions); + } + elseif ( $this->Labels["Type"] == LABEL_CLASSIC ) + { + $LabelOptions["Align"] = TEXT_ALIGN_TOPMIDDLE; + $LabelOptions["DrawBox"] = TRUE; + $LabelOptions["BoxAlpha"] = 50; + $LabelOptions["BorderOffset"] = 4; + $LabelOptions["RoundedRadius"] = 3; + $LabelOptions["BoxRounded"] = TRUE; + $LabelOptions["NoShadow"] = TRUE; + + $this->pChartObject->drawText($X,$Y+$Size+$TextPadding,$Name,$LabelOptions); + } + } + } + + /* Draw the vectors */ + if ( $DrawVectors ) + { + foreach($this->Data as $Key => $Settings) + { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Vectors"]) && $Settings["Type"] != NODE_TYPE_CENTRAL ) + { + foreach($Settings["Vectors"] as $ID => $Vector) + { + $Type = $Vector["Type"]; + $Force = $Vector["Force"]; + $Angle = $Vector["Angle"]; + $Factor = $Type == "A" ? $this->MagneticForceA : $this->MagneticForceR; + $Color = $Type == "A" ? array("FillR"=>255,"FillG"=>0,"FillB"=>0) : array("FillR"=>0,"FillG"=>255,"FillB"=>0); + + $X2 = cos(deg2rad($Angle)) * $Force * $Factor + $X1; + $Y2 = sin(deg2rad($Angle)) * $Force * $Factor + $Y1; + + $this->pChartObject->drawArrow($X1,$Y1,$X2,$Y2,$Color); + } + } + } + } + + return(array("Pass"=>$Jobs,"Conflicts"=>$Conflicts)); + } + + /* Return the distance between two points */ + function getDistance($X1,$Y1,$X2,$Y2) + { return (sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1))); } + + /* Return the angle made by a line and the X axis */ + function getAngle($X1,$Y1,$X2,$Y2) + { + $Opposite = $Y2 - $Y1; $Adjacent = $X2 - $X1;$Angle = rad2deg(atan2($Opposite,$Adjacent)); + if ($Angle > 0) { return($Angle); } else { return(360-abs($Angle)); } + } + + function intersect($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4) + { + $A = (($X3 * $Y4 - $X4 * $Y3) * ($X1 - $X2) - ($X1 * $Y2 - $X2 * $Y1) * ($X3 - $X4)); + $B = (($Y1 - $Y2) * ($X3 - $X4) - ($Y3 - $Y4) * ($X1 - $X2)); + + if ( $B == 0 ) { return(FALSE); } + $Xi = $A / $B; + + $C = ($X1 - $X2); + if ( $C == 0 ) { return(FALSE); } + $Yi = $Xi * (($Y1 - $Y2)/$C) + (($X1 * $Y2 - $X2 * $Y1)/$C); + + if ( $Xi >= min($X1,$X2) && $Xi >= min($X3,$X4) && $Xi <= max($X1,$X2) && $Xi <= max($X3,$X4)) + { + if ( $Yi >= min($Y1,$Y2) && $Yi >= min($Y3,$Y4) && $Yi <= max($Y1,$Y2) && $Yi <= max($Y3,$Y4)) + { return(TRUE); } + } + + return(FALSE); + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pStock.class.php b/webdata/graph/pchart/class/pStock.class.php new file mode 100644 index 0000000..b31c3e7 --- /dev/null +++ b/webdata/graph/pchart/class/pStock.class.php @@ -0,0 +1,216 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /* Draw a stock chart */ + function drawStockChart($Format="") + { + $SerieOpen = isset($Format["SerieOpen"]) ? $Format["SerieOpen"] : "Open"; + $SerieClose = isset($Format["SerieClose"]) ? $Format["SerieClose"] : "Close"; + $SerieMin = isset($Format["SerieMin"]) ? $Format["SerieMin"] : "Min"; + $SerieMax = isset($Format["SerieMax"]) ? $Format["SerieMax"] : "Max"; + $SerieMedian = isset($Format["SerieMedian"]) ? $Format["SerieMedian"] : NULL; + $LineWidth = isset($Format["LineWidth"]) ? $Format["LineWidth"] : 1; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 0; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 0; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 0; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 100; + $ExtremityWidth = isset($Format["ExtremityWidth"]) ? $Format["ExtremityWidth"] : 1; + $ExtremityLength = isset($Format["ExtremityLength"]) ? $Format["ExtremityLength"] : 3; + $ExtremityR = isset($Format["ExtremityR"]) ? $Format["ExtremityR"] : 0; + $ExtremityG = isset($Format["ExtremityG"]) ? $Format["ExtremityG"] : 0; + $ExtremityB = isset($Format["ExtremityB"]) ? $Format["ExtremityB"] : 0; + $ExtremityAlpha = isset($Format["ExtremityAlpha"]) ? $Format["ExtremityAlpha"] : 100; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 8; + $BoxUpR = isset($Format["BoxUpR"]) ? $Format["BoxUpR"] : 188; + $BoxUpG = isset($Format["BoxUpG"]) ? $Format["BoxUpG"] : 224; + $BoxUpB = isset($Format["BoxUpB"]) ? $Format["BoxUpB"] : 46; + $BoxUpAlpha = isset($Format["BoxUpAlpha"]) ? $Format["BoxUpAlpha"] : 100; + $BoxUpSurrounding = isset($Format["BoxUpSurrounding"]) ? $Format["BoxUpSurrounding"] : NULL; + $BoxUpBorderR = isset($Format["BoxUpBorderR"]) ? $Format["BoxUpBorderR"] : $BoxUpR-20; + $BoxUpBorderG = isset($Format["BoxUpBorderG"]) ? $Format["BoxUpBorderG"] : $BoxUpG-20; + $BoxUpBorderB = isset($Format["BoxUpBorderB"]) ? $Format["BoxUpBorderB"] : $BoxUpB-20; + $BoxUpBorderAlpha = isset($Format["BoxUpBorderAlpha"]) ? $Format["BoxUpBorderAlpha"] : 100; + $BoxDownR = isset($Format["BoxDownR"]) ? $Format["BoxDownR"] : 224; + $BoxDownG = isset($Format["BoxDownG"]) ? $Format["BoxDownG"] : 100; + $BoxDownB = isset($Format["BoxDownB"]) ? $Format["BoxDownB"] : 46; + $BoxDownAlpha = isset($Format["BoxDownAlpha"]) ? $Format["BoxDownAlpha"] : 100; + $BoxDownSurrounding= isset($Format["BoxDownSurrounding"]) ? $Format["BoxDownSurrounding"] : NULL; + $BoxDownBorderR = isset($Format["BoxDownBorderR"]) ? $Format["BoxDownBorderR"] : $BoxDownR-20; + $BoxDownBorderG = isset($Format["BoxDownBorderG"]) ? $Format["BoxDownBorderG"] : $BoxDownG-20; + $BoxDownBorderB = isset($Format["BoxDownBorderB"]) ? $Format["BoxDownBorderB"] : $BoxDownB-20; + $BoxDownBorderAlpha= isset($Format["BoxDownBorderAlpha"]) ? $Format["BoxDownBorderAlpha"] : 100; + $ShadowOnBoxesOnly = isset($Format["ShadowOnBoxesOnly"]) ? $Format["ShadowOnBoxesOnly"] : TRUE; + $MedianR = isset($Format["MedianR"]) ? $Format["MedianR"] : 255; + $MedianG = isset($Format["MedianG"]) ? $Format["MedianG"] : 0; + $MedianB = isset($Format["MedianB"]) ? $Format["MedianB"] : 0; + $MedianAlpha = isset($Format["MedianAlpha"]) ? $Format["MedianAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : "Stock Chart"; + + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( $BoxUpSurrounding != NULL ) { $BoxUpBorderR = $BoxUpR + $BoxUpSurrounding; $BoxUpBorderG = $BoxUpG + $BoxUpSurrounding; $BoxUpBorderB = $BoxUpB + $BoxUpSurrounding; } + if ( $BoxDownSurrounding != NULL ) { $BoxDownBorderR = $BoxDownR + $BoxDownSurrounding; $BoxDownBorderG = $BoxDownG + $BoxDownSurrounding; $BoxDownBorderB = $BoxDownB + $BoxDownSurrounding; } + + if ( $LineWidth != 1 ) { $LineOffset = $LineWidth / 2; } + $BoxOffset = $BoxWidth / 2; + + $Data = $this->pChartObject->DataSet->getData(); + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + if ( !isset($Data["Series"][$SerieOpen]) || !isset($Data["Series"][$SerieClose]) || !isset($Data["Series"][$SerieMin]) || !isset($Data["Series"][$SerieMax]) ) + return(STOCK_MISSING_SERIE); + + $Plots = ""; + foreach($Data["Series"][$SerieOpen]["Data"] as $Key => $Value) + { + $Point = ""; + if ( isset($Data["Series"][$SerieClose]["Data"][$Key]) || isset($Data["Series"][$SerieMin]["Data"][$Key]) || isset($Data["Series"][$SerieMax]["Data"][$Key]) ) + $Point = array($Value,$Data["Series"][$SerieClose]["Data"][$Key],$Data["Series"][$SerieMin]["Data"][$Key],$Data["Series"][$SerieMax]["Data"][$Key]); + if ( $SerieMedian != NULL && isset($Data["Series"][$SerieMedian]["Data"][$Key]) ) + $Point[] = $Data["Series"][$SerieMedian]["Data"][$Key]; + + $Plots[] = $Point; + } + + $AxisID = $Data["Series"][$SerieOpen]["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $YZero = $this->pChartObject->scaleComputeY(0,array("AxisID"=>$AxisID)); + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $LineSettings = array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha); + $ExtremitySettings = array("R"=>$ExtremityR,"G"=>$ExtremityG,"B"=>$ExtremityB,"Alpha"=>$ExtremityAlpha); + $BoxUpSettings = array("R"=>$BoxUpR,"G"=>$BoxUpG,"B"=>$BoxUpB,"Alpha"=>$BoxUpAlpha,"BorderR"=>$BoxUpBorderR,"BorderG"=>$BoxUpBorderG,"BorderB"=>$BoxUpBorderB,"BorderAlpha"=>$BoxUpBorderAlpha); + $BoxDownSettings = array("R"=>$BoxDownR,"G"=>$BoxDownG,"B"=>$BoxDownB,"Alpha"=>$BoxDownAlpha,"BorderR"=>$BoxDownBorderR,"BorderG"=>$BoxDownBorderG,"BorderB"=>$BoxDownBorderB,"BorderAlpha"=>$BoxDownBorderAlpha); + $MedianSettings = array("R"=>$MedianR,"G"=>$MedianG,"B"=>$MedianB,"Alpha"=>$MedianAlpha); + + foreach($Plots as $Key =>$Points) + { + $PosArray = $this->pChartObject->scaleComputeY($Points,array("AxisID"=>$AxisID)); + + $Values = "Open :".$Data["Series"][$SerieOpen]["Data"][$Key]."
Close : ".$Data["Series"][$SerieClose]["Data"][$Key]."
Min : ".$Data["Series"][$SerieMin]["Data"][$Key]."
Max : ".$Data["Series"][$SerieMax]["Data"][$Key]."
"; + if ( $SerieMedian != NULL ) { $Values = $Values."Median : ".$Data["Series"][$SerieMedian]["Data"][$Key]."
"; } + if ( $PosArray[0] > $PosArray[1] ) { $ImageMapColor = $this->pChartObject->toHTMLColor($BoxUpR,$BoxUpG,$BoxUpB); } else { $ImageMapColor = $this->pChartObject->toHTMLColor($BoxDownR,$BoxDownG,$BoxDownB); } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) + { + if ( $YZero > $this->pChartObject->GraphAreaY2-1 ) { $YZero = $this->pChartObject->GraphAreaY2-1; } + if ( $YZero < $this->pChartObject->GraphAreaY1+1 ) { $YZero = $this->pChartObject->GraphAreaY1+1; } + + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; } + + if ( $ShadowOnBoxesOnly ) { $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE; } + + if ( $LineWidth == 1 ) + $this->pChartObject->drawLine($X,$PosArray[2],$X,$PosArray[3],$LineSettings); + else + $this->pChartObject->drawFilledRectangle($X-$LineOffset,$PosArray[2],$X+$LineOffset,$PosArray[3],$LineSettings); + + if ( $ExtremityWidth == 1 ) + { + $this->pChartObject->drawLine($X-$ExtremityLength,$PosArray[2],$X+$ExtremityLength,$PosArray[2],$ExtremitySettings); + $this->pChartObject->drawLine($X-$ExtremityLength,$PosArray[3],$X+$ExtremityLength,$PosArray[3],$ExtremitySettings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$ExtremityLength).",".floor($PosArray[2]).",".floor($X+$ExtremityLength).",".floor($PosArray[3]),$ImageMapColor,$ImageMapTitle,$Values); } + } + else + { + $this->pChartObject->drawFilledRectangle($X-$ExtremityLength,$PosArray[2],$X+$ExtremityLength,$PosArray[2]-$ExtremityWidth,$ExtremitySettings); + $this->pChartObject->drawFilledRectangle($X-$ExtremityLength,$PosArray[3],$X+$ExtremityLength,$PosArray[3]+$ExtremityWidth,$ExtremitySettings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$ExtremityLength).",".floor($PosArray[2]-$ExtremityWidth).",".floor($X+$ExtremityLength).",".floor($PosArray[3]+$ExtremityWidth),$ImageMapColor,$ImageMapTitle,$Values); } + } + + if ( $ShadowOnBoxesOnly ) { $this->pChartObject->Shadow = $RestoreShadow; } + + if ( $PosArray[0] > $PosArray[1] ) + $this->pChartObject->drawFilledRectangle($X-$BoxOffset,$PosArray[0],$X+$BoxOffset,$PosArray[1],$BoxUpSettings); + else + $this->pChartObject->drawFilledRectangle($X-$BoxOffset,$PosArray[0],$X+$BoxOffset,$PosArray[1],$BoxDownSettings); + + if ( isset($PosArray[4]) ) + $this->pChartObject->drawLine($X-$ExtremityLength,$PosArray[4],$X+$ExtremityLength,$PosArray[4],$MedianSettings); + + $X = $X + $XStep; + } + elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) + { + if ( $YZero > $this->pChartObject->GraphAreaX2-1 ) { $YZero = $this->pChartObject->GraphAreaX2-1; } + if ( $YZero < $this->pChartObject->GraphAreaX1+1 ) { $YZero = $this->pChartObject->GraphAreaX1+1; } + + if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; } + + if ( $LineWidth == 1 ) + $this->pChartObject->drawLine($PosArray[2],$Y,$PosArray[3],$Y,$LineSettings); + else + $this->pChartObject->drawFilledRectangle($PosArray[2],$Y-$LineOffset,$PosArray[3],$Y+$LineOffset,$LineSettings); + + if ( $ShadowOnBoxesOnly ) { $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE; } + + if ( $ExtremityWidth == 1 ) + { + $this->pChartObject->drawLine($PosArray[2],$Y-$ExtremityLength,$PosArray[2],$Y+$ExtremityLength,$ExtremitySettings); + $this->pChartObject->drawLine($PosArray[3],$Y-$ExtremityLength,$PosArray[3],$Y+$ExtremityLength,$ExtremitySettings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($PosArray[2]).",".floor($Y-$ExtremityLength).",".floor($PosArray[3]).",".floor($Y+$ExtremityLength),$ImageMapColor,$ImageMapTitle,$Values); } + } + else + { + $this->pChartObject->drawFilledRectangle($PosArray[2],$Y-$ExtremityLength,$PosArray[2]-$ExtremityWidth,$Y+$ExtremityLength,$ExtremitySettings); + $this->pChartObject->drawFilledRectangle($PosArray[3],$Y-$ExtremityLength,$PosArray[3]+$ExtremityWidth,$Y+$ExtremityLength,$ExtremitySettings); + + if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($PosArray[2]-$ExtremityWidth).",".floor($Y-$ExtremityLength).",".floor($PosArray[3]+$ExtremityWidth).",".floor($Y+$ExtremityLength),$ImageMapColor,$ImageMapTitle,$Values); } + } + + if ( $ShadowOnBoxesOnly ) { $this->pChartObject->Shadow = $RestoreShadow; } + + if ( $PosArray[0] < $PosArray[1] ) + $this->pChartObject->drawFilledRectangle($PosArray[0],$Y-$BoxOffset,$PosArray[1],$Y+$BoxOffset,$BoxUpSettings); + else + $this->pChartObject->drawFilledRectangle($PosArray[0],$Y-$BoxOffset,$PosArray[1],$Y+$BoxOffset,$BoxDownSettings); + + if ( isset($PosArray[4]) ) + $this->pChartObject->drawLine($PosArray[4],$Y-$ExtremityLength,$PosArray[4],$Y+$ExtremityLength,$MedianSettings); + + $Y = $Y + $XStep; + } + } + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/class/pSurface.class.php b/webdata/graph/pchart/class/pSurface.class.php new file mode 100644 index 0000000..bace49a --- /dev/null +++ b/webdata/graph/pchart/class/pSurface.class.php @@ -0,0 +1,315 @@ +pChartObject = $pChartObject; + $this->GridSize = 10; + $this->Points = ""; + } + + /* Define the grid size and initialise the 2D matrix */ + function setGrid($XSize=10,$YSize=10) + { + for($X=0; $X<=$XSize; $X++) { for($Y=0; $Y<=$YSize; $Y++) { $this->Points[$X][$Y]=UNKNOWN; } } + + $this->GridSizeX = $XSize; + $this->GridSizeY = $YSize; + } + + /* Add a point on the grid */ + function addPoint($X,$Y,$Value,$Force=TRUE) + { + if ( $X < 0 || $X >$this->GridSizeX ) { return(0); } + if ( $Y < 0 || $Y >$this->GridSizeY ) { return(0); } + + if ( $this->Points[$X][$Y] == UNKNOWN || $Force ) + $this->Points[$X][$Y] = $Value; + elseif ( $this->Points[$X][$Y] == UNKNOWN ) + $this->Points[$X][$Y] = $Value; + else + $this->Points[$X][$Y] = ($this->Points[$X][$Y] + $Value)/2; + } + + /* Write the X labels */ + function writeXLabels($Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5; + $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_TOP; + $Labels = isset($Format["Labels"]) ? $Format["Labels"] : NULL; + $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0; + + if ( $Labels != NULL && !is_array($Labels) ) { $Label = $Labels; $Labels = ""; $Labels[] = $Label; } + + $X0 = $this->pChartObject->GraphAreaX1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + + $Settings = array("Angle"=>$Angle,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Position == LABEL_POSITION_TOP ) + { + $YPos = $this->pChartObject->GraphAreaY1 - $Padding; + if ($Angle == 0 ) { $Settings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; } + if ($Angle != 0 ) { $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + } + elseif ( $Position == LABEL_POSITION_BOTTOM ) + { + $YPos = $this->pChartObject->GraphAreaY2 + $Padding; + if ($Angle == 0 ) { $Settings["Align"] = TEXT_ALIGN_TOPMIDDLE; } + if ($Angle != 0 ) { $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + } + else + return(-1); + + for($X=0;$X<=$this->GridSizeX;$X++) + { + $XPos = floor($X0+$X*$XSize + $XSize/2); + + if( $Labels == NULL || !isset($Labels[$X]) ) + $Value = $X+$CountOffset; + else + $Value = $Labels[$X]; + + $this->pChartObject->drawText($XPos,$YPos,$Value,$Settings); + } + } + + /* Write the Y labels */ + function writeYLabels($Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5; + $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_LEFT; + $Labels = isset($Format["Labels"]) ? $Format["Labels"] : NULL; + $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0; + + if ( $Labels != NULL && !is_array($Labels) ) { $Label = $Labels; $Labels = ""; $Labels[] = $Label; } + + $Y0 = $this->pChartObject->GraphAreaY1; + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + $Settings = array("Angle"=>$Angle,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Position == LABEL_POSITION_LEFT ) + { $XPos = $this->pChartObject->GraphAreaX1 - $Padding; $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + elseif ( $Position == LABEL_POSITION_RIGHT ) + { $XPos = $this->pChartObject->GraphAreaX2 + $Padding; $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + else + return(-1); + + for($Y=0;$Y<=$this->GridSizeY;$Y++) + { + $YPos = floor($Y0+$Y*$YSize + $YSize/2); + + if( $Labels == NULL || !isset($Labels[$Y]) ) + $Value = $Y+$CountOffset; + else + $Value = $Labels[$Y]; + + $this->pChartObject->drawText($XPos,$YPos,$Value,$Settings); + } + } + + /* Draw the area arround the specified Threshold */ + function drawContour($Threshold,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 3; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 0; + + $X0 = $this->pChartObject->GraphAreaX1; + $Y0 = $this->pChartObject->GraphAreaY1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks); + + for($X=0;$X<=$this->GridSizeX;$X++) + { + for($Y=0;$Y<=$this->GridSizeY;$Y++) + { + $Value = $this->Points[$X][$Y]; + + if ( $Value != UNKNOWN && $Value != IGNORED && $Value >= $Threshold) + { + $X1 = floor($X0+$X*$XSize)+$Padding; + $Y1 = floor($Y0+$Y*$YSize)+$Padding; + $X2 = floor($X0+$X*$XSize+$XSize); + $Y2 = floor($Y0+$Y*$YSize+$YSize); + + if ( $X > 0 && $this->Points[$X-1][$Y] != UNKNOWN && $this->Points[$X-1][$Y] != IGNORED && $this->Points[$X-1][$Y] < $Threshold) + $this->pChartObject->drawLine($X1,$Y1,$X1,$Y2,$Color); + if ( $Y > 0 && $this->Points[$X][$Y-1] != UNKNOWN && $this->Points[$X][$Y-1] != IGNORED && $this->Points[$X][$Y-1] < $Threshold) + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y1,$Color); + if ( $X < $this->GridSizeX && $this->Points[$X+1][$Y] != UNKNOWN && $this->Points[$X+1][$Y] != IGNORED && $this->Points[$X+1][$Y] < $Threshold) + $this->pChartObject->drawLine($X2,$Y1,$X2,$Y2,$Color); + if ( $Y < $this->GridSizeY && $this->Points[$X][$Y+1] != UNKNOWN && $this->Points[$X][$Y+1] != IGNORED && $this->Points[$X][$Y+1] < $Threshold) + $this->pChartObject->drawLine($X1,$Y2,$X2,$Y2,$Color); + } + } + } + } + + /* Draw the surface chart */ + function drawSurface($Format="") + { + $Palette = isset($Format["Palette"]) ? $Format["Palette"] : NULL; + $ShadeR1 = isset($Format["ShadeR1"]) ? $Format["ShadeR1"] : 77; + $ShadeG1 = isset($Format["ShadeG1"]) ? $Format["ShadeG1"] : 205; + $ShadeB1 = isset($Format["ShadeB1"]) ? $Format["ShadeB1"] : 21; + $ShadeA1 = isset($Format["ShadeA1"]) ? $Format["ShadeA1"] : 40; + $ShadeR2 = isset($Format["ShadeR2"]) ? $Format["ShadeR2"] : 227; + $ShadeG2 = isset($Format["ShadeG2"]) ? $Format["ShadeG2"] : 135; + $ShadeB2 = isset($Format["ShadeB2"]) ? $Format["ShadeB2"] : 61; + $ShadeA2 = isset($Format["ShadeA2"]) ? $Format["ShadeA2"] : 100; + $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : -1; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 1; + + $X0 = $this->pChartObject->GraphAreaX1; + $Y0 = $this->pChartObject->GraphAreaY1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + for($X=0;$X<=$this->GridSizeX;$X++) + { + for($Y=0;$Y<=$this->GridSizeY;$Y++) + { + $Value = $this->Points[$X][$Y]; + + if ( $Value != UNKNOWN && $Value != IGNORED ) + { + $X1 = floor($X0+$X*$XSize)+$Padding; + $Y1 = floor($Y0+$Y*$YSize)+$Padding; + $X2 = floor($X0+$X*$XSize+$XSize); + $Y2 = floor($Y0+$Y*$YSize+$YSize); + + if ( $Palette != NULL ) + { + if ( isset($Palette[$Value]) && isset($Palette[$Value]["R"]) ) { $R = $Palette[$Value]["R"]; } else { $R = 0; } + if ( isset($Palette[$Value]) && isset($Palette[$Value]["G"]) ) { $G = $Palette[$Value]["G"]; } else { $G = 0; } + if ( isset($Palette[$Value]) && isset($Palette[$Value]["B"]) ) { $B = $Palette[$Value]["B"]; } else { $B = 0; } + if ( isset($Palette[$Value]) && isset($Palette[$Value]["Alpha"]) ) { $Alpha = $Palette[$Value]["Alpha"]; } else { $Alpha = 1000; } + } + else + { + $R = (($ShadeR2-$ShadeR1)/100)*$Value + $ShadeR1; + $G = (($ShadeG2-$ShadeG1)/100)*$Value + $ShadeG1; + $B = (($ShadeB2-$ShadeB1)/100)*$Value + $ShadeB1; + $Alpha = (($ShadeA2-$ShadeA1)/100)*$Value + $ShadeA1; + } + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Border ) { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; } + if ( $Surrounding != -1 ) { $Settings["BorderR"] = $R+$Surrounding; $Settings["BorderG"] = $G+$Surrounding; $Settings["BorderB"] = $B+$Surrounding; } + + $this->pChartObject->drawFilledRectangle($X1,$Y1,$X2-1,$Y2-1,$Settings); + } + } + } + } + + /* Compute the missing points */ + function computeMissing() + { + $Missing = ""; + for($X=0;$X<=$this->GridSizeX;$X++) + { + for($Y=0;$Y<=$this->GridSizeY;$Y++) + { + if ( $this->Points[$X][$Y] == UNKNOWN ) + $Missing[] = $X.",".$Y; + } + } + shuffle($Missing); + + foreach($Missing as $Key => $Pos) + { + $Pos = preg_split("/,/",$Pos); + $X = $Pos[0]; + $Y = $Pos[1]; + + if ( $this->Points[$X][$Y] == UNKNOWN ) + { + $NearestNeighbor = $this->getNearestNeighbor($X,$Y); + + $Value = 0; $Points = 0; + for($Xi=$X-$NearestNeighbor;$Xi<=$X+$NearestNeighbor;$Xi++) + { + for($Yi=$Y-$NearestNeighbor;$Yi<=$Y+$NearestNeighbor;$Yi++) + { + if ($Xi >=0 && $Yi >= 0 && $Xi <= $this->GridSizeX && $Yi <= $this->GridSizeY && $this->Points[$Xi][$Yi] != UNKNOWN && $this->Points[$Xi][$Yi] != IGNORED) + { + $Value = $Value + $this->Points[$Xi][$Yi]; $Points++; + } + } + } + + if ( $Points != 0 ) { $this->Points[$X][$Y] = $Value / $Points; } + } + } + } + + /* Return the nearest Neighbor distance of a point */ + function getNearestNeighbor($Xp,$Yp) + { + $Nearest = UNKNOWN; + for($X=0;$X<=$this->GridSizeX;$X++) + { + for($Y=0;$Y<=$this->GridSizeY;$Y++) + { + if ( $this->Points[$X][$Y] != UNKNOWN && $this->Points[$X][$Y] != IGNORED ) + { + $DistanceX = max($Xp,$X)-min($Xp,$X); + $DistanceY = max($Yp,$Y)-min($Yp,$Y); + $Distance = max($DistanceX,$DistanceY); + if ( $Distance < $Nearest || $Nearest == UNKNOWN ) { $Nearest = $Distance; } + } + } + } + return($Nearest); + } + } +?> \ No newline at end of file diff --git a/webdata/graph/pchart/data/128B.db b/webdata/graph/pchart/data/128B.db new file mode 100644 index 0000000..20de3c9 --- /dev/null +++ b/webdata/graph/pchart/data/128B.db @@ -0,0 +1,107 @@ +0;32;11011001100 +1;33;11001101100 +2;34;11001100110 +3;35;10010011000 +4;36;10010001100 +5;37;10001001100 +6;38;10011001000 +7;39;10011000100 +8;40;10001100100 +9;41;11001001000 +10;42;11001000100 +11;43;11000100100 +12;44;10110011100 +13;45;10011011100 +14;46;10011001110 +15;47;10111001100 +16;48;10011101100 +17;49;10011100110 +18;50;11001110010 +19;51;11001011100 +20;52;11001001110 +21;53;11011100100 +22;54;11001110100 +23;55;11101101110 +24;56;11101001100 +25;57;11100101100 +26;58;11100100110 +27;59;11101100100 +28;60;11100110100 +29;61;11100110010 +30;62;11011011000 +31;63;11011000110 +32;64;11000110110 +33;65;10100011000 +34;66;10001011000 +35;67;10001000110 +36;68;10110001000 +37;69;10001101000 +38;70;10001100010 +39;71;11010001000 +40;72;11000101000 +41;73;11000100010 +42;74;10110111000 +43;75;10110001110 +44;76;10001101110 +45;77;10111011000 +46;78;10111000110 +47;79;10001110110 +48;80;11101110110 +49;81;11010001110 +50;82;11000101110 +51;83;11011101000 +52;84;11011100010 +53;85;11011101110 +54;86;11101011000 +55;87;11101000110 +56;88;11100010110 +57;89;11101101000 +58;90;11101100010 +59;91;11100011010 +60;92;11101111010 +61;93;11001000010 +62;94;11110001010 +63;95;10100110000 +64;96;10100001100 +65;97;10010110000 +66;98;10010000110 +67;99;10000101100 +68;100;10000100110 +69;101;10110010000 +70;102;10110000100 +71;103;10011010000 +72;104;10011000010 +73;105;10000110100 +74;106;10000110010 +75;107;11000010010 +76;108;11001010000 +77;109;11110111010 +78;110;11000010100 +79;111;10001111010 +80;112;10100111100 +81;113;10010111100 +82;114;10010011110 +83;115;10111100100 +84;116;10011110100 +85;117;10011110010 +86;118;11110100100 +87;119;11110010100 +88;120;11110010010 +89;121;11011011110 +90;122;11011110110 +91;123;11110110110 +92;124;10101111000 +93;125;10100011110 +94;126;10001011110 +95;200;10111101000 +96;201;10111100010 +97;202;11110101000 +98;203;11110100010 +99;204;10111011110 +100;205;10111101110 +101;206;11101011110 +102;207;11110101110 +103;208;11010000100 +104;209;11010010000 +105;210;11010011100 +106;211;1100011101011 \ No newline at end of file diff --git a/webdata/graph/pchart/data/39.db b/webdata/graph/pchart/data/39.db new file mode 100644 index 0000000..b1a74d6 --- /dev/null +++ b/webdata/graph/pchart/data/39.db @@ -0,0 +1,44 @@ +0;101001101101 +1;110100101011 +2;101100101011 +3;110110010101 +4;101001101011 +5;110100110101 +6;101100110101 +7;101001011011 +8;110100101101 +9;101100101101 +A;110101001011 +B;101101001011 +C;110110100101 +D;101011001011 +E;110101100101 +F;101101100101 +G;101010011011 +H;110101001101 +I;101101001101 +J;101011001101 +K;110101010011 +L;101101010011 +M;110110101001 +N;101011010011 +O;110101101001 +P;101101101001 +Q;101010110011 +R;110101011001 +S;101101011001 +T;101011011001 +U;110010101011 +V;100110101011 +W;110011010101 +X;100101101011 +Y;110010110101 +Z;100110110101 +-;100101011011 +.;110010101101 + ;100110101101 +$;100100100101 +/;100100101001 ++;100101001001 +%;101001001001 +*;100101101101 \ No newline at end of file diff --git a/webdata/graph/pchart/fonts/Bedizen.ttf b/webdata/graph/pchart/fonts/Bedizen.ttf new file mode 100644 index 0000000..d115733 Binary files /dev/null and b/webdata/graph/pchart/fonts/Bedizen.ttf differ diff --git a/webdata/graph/pchart/fonts/Forgotte.ttf b/webdata/graph/pchart/fonts/Forgotte.ttf new file mode 100644 index 0000000..a2f7f4a Binary files /dev/null and b/webdata/graph/pchart/fonts/Forgotte.ttf differ diff --git a/webdata/graph/pchart/fonts/GeosansLight.ttf b/webdata/graph/pchart/fonts/GeosansLight.ttf new file mode 100644 index 0000000..055932a Binary files /dev/null and b/webdata/graph/pchart/fonts/GeosansLight.ttf differ diff --git a/webdata/graph/pchart/fonts/MankSans.ttf b/webdata/graph/pchart/fonts/MankSans.ttf new file mode 100644 index 0000000..a6146a9 Binary files /dev/null and b/webdata/graph/pchart/fonts/MankSans.ttf differ diff --git a/webdata/graph/pchart/fonts/Silkscreen.ttf b/webdata/graph/pchart/fonts/Silkscreen.ttf new file mode 100644 index 0000000..ae4425d Binary files /dev/null and b/webdata/graph/pchart/fonts/Silkscreen.ttf differ diff --git a/webdata/graph/pchart/fonts/advent_light.ttf b/webdata/graph/pchart/fonts/advent_light.ttf new file mode 100644 index 0000000..514030a Binary files /dev/null and b/webdata/graph/pchart/fonts/advent_light.ttf differ diff --git a/webdata/graph/pchart/fonts/calibri.ttf b/webdata/graph/pchart/fonts/calibri.ttf new file mode 100644 index 0000000..8b6e3c9 Binary files /dev/null and b/webdata/graph/pchart/fonts/calibri.ttf differ diff --git a/webdata/graph/pchart/fonts/pf_arma_five.ttf b/webdata/graph/pchart/fonts/pf_arma_five.ttf new file mode 100644 index 0000000..db04ec3 Binary files /dev/null and b/webdata/graph/pchart/fonts/pf_arma_five.ttf differ diff --git a/webdata/graph/pchart/fonts/verdana.ttf b/webdata/graph/pchart/fonts/verdana.ttf new file mode 100644 index 0000000..5a059d2 Binary files /dev/null and b/webdata/graph/pchart/fonts/verdana.ttf differ diff --git a/webdata/graph/pchart/index.php b/webdata/graph/pchart/index.php new file mode 100644 index 0000000..e431508 --- /dev/null +++ b/webdata/graph/pchart/index.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/webdata/graph/pchart/palettes/autumn.color b/webdata/graph/pchart/palettes/autumn.color new file mode 100644 index 0000000..80ffbc0 --- /dev/null +++ b/webdata/graph/pchart/palettes/autumn.color @@ -0,0 +1,6 @@ +185,106,154,100 +216,137,184,100 +156,192,137,100 +216,243,201,100 +253,232,215,100 +255,255,255,100 diff --git a/webdata/graph/pchart/palettes/blind.color b/webdata/graph/pchart/palettes/blind.color new file mode 100644 index 0000000..9d62238 --- /dev/null +++ b/webdata/graph/pchart/palettes/blind.color @@ -0,0 +1,6 @@ +109,152,171,100 +0,39,94,100 +254,183,41,100 +168,177,184,100 +255,255,255,100 +0,0,0,100 diff --git a/webdata/graph/pchart/palettes/evening.color b/webdata/graph/pchart/palettes/evening.color new file mode 100644 index 0000000..5d0c1a5 --- /dev/null +++ b/webdata/graph/pchart/palettes/evening.color @@ -0,0 +1,6 @@ +242,245,237,100 +255,194,0,100 +255,91,0,100 +184,0,40,100 +132,0,46,100 +74,192,242,100 diff --git a/webdata/graph/pchart/palettes/kitchen.color b/webdata/graph/pchart/palettes/kitchen.color new file mode 100644 index 0000000..b0eeb33 --- /dev/null +++ b/webdata/graph/pchart/palettes/kitchen.color @@ -0,0 +1,6 @@ +155,225,251,100 +197,239,253,100 +189,32,49,100 +35,31,32,100 +255,255,255,100 +0,98,149,100 diff --git a/webdata/graph/pchart/palettes/light.color b/webdata/graph/pchart/palettes/light.color new file mode 100644 index 0000000..d0657db --- /dev/null +++ b/webdata/graph/pchart/palettes/light.color @@ -0,0 +1,7 @@ +239,210,121,100 +149,203,233,100 +2,71,105,100 +175,215,117,100 +44,87,0,100 +222,157,127,100 + diff --git a/webdata/graph/pchart/palettes/navy.color b/webdata/graph/pchart/palettes/navy.color new file mode 100644 index 0000000..3b6df5e --- /dev/null +++ b/webdata/graph/pchart/palettes/navy.color @@ -0,0 +1,6 @@ +25,78,132,100 +59,107,156,100 +31,36,42,100 +55,65,74,100 +96,187,34,100 +242,186,187,100 diff --git a/webdata/graph/pchart/palettes/shade.color b/webdata/graph/pchart/palettes/shade.color new file mode 100644 index 0000000..0e43a1d --- /dev/null +++ b/webdata/graph/pchart/palettes/shade.color @@ -0,0 +1,6 @@ +117,113,22,100 +174,188,33,100 +217,219,86,100 +0,71,127,100 +76,136,190,100 +141,195,233,100 diff --git a/webdata/graph/pchart/palettes/spring.color b/webdata/graph/pchart/palettes/spring.color new file mode 100644 index 0000000..386cbc4 --- /dev/null +++ b/webdata/graph/pchart/palettes/spring.color @@ -0,0 +1,6 @@ +146,123,81,100 +168,145,102,100 +128,195,28,100 +188,221,90,100 +255,121,0,100 +251,179,107,100 diff --git a/webdata/graph/pchart/palettes/summer.color b/webdata/graph/pchart/palettes/summer.color new file mode 100644 index 0000000..1609534 --- /dev/null +++ b/webdata/graph/pchart/palettes/summer.color @@ -0,0 +1,6 @@ +253,184,19,100 +246,139,31,100 +241,112,34,100 +98,194,204,100 +228,246,248,100 +238,246,108,100 diff --git a/webdata/graph/pchart/readme.txt b/webdata/graph/pchart/readme.txt new file mode 100644 index 0000000..6591712 Binary files /dev/null and b/webdata/graph/pchart/readme.txt differ diff --git a/webdata/graphs.php b/webdata/graphs.php new file mode 100644 index 0000000..400d01f --- /dev/null +++ b/webdata/graphs.php @@ -0,0 +1,93 @@ + + + + + Traffic Graphing + "; + } + ?> + + +
+

LiquidWeb Traffic Monitoring

+

Inbound Traffic Graphs

+ +
+
+

You must select a service to view data.

+

These graphs illustrate the total number of incoming connections for the selected service.

+ + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +
+ +

+ For which service would you like to see data? +
+ +
+ +

+
+ + + +
+
+ Every 15 minutes for the past 12 hours: +
+ +
+
+ Every 30 minutes for the past 24 hours: +
+ +
+
+ Every 60 minutes for the past 48 hours: +
+ +
+
+ Every Day for the past 30 days: +
+ +
+ + diff --git a/webdata/includes/db_config.php b/webdata/includes/db_config.php new file mode 100644 index 0000000..0fd5c97 --- /dev/null +++ b/webdata/includes/db_config.php @@ -0,0 +1,6 @@ + diff --git a/webdata/includes/menu.php b/webdata/includes/menu.php new file mode 100644 index 0000000..8662a9a --- /dev/null +++ b/webdata/includes/menu.php @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/webdata/index.php b/webdata/index.php new file mode 100644 index 0000000..29aee76 --- /dev/null +++ b/webdata/index.php @@ -0,0 +1,182 @@ + + + + + + + + Traffic Monitoring + "; + ?> + + + + + +
+

LiquidWeb Traffic Monitoring

+ +
+
+

More information is available through the Menus above

+
+

Inbound SSH Traffic

+
+ (UNIX_TIMESTAMP() - 1800) GROUP BY src_ip ORDER BY COUNT(DISTINCT(dst_ip)) DESC LIMIT 10"; + + $result = $conn2->query($sql); + //If there are results, display them in a table + if ($result->num_rows >0) { + echo "Inbound connections from the last 30 minutes"; + echo "
"; + echo ""; + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
Source IP# of targets# of connectionsSource WhoisDestination IPs
".$row["src_ip"]."".$row["COUNT(DISTINCT(dst_ip))"]."".$row["COUNT(src_ip)"]."WhoisList
"; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
+
+ Total Connections, every 30 minutes for the past 24hrs. +
+ +
+ + + (UNIX_TIMESTAMP() - 900) GROUP BY src_ip"; + $iplist = mysqli_query($conn1, $query1); + + echo "Locations of the Unique Source IP addresses from the last 15 minutes"; + + //Initialize your first couple variables + $encodedString = ""; //This is the string that will hold all your location data + $x = 0; //This is a trigger to keep the string tidy + + + //Multiple rows are returned + while ($row = mysqli_fetch_array($iplist)) + { + $ip = $row['src_ip']; + $location = $geoip->lookupLocation($ip); + //This is to keep an empty first or last line from forming, when the string is split + if ( $x == 0 ) + { + $separator = ""; + } + else + { + //Each row in the database is separated in the string by four *'s + $separator = "****"; + } + //Saving to the String, each variable is separated by three &'s + $encodedString = $encodedString.$separator. + "

IP: ".$row['src_ip']. + "
Lat: ".$location->latitude. + "
Long: ".$location->longitude. + "

&&&".$location->latitude."&&&".$location->longitude; + $x = $x + 1; + } + $conn1->close(); + ?> + +
+ +
+ + + diff --git a/webdata/mapdata/jquery-1.6.2.min.js b/webdata/mapdata/jquery-1.6.2.min.js new file mode 100644 index 0000000..48590ec --- /dev/null +++ b/webdata/mapdata/jquery-1.6.2.min.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Jun 30 14:16:56 2011 -0400 + */ +(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. +shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j +)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/webdata/mapdata/jquery-ui.min.js b/webdata/mapdata/jquery-ui.min.js new file mode 100755 index 0000000..ac05c38 --- /dev/null +++ b/webdata/mapdata/jquery-ui.min.js @@ -0,0 +1,13 @@ +/*! jQuery UI - v1.11.2 - 2015-01-04 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("
"))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return n=!a&&o.length?e.widget.extend.apply(null,[n].concat(o)):n,a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))}),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("
"),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.widthi?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,e.top+p+f+m>u&&(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,e.top+p+f+m>d&&(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.draggable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.options;return this._blurActiveElement(t),this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(t){this.iframeBlocks=this.document.find(t).map(function(){var t=e(this);return e("
").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var i=this.document[0];if(this.handleElement.is(t.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(s){}},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===e(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(t),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._normalizeRightBottom(),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_refreshOffsets:function(e){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:e.pageX-this.offset.left,top:e.pageY-this.offset.top}},_mouseDrag:function(t,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return this._unblockFrames(),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.handleElement.is(t.target)&&this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper),n=s?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,e(a).width()-this.helperProportions.width-this.margins.left,(e(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)} +},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var n=e.extend({},i,{item:s.element});s.sortables=[],e(s.options.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var n=e.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,e.each(s.sortables,function(){var e=this;e.isOver?(e.isOver=0,s.cancelHelperRemoval=!0,e.cancelHelperRemoval=!1,e._storedCSS={position:e.placeholder.css("position"),top:e.placeholder.css("top"),left:e.placeholder.css("left")},e._mouseStop(t),e.options.helper=e.options._helper):(e.cancelHelperRemoval=!0,e._trigger("deactivate",t,n))})},drag:function(t,i,s){e.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&e.contains(a.element[0],this.element[0])&&(n=!1),n})),n?(a.isOver||(a.isOver=1,a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},t.target=a.currentItem[0],a._mouseCapture(t,!0),a._mouseStart(t,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",t),s.dropped=a.element,e.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(t),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",t,a._uiHash(a)),a._mouseStop(t,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),s._refreshOffsets(t),i.position=s._generatePosition(t,!0),s._trigger("fromSortable",t),s.dropped=!1,e.each(s.sortables,function(){this.refreshPositions()}))})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var n=e("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(t,i,s){var n=s.options;n._cursor&&e("body").css("cursor",n._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(t,i,s){var n=s.options;n._opacity&&e(i.helper).css("opacity",n._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-t.pageY=0;c--)h=s.snapElements[c].left-s.margins.left,l=h+s.snapElements[c].width,u=s.snapElements[c].top-s.margins.top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-y),a=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[c].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=n||a||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var n,a=s.options,o=e.makeArray(e(a.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",n+t)}),this.css("zIndex",n+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(t,i,s){var n=s.options;n._zIndex&&e(i.helper).css("zIndex",n._zIndex)}}),e.ui.draggable,e.widget("ui.droppable",{version:"1.11.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1)},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=e(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(i,{offset:i.element.offset()}),i.options.tolerance,t)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s,n){if(!i.offset)return!1;var a=(t.positionAbs||t.position.absolute).left+t.margins.left,o=(t.positionAbs||t.position.absolute).top+t.margins.top,r=a+t.helperProportions.width,h=o+t.helperProportions.height,l=i.offset.left,u=i.offset.top,d=l+i.proportions().width,c=u+i.proportions().height;switch(s){case"fit":return a>=l&&d>=r&&o>=u&&c>=h;case"intersect":return a+t.helperProportions.width/2>l&&d>r-t.helperProportions.width/2&&o+t.helperProportions.height/2>u&&c>h-t.helperProportions.height/2;case"pointer":return e(n.pageY,u,i.proportions().height)&&e(n.pageX,l,i.proportions().width);case"touch":return(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c)&&(a>=l&&d>=a||r>=l&&d>=r||l>a&&r>d);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance,i),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===n}),a.length&&(s=e(a[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable,e.widget("ui.resizable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(e){return parseInt(e,10)||0},_isNumber:function(e){return!isNaN(parseInt(e,10))},_hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return t[s]>0?!0:(t[s]=1,n=t[s]>0,t[s]=0,n)},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("
"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=this.element.children(this.handles[i]).first().show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=e(a.containment).scrollLeft()||0,s+=e(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var i,s,n=this.originalMousePosition,a=this.axis,o=t.pageX-n.left||0,r=t.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[t,o,r]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var e={};return this.position.top!==this.prevPosition.top&&(e.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(e.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(e.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(e.height=this.size.height+"px"),this.helper.css(e),e},_updateVirtualBoundaries:function(e){var t,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||e)&&(t=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,t>a.minWidth&&(a.minWidth=t),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(e){this.offset=this.helper.offset(),this._isNumber(e.left)&&(this.position.left=e.left),this._isNumber(e.top)&&(this.position.top=e.top),this._isNumber(e.height)&&(this.size.height=e.height),this._isNumber(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,i=this.size,s=this.axis;return this._isNumber(e.height)?e.width=e.height*this.aspectRatio:this._isNumber(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===s&&(e.left=t.left+(i.width-e.width),e.top=null),"nw"===s&&(e.top=t.top+(i.height-e.height),e.left=t.left+(i.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,i=this.axis,s=this._isNumber(e.width)&&t.maxWidth&&t.maxWidthe.width,o=this._isNumber(e.height)&&t.minHeight&&t.minHeight>e.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(e.width=t.minWidth),o&&(e.height=t.minHeight),s&&(e.width=t.maxWidth),n&&(e.height=t.maxHeight),a&&l&&(e.left=r-t.minWidth),s&&l&&(e.left=r-t.maxWidth),o&&u&&(e.top=h-t.minHeight),n&&u&&(e.top=h-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_getPaddingPlusBorderDimensions:function(e){for(var t=0,i=[],s=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],n=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];4>t;t++)i[t]=parseInt(s[t],10)||0,i[t]+=parseInt(n[t],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e,t=0,i=this.helper||this.element;this._proportionallyResizeElements.length>t;t++)e=this._proportionallyResizeElements[t],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(e)),e.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("
"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var t,i,s,n,a,o,r,h=e(this).resizable("instance"),l=h.options,u=h.element,d=l.containment,c=d instanceof e?d.get(0):/parent/.test(d)?u.parent().get(0):d;c&&(h.containerElement=e(c),/document/.test(d)||d===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(t=e(c),i=[],e(["Top","Right","Left","Bottom"]).each(function(e,s){i[e]=h._num(t.css("padding"+s))}),h.containerOffset=t.offset(),h.containerPosition=t.position(),h.containerSize={height:t.innerHeight()-i[3],width:t.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(c,"left")?c.scrollWidth:a,r=h._hasScroll(c)?c.scrollHeight:n,h.parentData={element:c,left:s.left,top:s.top,width:o,height:r}))},resize:function(t){var i,s,n,a,o=e(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,d={top:0,left:0},c=o.containerElement,p=!0;c[0]!==document&&/static/.test(c.css("position"))&&(d=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-d.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-d.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-d.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var t=e(this).resizable("instance"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t,i=e(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,d=Math.round((n.width-a.width)/l)*l,c=Math.round((n.height-a.height)/u)*u,p=a.width+d,f=a.height+c,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,y=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),y&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-c):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-d):((0>=f-u||0>=p-l)&&(t=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-c):(f=u-t.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-d):(p=u-t.height,i.size.width=p,i.position.left=o.left+a.width-p))}}),e.ui.resizable,e.widget("ui.selectable",e.ui.mouse,{version:"1.11.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this; +this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}}),e.widget("ui.sortable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===e.axis||this._isFloating(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,a.widgetName+"-item")===a?(s=e(this),!1):void 0}),e.data(t.target,a.widgetName+"-item")===a&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=e("").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?t.currentItem.children().each(function(){e(" ",t.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(e("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}}),e.widget("ui.accordion",{version:"1.11.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id"); +t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.length&&(!t.length||e.index()",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget);i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("
    ").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(s){s.target===t.element[0]||s.target===i||e.contains(i,s.target)||t.close()})})},menufocus:function(t,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:n})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&e.trim(s).length&&(this.liveRegion.children().hide(),e("
    ").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,t){var i=t.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",e,{item:i})&&this._value(i.value),this.term=this._value(),this.close(e),this.selectedItem=i}}),this.liveRegion=e("",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),"source"===e&&this._initSource(),"appendTo"===e&&this.menu.element.appendTo(this._appendTo()),"disabled"===e&&t&&this.xhr&&this.xhr.abort()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_initSource:function(){var t,i,s=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(i,s){s(e.ui.autocomplete.filter(t,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(t,n){s.xhr&&s.xhr.abort(),s.xhr=e.ajax({url:i,data:t,dataType:"json",success:function(e){n(e)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),i=this.menu.element.is(":visible"),s=e.altKey||e.ctrlKey||e.metaKey||e.shiftKey;(!t||t&&!i&&!s)&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){return e=null!=e?e:this._value(),this.term=this._value(),e.length").text(i.label).appendTo(t)},_move:function(e,t){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[e](t),void 0):(this.search(null,t),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(e,t),t.preventDefault())}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,i){var s=RegExp(e.ui.autocomplete.escapeRegex(i),"i");return e.grep(t,function(e){return s.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.children().hide(),e("
    ").text(i).appendTo(this.liveRegion))}}),e.ui.autocomplete;var c,p="ui-button ui-widget ui-state-default ui-corner-all",f="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",m=function(){var t=e(this);setTimeout(function(){t.find(":ui-button").button("refresh")},1)},g=function(t){var i=t.name,s=t.form,n=e([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?e(s).find("[name='"+i+"'][type=radio]"):e("[name='"+i+"'][type=radio]",t.ownerDocument).filter(function(){return!this.form})),n};e.widget("ui.button",{version:"1.11.2",defaultElement:"").addClass(this._triggerClass).html(a?e("").attr({src:a,alt:n,title:n}):n)),t[r?"before":"after"](i.trigger),i.trigger.click(function(){return e.datepicker._datepickerShowing&&e.datepicker._lastInput===t[0]?e.datepicker._hideDatepicker():e.datepicker._datepickerShowing&&e.datepicker._lastInput!==t[0]?(e.datepicker._hideDatepicker(),e.datepicker._showDatepicker(t[0])):e.datepicker._showDatepicker(t[0]),!1}))},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t,i,s,n,a=new Date(2009,11,20),o=this._get(e,"dateFormat");o.match(/[DM]/)&&(t=function(e){for(i=0,s=0,n=0;e.length>n;n++)e[n].length>i&&(i=e[n].length,s=n);return s},a.setMonth(t(this._get(e,o.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(t(this._get(e,o.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),e.input.attr("size",this._formatDate(e,a).length)}},_inlineDatepicker:function(t,i){var s=e(t);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),e.data(t,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(t),i.dpDiv.css("display","block"))},_dialogDatepicker:function(t,i,s,n,a){var o,h,l,u,d,c=this._dialogInst;return c||(this.uuid+=1,o="dp"+this.uuid,this._dialogInput=e(""),this._dialogInput.keydown(this._doKeyDown),e("body").append(this._dialogInput),c=this._dialogInst=this._newInst(this._dialogInput,!1),c.settings={},e.data(this._dialogInput[0],"datepicker",c)),r(c.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(c,i):i,this._dialogInput.val(i),this._pos=a?a.length?a:[a.pageX,a.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+u,l/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),c.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),e.blockUI&&e.blockUI(this.dpDiv),e.data(this._dialogInput[0],"datepicker",c),this},_destroyDatepicker:function(t){var i,s=e(t),n=e.data(t,"datepicker");s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty()) +},_enableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;this._disabledInputs.length>t;t++)if(this._disabledInputs[t]===e)return!0;return!1},_getInst:function(t){try{return e.data(t,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(t,i,s){var n,a,o,h,l=this._getInst(t);return 2===arguments.length&&"string"==typeof i?"defaults"===i?e.extend({},e.datepicker._defaults):l?"all"===i?e.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),a=this._getDateDatepicker(t,!0),o=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),r(l.settings,n),null!==o&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,o)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(t):this._enableDatepicker(t)),this._attachments(e(t),l),this._autoSize(l),this._setDate(l,a),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(e,t,i){this._optionDatepicker(e,t,i)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var i=this._getInst(e);i&&(this._setDate(i,t),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(e,t){var i=this._getInst(e);return i&&!i.inline&&this._setDateFromField(i,t),i?this._getDate(i):null},_doKeyDown:function(t){var i,s,n,a=e.datepicker._getInst(t.target),o=!0,r=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,e.datepicker._datepickerShowing)switch(t.keyCode){case 9:e.datepicker._hideDatepicker(),o=!1;break;case 13:return n=e("td."+e.datepicker._dayOverClass+":not(."+e.datepicker._currentClass+")",a.dpDiv),n[0]&&e.datepicker._selectDay(t.target,a.selectedMonth,a.selectedYear,n[0]),i=e.datepicker._get(a,"onSelect"),i?(s=e.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):e.datepicker._hideDatepicker(),!1;case 27:e.datepicker._hideDatepicker();break;case 33:e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 34:e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 35:(t.ctrlKey||t.metaKey)&&e.datepicker._clearDate(t.target),o=t.ctrlKey||t.metaKey;break;case 36:(t.ctrlKey||t.metaKey)&&e.datepicker._gotoToday(t.target),o=t.ctrlKey||t.metaKey;break;case 37:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?1:-1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 38:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,-7,"D"),o=t.ctrlKey||t.metaKey;break;case 39:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?-1:1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 40:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,7,"D"),o=t.ctrlKey||t.metaKey;break;default:o=!1}else 36===t.keyCode&&t.ctrlKey?e.datepicker._showDatepicker(this):o=!1;o&&(t.preventDefault(),t.stopPropagation())},_doKeyPress:function(t){var i,s,n=e.datepicker._getInst(t.target);return e.datepicker._get(n,"constrainInput")?(i=e.datepicker._possibleChars(e.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==t.charCode?t.keyCode:t.charCode),t.ctrlKey||t.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(t){var i,s=e.datepicker._getInst(t.target);if(s.input.val()!==s.lastVal)try{i=e.datepicker.parseDate(e.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,e.datepicker._getFormatConfig(s)),i&&(e.datepicker._setDateFromField(s),e.datepicker._updateAlternate(s),e.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(t){if(t=t.target||t,"input"!==t.nodeName.toLowerCase()&&(t=e("input",t.parentNode)[0]),!e.datepicker._isDisabledDatepicker(t)&&e.datepicker._lastInput!==t){var i,n,a,o,h,l,u;i=e.datepicker._getInst(t),e.datepicker._curInst&&e.datepicker._curInst!==i&&(e.datepicker._curInst.dpDiv.stop(!0,!0),i&&e.datepicker._datepickerShowing&&e.datepicker._hideDatepicker(e.datepicker._curInst.input[0])),n=e.datepicker._get(i,"beforeShow"),a=n?n.apply(t,[t,i]):{},a!==!1&&(r(i.settings,a),i.lastVal=null,e.datepicker._lastInput=t,e.datepicker._setDateFromField(i),e.datepicker._inDialog&&(t.value=""),e.datepicker._pos||(e.datepicker._pos=e.datepicker._findPos(t),e.datepicker._pos[1]+=t.offsetHeight),o=!1,e(t).parents().each(function(){return o|="fixed"===e(this).css("position"),!o}),h={left:e.datepicker._pos[0],top:e.datepicker._pos[1]},e.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),e.datepicker._updateDatepicker(i),h=e.datepicker._checkOffset(i,h,o),i.dpDiv.css({position:e.datepicker._inDialog&&e.blockUI?"static":o?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),i.inline||(l=e.datepicker._get(i,"showAnim"),u=e.datepicker._get(i,"duration"),i.dpDiv.css("z-index",s(e(t))+1),e.datepicker._datepickerShowing=!0,e.effects&&e.effects.effect[l]?i.dpDiv.show(l,e.datepicker._get(i,"showOptions"),u):i.dpDiv[l||"show"](l?u:null),e.datepicker._shouldFocusInput(i)&&i.input.focus(),e.datepicker._curInst=i))}},_updateDatepicker:function(t){this.maxRows=4,v=t,t.dpDiv.empty().append(this._generateHTML(t)),this._attachHandlers(t);var i,s=this._getNumberOfMonths(t),n=s[1],a=17,r=t.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),t.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&t.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),t.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),t.dpDiv[(this._get(t,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),t===e.datepicker._curInst&&e.datepicker._datepickerShowing&&e.datepicker._shouldFocusInput(t)&&t.input.focus(),t.yearshtml&&(i=t.yearshtml,setTimeout(function(){i===t.yearshtml&&t.yearshtml&&t.dpDiv.find("select.ui-datepicker-year:first").replaceWith(t.yearshtml),i=t.yearshtml=null},0))},_shouldFocusInput:function(e){return e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&!e.input.is(":focus")},_checkOffset:function(t,i,s){var n=t.dpDiv.outerWidth(),a=t.dpDiv.outerHeight(),o=t.input?t.input.outerWidth():0,r=t.input?t.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:e(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:e(document).scrollTop());return i.left-=this._get(t,"isRTL")?n-o:0,i.left-=s&&i.left===t.input.offset().left?e(document).scrollLeft():0,i.top-=s&&i.top===t.input.offset().top+r?e(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+r):0),i},_findPos:function(t){for(var i,s=this._getInst(t),n=this._get(s,"isRTL");t&&("hidden"===t.type||1!==t.nodeType||e.expr.filters.hidden(t));)t=t[n?"previousSibling":"nextSibling"];return i=e(t).offset(),[i.left,i.top]},_hideDatepicker:function(t){var i,s,n,a,o=this._curInst;!o||t&&o!==e.data(t,"datepicker")||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){e.datepicker._tidyDialog(o)},e.effects&&(e.effects.effect[i]||e.effects[i])?o.dpDiv.hide(i,e.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),e.blockUI&&(e.unblockUI(),e("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(t){if(e.datepicker._curInst){var i=e(t.target),s=e.datepicker._getInst(i[0]);(i[0].id!==e.datepicker._mainDivId&&0===i.parents("#"+e.datepicker._mainDivId).length&&!i.hasClass(e.datepicker.markerClassName)&&!i.closest("."+e.datepicker._triggerClass).length&&e.datepicker._datepickerShowing&&(!e.datepicker._inDialog||!e.blockUI)||i.hasClass(e.datepicker.markerClassName)&&e.datepicker._curInst!==s)&&e.datepicker._hideDatepicker()}},_adjustDate:function(t,i,s){var n=e(t),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(t){var i,s=e(t),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(t,i,s){var n=e(t),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(t,i,s,n){var a,o=e(t);e(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0])||(a=this._getInst(o[0]),a.selectedDay=a.currentDay=e("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(t,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(t){var i=e(t);this._selectDate(i,"")},_selectDate:function(t,i){var s,n=e(t),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(t){var i,s,n,a=this._get(t,"altField");a&&(i=this._get(t,"altFormat")||this._get(t,"dateFormat"),s=this._getDate(t),n=this.formatDate(i,s,this._getFormatConfig(t)),e(a).each(function(){e(this).val(n)}))},noWeekends:function(e){var t=e.getDay();return[t>0&&6>t,""]},iso8601Week:function(e){var t,i=new Date(e.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),t=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((t-i)/864e5)/7)+1},parseDate:function(t,i,s){if(null==t||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,a,o,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),d=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,c=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,m=-1,g=-1,v=-1,y=-1,b=!1,_=function(e){var i=t.length>n+1&&t.charAt(n+1)===e;return i&&n++,i},x=function(e){var t=_(e),s="@"===e?14:"!"===e?20:"y"===e&&t?4:"o"===e?3:2,n="y"===e?s:1,a=RegExp("^\\d{"+n+","+s+"}"),o=i.substring(h).match(a);if(!o)throw"Missing number at position "+h;return h+=o[0].length,parseInt(o[0],10)},w=function(t,s,n){var a=-1,o=e.map(_(t)?n:s,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)});if(e.each(o,function(e,t){var s=t[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(a=t[0],h+=s.length,!1):void 0}),-1!==a)return a+1;throw"Unknown name at position "+h},k=function(){if(i.charAt(h)!==t.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;t.length>n;n++)if(b)"'"!==t.charAt(n)||_("'")?k():b=!1;else switch(t.charAt(n)){case"d":v=x("d");break;case"D":w("D",d,c);break;case"o":y=x("o");break;case"m":g=x("m");break;case"M":g=w("M",p,f);break;case"y":m=x("y");break;case"@":r=new Date(x("@")),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"!":r=new Date((x("!")-this._ticksTo1970)/1e4),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"'":_("'")?k():b=!0;break;default:k()}if(i.length>h&&(o=i.substr(h),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),y>-1)for(g=1,v=y;;){if(a=this._getDaysInMonth(m,g-1),a>=v)break;g++,v-=a}if(r=this._daylightSavingAdjust(new Date(m,g-1,v)),r.getFullYear()!==m||r.getMonth()+1!==g||r.getDate()!==v)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(e,t,i){if(!t)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,o=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(t){var i=e.length>s+1&&e.charAt(s+1)===t;return i&&s++,i},l=function(e,t,i){var s=""+t;if(h(e))for(;i>s.length;)s="0"+s;return s},u=function(e,t,i,s){return h(e)?s[t]:i[t]},d="",c=!1;if(t)for(s=0;e.length>s;s++)if(c)"'"!==e.charAt(s)||h("'")?d+=e.charAt(s):c=!1;else switch(e.charAt(s)){case"d":d+=l("d",t.getDate(),2);break;case"D":d+=u("D",t.getDay(),n,a);break;case"o":d+=l("o",Math.round((new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()-new Date(t.getFullYear(),0,0).getTime())/864e5),3);break;case"m":d+=l("m",t.getMonth()+1,2);break;case"M":d+=u("M",t.getMonth(),o,r);break;case"y":d+=h("y")?t.getFullYear():(10>t.getYear()%100?"0":"")+t.getYear()%100;break;case"@":d+=t.getTime();break;case"!":d+=1e4*t.getTime()+this._ticksTo1970;break;case"'":h("'")?d+="'":c=!0;break;default:d+=e.charAt(s)}return d},_possibleChars:function(e){var t,i="",s=!1,n=function(i){var s=e.length>t+1&&e.charAt(t+1)===i;return s&&t++,s};for(t=0;e.length>t;t++)if(s)"'"!==e.charAt(t)||n("'")?i+=e.charAt(t):s=!1;else switch(e.charAt(t)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=e.charAt(t)}return i},_get:function(e,t){return void 0!==e.settings[t]?e.settings[t]:this._defaults[t]},_setDateFromField:function(e,t){if(e.input.val()!==e.lastVal){var i=this._get(e,"dateFormat"),s=e.lastVal=e.input?e.input.val():null,n=this._getDefaultDate(e),a=n,o=this._getFormatConfig(e);try{a=this.parseDate(i,s,o)||n}catch(r){s=t?"":s}e.selectedDay=a.getDate(),e.drawMonth=e.selectedMonth=a.getMonth(),e.drawYear=e.selectedYear=a.getFullYear(),e.currentDay=s?a.getDate():0,e.currentMonth=s?a.getMonth():0,e.currentYear=s?a.getFullYear():0,this._adjustInstDate(e)}},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(t,i,s){var n=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},a=function(i){try{return e.datepicker.parseDate(e.datepicker._get(t,"dateFormat"),i,e.datepicker._getFormatConfig(t))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?e.datepicker._getDate(t):null)||new Date,a=n.getFullYear(),o=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":o+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o));break;case"y":case"Y":a+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o))}l=h.exec(i)}return new Date(a,o,r)},o=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return o=o&&"Invalid Date"==""+o?s:o,o&&(o.setHours(0),o.setMinutes(0),o.setSeconds(0),o.setMilliseconds(0)),this._daylightSavingAdjust(o)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,i){var s=!t,n=e.selectedMonth,a=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),n===e.selectedMonth&&a===e.selectedYear||i||this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(s?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&""===e.input.val()?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(t){var i=this._get(t,"stepMonths"),s="#"+t.id.replace(/\\\\/g,"\\");t.dpDiv.find("[data-handler]").map(function(){var t={prev:function(){e.datepicker._adjustDate(s,-i,"M")},next:function(){e.datepicker._adjustDate(s,+i,"M")},hide:function(){e.datepicker._hideDatepicker()},today:function(){e.datepicker._gotoToday(s)},selectDay:function(){return e.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return e.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return e.datepicker._selectMonthYear(s,this,"Y"),!1}};e(this).bind(this.getAttribute("data-event"),t[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t,i,s,n,a,o,r,h,l,u,d,c,p,f,m,g,v,y,b,_,x,w,k,T,D,S,M,C,N,A,P,I,z,H,F,E,O,j,W,L=new Date,R=this._daylightSavingAdjust(new Date(L.getFullYear(),L.getMonth(),L.getDate())),Y=this._get(e,"isRTL"),B=this._get(e,"showButtonPanel"),J=this._get(e,"hideIfNoPrevNext"),q=this._get(e,"navigationAsDateFormat"),K=this._getNumberOfMonths(e),V=this._get(e,"showCurrentAtPos"),U=this._get(e,"stepMonths"),Q=1!==K[0]||1!==K[1],G=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),X=this._getMinMaxDate(e,"min"),$=this._getMinMaxDate(e,"max"),Z=e.drawMonth-V,et=e.drawYear;if(0>Z&&(Z+=12,et--),$)for(t=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-K[0]*K[1]+1,$.getDate())),t=X&&X>t?X:t;this._daylightSavingAdjust(new Date(et,Z,1))>t;)Z--,0>Z&&(Z=11,et--);for(e.drawMonth=Z,e.drawYear=et,i=this._get(e,"prevText"),i=q?this.formatDate(i,this._daylightSavingAdjust(new Date(et,Z-U,1)),this._getFormatConfig(e)):i,s=this._canAdjustMonth(e,-1,et,Z)?""+i+"":J?"":""+i+"",n=this._get(e,"nextText"),n=q?this.formatDate(n,this._daylightSavingAdjust(new Date(et,Z+U,1)),this._getFormatConfig(e)):n,a=this._canAdjustMonth(e,1,et,Z)?""+n+"":J?"":""+n+"",o=this._get(e,"currentText"),r=this._get(e,"gotoCurrent")&&e.currentDay?G:R,o=q?this.formatDate(o,r,this._getFormatConfig(e)):o,h=e.inline?"":"",l=B?"
    "+(Y?h:"")+(this._isInRange(e,r)?"":"")+(Y?"":h)+"
    ":"",u=parseInt(this._get(e,"firstDay"),10),u=isNaN(u)?0:u,d=this._get(e,"showWeek"),c=this._get(e,"dayNames"),p=this._get(e,"dayNamesMin"),f=this._get(e,"monthNames"),m=this._get(e,"monthNamesShort"),g=this._get(e,"beforeShowDay"),v=this._get(e,"showOtherMonths"),y=this._get(e,"selectOtherMonths"),b=this._getDefaultDate(e),_="",w=0;K[0]>w;w++){for(k="",this.maxRows=4,T=0;K[1]>T;T++){if(D=this._daylightSavingAdjust(new Date(et,Z,e.selectedDay)),S=" ui-corner-all",M="",Q){if(M+="
    "}for(M+="
    "+(/all|left/.test(S)&&0===w?Y?a:s:"")+(/all|right/.test(S)&&0===w?Y?s:a:"")+this._generateMonthYearHeader(e,Z,et,X,$,w>0||T>0,f,m)+"
    "+"",C=d?"":"",x=0;7>x;x++)N=(x+u)%7,C+="";for(M+=C+"",A=this._getDaysInMonth(et,Z),et===e.selectedYear&&Z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,A)),P=(this._getFirstDayOfMonth(et,Z)-u+7)%7,I=Math.ceil((P+A)/7),z=Q?this.maxRows>I?this.maxRows:I:I,this.maxRows=z,H=this._daylightSavingAdjust(new Date(et,Z,1-P)),F=0;z>F;F++){for(M+="",E=d?"":"",x=0;7>x;x++)O=g?g.apply(e.input?e.input[0]:null,[H]):[!0,""],j=H.getMonth()!==Z,W=j&&!y||!O[0]||X&&X>H||$&&H>$,E+="",H.setDate(H.getDate()+1),H=this._daylightSavingAdjust(H);M+=E+""}Z++,Z>11&&(Z=0,et++),M+="
    "+this._get(e,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[N]+"
    "+this._get(e,"calculateWeek")(H)+""+(j&&!v?" ":W?""+H.getDate()+"":""+H.getDate()+"")+"
    "+(Q?"
    "+(K[0]>0&&T===K[1]-1?"
    ":""):""),k+=M}_+=k}return _+=l,e._keyEvent=!1,_},_generateMonthYearHeader:function(e,t,i,s,n,a,o,r){var h,l,u,d,c,p,f,m,g=this._get(e,"changeMonth"),v=this._get(e,"changeYear"),y=this._get(e,"showMonthAfterYear"),b="
    ",_="";if(a||!g)_+=""+o[t]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,_+=""}if(y||(b+=_+(!a&&g&&v?"":" ")),!e.yearshtml)if(e.yearshtml="",a||!v)b+=""+i+"";else{for(d=this._get(e,"yearRange").split(":"),c=(new Date).getFullYear(),p=function(e){var t=e.match(/c[+\-].*/)?i+parseInt(e.substring(1),10):e.match(/[+\-].*/)?c+parseInt(e,10):parseInt(e,10);return isNaN(t)?c:t},f=p(d[0]),m=Math.max(f,p(d[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,e.yearshtml+="",b+=e.yearshtml,e.yearshtml=null}return b+=this._get(e,"yearSuffix"),y&&(b+=(!a&&g&&v?"":" ")+_),b+="
    "},_adjustInstDate:function(e,t,i){var s=e.drawYear+("Y"===i?t:0),n=e.drawMonth+("M"===i?t:0),a=Math.min(e.selectedDay,this._getDaysInMonth(s,n))+("D"===i?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(s,n,a)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(e)},_restrictMinMax:function(e,t){var i=this._getMinMaxDate(e,"min"),s=this._getMinMaxDate(e,"max"),n=i&&i>t?i:t;return s&&n>s?s:n},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return null==t?[1,1]:"number"==typeof t?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return new Date(e,t,1).getDay()},_canAdjustMonth:function(e,t,i,s){var n=this._getNumberOfMonths(e),a=this._daylightSavingAdjust(new Date(i,s+(0>t?t:n[0]*n[1]),1));return 0>t&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(e,a)},_isInRange:function(e,t){var i,s,n=this._getMinMaxDate(e,"min"),a=this._getMinMaxDate(e,"max"),o=null,r=null,h=this._get(e,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),o=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(o+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||t.getTime()>=n.getTime())&&(!a||t.getTime()<=a.getTime())&&(!o||t.getFullYear()>=o)&&(!r||r>=t.getFullYear())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,i,s){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var n=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(s,i,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),n,this._getFormatConfig(e))}}),e.fn.datepicker=function(t){if(!this.length)return this;e.datepicker.initialized||(e(document).mousedown(e.datepicker._checkExternalClick),e.datepicker.initialized=!0),0===e("#"+e.datepicker._mainDivId).length&&e("body").append(e.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof t||"isDisabled"!==t&&"getDate"!==t&&"widget"!==t?"option"===t&&2===arguments.length&&"string"==typeof arguments[1]?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof t?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this].concat(i)):e.datepicker._attachDatepicker(this,t)}):e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i))},e.datepicker=new n,e.datepicker.initialized=!1,e.datepicker.uuid=(new Date).getTime(),e.datepicker.version="1.11.2",e.datepicker,e.widget("ui.dialog",{version:"1.11.2",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"Close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var i=e(this).css(t).offset().top;0>i&&e(this).css("top",t.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&e.fn.draggable&&this._makeDraggable(),this.options.resizable&&e.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var t=this.options.appendTo;return t&&(t.jquery||t.nodeType)?e(t):this.document.find(t||"body").eq(0)},_destroy:function(){var e,t=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},disable:e.noop,enable:e.noop,close:function(t){var i,s=this;if(this._isOpen&&this._trigger("beforeClose",t)!==!1){if(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&e(i).blur()}catch(n){}this._hide(this.uiDialog,this.options.hide,function(){s._trigger("close",t)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+e(this).css("z-index")}).get(),a=Math.max.apply(null,n);return a>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",a+1),s=!0),s&&!i&&this._trigger("focus",t),s},open:function(){var t=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var e=this._focusedElement; +e||(e=this.element.find("[autofocus]")),e.length||(e=this.element.find(":tabbable")),e.length||(e=this.uiDialogButtonPane.find(":tabbable")),e.length||(e=this.uiDialogTitlebarClose.filter(":tabbable")),e.length||(e=this.uiDialog),e.eq(0).focus()},_keepFocus:function(t){function i(){var t=this.document[0].activeElement,i=this.uiDialog[0]===t||e.contains(this.uiDialog[0],t);i||this._focusTabbable()}t.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=e("
    ").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(t){if(this.options.closeOnEscape&&!t.isDefaultPrevented()&&t.keyCode&&t.keyCode===e.ui.keyCode.ESCAPE)return t.preventDefault(),this.close(t),void 0;if(t.keyCode===e.ui.keyCode.TAB&&!t.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");t.target!==n[0]&&t.target!==this.uiDialog[0]||t.shiftKey?t.target!==s[0]&&t.target!==this.uiDialog[0]||!t.shiftKey||(this._delay(function(){n.focus()}),t.preventDefault()):(this._delay(function(){s.focus()}),t.preventDefault())}},mousedown:function(e){this._moveToTop(e)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var t;this.uiDialogTitlebar=e("
    ").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(t){e(t.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=e("").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(e){e.preventDefault(),this.close(e)}}),t=e("").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(t),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(e){this.options.title||e.html(" "),e.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=e("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=e("
    ").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var t=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),e.isEmptyObject(i)||e.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),void 0):(e.each(i,function(i,s){var n,a;s=e.isFunction(s)?{click:s,text:i}:s,s=e.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(t.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,e("",s).button(a).appendTo(t.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function t(e){return{position:e.position,offset:e.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){e(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,t(n))},drag:function(e,s){i._trigger("drag",e,t(s))},stop:function(n,a){var o=a.offset.left-i.document.scrollLeft(),r=a.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(o>=0?"+":"")+o+" "+"top"+(r>=0?"+":"")+r,of:i.window},e(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,t(a))}})},_makeResizable:function(){function t(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){e(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,t(n))},resize:function(e,s){i._trigger("resize",e,t(s))},stop:function(n,a){var o=i.uiDialog.offset(),r=o.left-i.document.scrollLeft(),h=o.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},e(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,t(a))}}).css("position",a)},_trackFocus:function(){this._on(this.widget(),{focusin:function(t){this._makeFocusTarget(),this._focusedElement=e(t.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var t=this._trackingInstances(),i=e.inArray(this,t);-1!==i&&t.splice(i,1)},_trackingInstances:function(){var e=this.document.data("ui-dialog-instances");return e||(e=[],this.document.data("ui-dialog-instances",e)),e},_minHeight:function(){var e=this.options;return"auto"===e.height?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(){var e=this.uiDialog.is(":visible");e||this.uiDialog.show(),this.uiDialog.position(this.options.position),e||this.uiDialog.hide()},_setOptions:function(t){var i=this,s=!1,n={};e.each(t,function(e,t){i._setOption(e,t),e in i.sizeRelatedOptions&&(s=!0),e in i.resizableRelatedOptions&&(n[e]=t)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,t){var i,s,n=this.uiDialog;"dialogClass"===e&&n.removeClass(this.options.dialogClass).addClass(t),"disabled"!==e&&(this._super(e,t),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:""+t}),"draggable"===e&&(i=n.is(":data(ui-draggable)"),i&&!t&&n.draggable("destroy"),!i&&t&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(s=n.is(":data(ui-resizable)"),s&&!t&&n.resizable("destroy"),s&&"string"==typeof t&&n.resizable("option","handles",t),s||t===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var e,t,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),e=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),t=Math.max(0,s.minHeight-e),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-e):"none","auto"===s.height?this.element.css({minHeight:t,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-e)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=e(this);return e("
    ").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return e(t.target).closest(".ui-dialog").length?!0:!!e(t.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var t=!0;this._delay(function(){t=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(e){t||this._allowInteraction(e)||(e.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=e("
    ").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var e=this.document.data("ui-dialog-overlays")-1;e?this.document.data("ui-dialog-overlays",e):this.document.unbind("focusin").removeData("ui-dialog-overlays"),this.overlay.remove(),this.overlay=null}}}),e.widget("ui.progressbar",{version:"1.11.2",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=e("
    ").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return void 0===e?this.options.value:(this.options.value=this._constrainedValue(e),this._refreshValue(),void 0)},_constrainedValue:function(e){return void 0===e&&(e=this.options.value),this.indeterminate=e===!1,"number"!=typeof e&&(e=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,e))},_setOptions:function(e){var t=e.value;delete e.value,this._super(e),this.options.value=this._constrainedValue(t),this._refreshValue()},_setOption:function(e,t){"max"===e&&(t=Math.max(this.min,t)),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).toggleClass("ui-corner-right",t===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=e("
    ").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}}),e.widget("ui.selectmenu",{version:"1.11.2",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},i=this.element;return e.each(["min","max","step"],function(e,s){var n=i.attr(s);void 0!==n&&n.length&&(t[s]=n)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e),void 0)},mousewheel:function(e,t){if(t){if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()}},"mousedown .ui-spinner-button":function(t){function i(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(t)!==!1&&this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){return e(t.currentTarget).hasClass("ui-state-active")?this._start(t)===!1?!1:(this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*e.height())&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+"" +},_start:function(e){return this.spinning||this._trigger("start",e)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(e,t,i){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,i)},e),this._spin(t*this.options.step,i)},_spin:function(e,t){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+e*this._increment(this.counter)),this.spinning&&this._trigger("spin",t,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(t){var i=this.options.incremental;return i?e.isFunction(i)?i(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_adjustValue:function(e){var t,i,s=this.options;return t=null!==s.min?s.min:0,i=e-t,i=Math.round(i/s.step)*s.step,e=t+i,e=parseFloat(e.toFixed(this._precision())),null!==s.max&&e>s.max?s.max:null!==s.min&&s.min>e?s.min:e},_stop:function(e){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e))},_setOption:function(e,t){if("culture"===e||"numberFormat"===e){var i=this._parse(this.element.val());return this.options[e]=t,this.element.val(this._format(i)),void 0}("max"===e||"min"===e||"step"===e)&&"string"==typeof t&&(t=this._parse(t)),"icons"===e&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(t.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(t.down)),this._super(e,t),"disabled"===e&&(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable"))},_setOptions:h(function(e){this._super(e)}),_parse:function(e){return"string"==typeof e&&""!==e&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),""===e||isNaN(e)?null:e},_format:function(e){return""===e?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var e=this.value();return null===e?!1:e===this._adjustValue(e)},_value:function(e,t){var i;""!==e&&(i=this._parse(e),null!==i&&(t||(i=this._adjustValue(i)),e=this._format(i))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:h(function(e){this._stepUp(e)}),_stepUp:function(e){this._start()&&(this._spin((e||1)*this.options.step),this._stop())},stepDown:h(function(e){this._stepDown(e)}),_stepDown:function(e){this._start()&&(this._spin((e||1)*-this.options.step),this._stop())},pageUp:h(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:h(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){return arguments.length?(h(this._value).call(this,e),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),e.widget("ui.tabs",{version:"1.11.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var e=/#.*$/;return function(t){var i,s;t=t.cloneNode(!1),i=t.href.replace(e,""),s=location.href.replace(e,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return t.hash.length>1&&i===s}}(),_create:function(){var t=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible),this._processTabs(),i.active=this._initialActive(),e.isArray(i.disabled)&&(i.disabled=e.unique(i.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):e(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var t=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===t&&(s&&this.tabs.each(function(i,n){return e(n).attr("aria-controls")===s?(t=i,!1):void 0}),null===t&&(t=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===t||-1===t)&&(t=this.tabs.length?0:!1)),t!==!1&&(t=this.tabs.index(this.tabs.eq(t)),-1===t&&(t=i?!1:0)),!i&&t===!1&&this.anchors.length&&(t=0),t},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var i=e(this.document[0].activeElement).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(t)){switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:s++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:n=!1,s--;break;case e.ui.keyCode.END:s=this.anchors.length-1;break;case e.ui.keyCode.HOME:s=0;break;case e.ui.keyCode.SPACE:return t.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case e.ui.keyCode.ENTER:return t.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}t.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),t.ctrlKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(t){this._handlePageNav(t)||t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){return t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(t,i){function s(){return t>n&&(t=0),0>t&&(t=n),t}for(var n=this.tabs.length-1;-1!==e.inArray(s(),this.options.disabled);)t=i?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):"disabled"===e?(this._setupDisabled(t),void 0):(this._super(e,t),"collapsible"===e&&(this.element.toggleClass("ui-tabs-collapsible",t),t||this.options.active!==!1||this._activate(0)),"event"===e&&this._setupEvents(t),"heightStyle"===e&&this._setupHeightStyle(t),void 0)},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,i=this.tablist.children(":has(a[href])");t.disabled=e.map(i.filter(".ui-state-disabled"),function(e){return i.index(e)}),this._processTabs(),t.active!==!1&&this.anchors.length?this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=e()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist").delegate("> li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(i,s){var n,a,o,r=e(s).uniqueId().attr("id"),h=e(s).closest("li"),l=h.attr("aria-controls");t._isLocal(s)?(n=s.hash,o=n.substring(1),a=t.element.find(t._sanitizeSelector(n))):(o=h.attr("aria-controls")||e({}).uniqueId()[0].id,n="#"+o,a=t.element.find(n),a.length||(a=t._createPanel(o),a.insertAfter(t.panels[i-1]||t.tablist)),a.attr("aria-live","polite")),a.length&&(t.panels=t.panels.add(a)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":o,"aria-labelledby":r}),a.attr("aria-labelledby",r)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
    ").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var i,s=0;i=this.tabs[s];s++)t===!0||-1!==e.inArray(s,t)?e(i).addClass("ui-state-disabled").attr("aria-disabled","true"):e(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var i={};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(e){e.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,s=this.element.parent();"fill"===t?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=e(this),s=t.css("position");"absolute"!==s&&"fixed"!==s&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,e(this).height("").height())}).height(i))},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?e():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):e(),u={oldTab:s,oldPanel:l,newTab:r?e():a,newPanel:h};t.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",t,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?e():a,this.xhr&&this.xhr.abort(),l.length||h.length||e.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),t),this._toggle(t,u))},_toggle:function(t,i){function s(){a.running=!1,a._trigger("activate",t,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var i,s=this._findActive(t);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tablist.unbind(this.eventNamespace),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),i=t.data("ui-tabs-aria-controls");i?t.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(t){var i=this.options.disabled;i!==!1&&(void 0===t?i=!1:(t=this._getIndex(t),i=e.isArray(i)?e.map(i,function(e){return e!==t?e:null}):e.map(this.tabs,function(e,i){return i!==t?i:null})),this._setupDisabled(i))},disable:function(t){var i=this.options.disabled;if(i!==!0){if(void 0===t)i=!0;else{if(t=this._getIndex(t),-1!==e.inArray(t,i))return;i=e.isArray(i)?e.merge([t],i).sort():[t]}this._setupDisabled(i)}},load:function(t,i){t=this._getIndex(t);var s=this,n=this.tabs.eq(t),a=n.find(".ui-tabs-anchor"),o=this._getPanelForTab(n),r={tab:n,panel:o};this._isLocal(a[0])||(this.xhr=e.ajax(this._ajaxSettings(a,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(n.addClass("ui-tabs-loading"),o.attr("aria-busy","true"),this.xhr.success(function(e){setTimeout(function(){o.html(e),s._trigger("load",i,r)},1)}).complete(function(e,t){setTimeout(function(){"abort"===t&&s.panels.stop(!1,!0),n.removeClass("ui-tabs-loading"),o.removeAttr("aria-busy"),e===s.xhr&&delete s.xhr},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href"),beforeSend:function(t,a){return n._trigger("beforeLoad",i,e.extend({jqXHR:t,ajaxSettings:a},s))}}},_getPanelForTab:function(t){var i=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),e.widget("ui.tooltip",{version:"1.11.2",options:{content:function(){var t=e(this).attr("title")||"";return e("").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_addDescribedBy:function(t,i){var s=(t.attr("aria-describedby")||"").split(/\s+/);s.push(i),t.data("ui-tooltip-id",i).attr("aria-describedby",e.trim(s.join(" ")))},_removeDescribedBy:function(t){var i=t.data("ui-tooltip-id"),s=(t.attr("aria-describedby")||"").split(/\s+/),n=e.inArray(i,s);-1!==n&&s.splice(n,1),t.removeData("ui-tooltip-id"),s=e.trim(s.join(" ")),s?t.attr("aria-describedby",s):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable(),this.liveRegion=e("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body)},_setOption:function(t,i){var s=this;return"disabled"===t?(this[i?"_disable":"_enable"](),this.options[t]=i,void 0):(this._super(t,i),"content"===t&&e.each(this.tooltips,function(e,t){s._updateContent(t.element)}),void 0)},_disable:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur");n.target=n.currentTarget=s.element[0],t.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var i=this,s=e(t?t.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&s.parents().each(function(){var t,s=e(this);s.data("ui-tooltip-open")&&(t=e.Event("blur"),t.target=t.currentTarget=this,i.close(t,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,t))},_updateContent:function(e,t){var i,s=this.options.content,n=this,a=t?t.type:null;return"string"==typeof s?this._open(t,e,s):(i=s.call(e[0],function(i){e.data("ui-tooltip-open")&&n._delay(function(){t&&(t.type=a),this._open(t,e,i)})}),i&&this._open(t,e,i),void 0)},_open:function(t,i,s){function n(e){u.of=e,o.is(":hidden")||o.position(u)}var a,o,r,h,l,u=e.extend({},this.options.position);if(s){if(a=this._find(i))return a.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(t&&"mouseover"===t.type?i.attr("title",""):i.removeAttr("title")),a=this._tooltip(i),o=a.tooltip,this._addDescribedBy(i,o.attr("id")),o.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),s.clone?(l=s.clone(),l.removeAttr("id").find("[id]").removeAttr("id")):l=s,e("
    ").html(l).appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:n}),n(t)):o.position(e.extend({of:i},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){o.is(":visible")&&(n(u.of),clearInterval(h))},e.fx.interval)),this._trigger("open",t,{tooltip:o}),r={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var s=e.Event(t);s.currentTarget=i[0],this.close(s,!0)}}},i[0]!==this.element[0]&&(r.remove=function(){this._removeTooltip(o)}),t&&"mouseover"!==t.type||(r.mouseleave="close"),t&&"focusin"!==t.type||(r.focusout="close"),this._on(!0,i,r)}},close:function(t){var i,s=this,n=e(t?t.currentTarget:this.element),a=this._find(n);a&&(i=a.tooltip,a.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),a.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(e(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&e.each(this.parents,function(t,i){e(i.element).attr("title",i.title),delete s.parents[t]}),a.closing=!0,this._trigger("close",t,{tooltip:i}),a.hiding||(a.closing=!1)))},_tooltip:function(t){var i=e("
    ").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("
    ").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}});var y="ui-effects-",b=e;e.effects={effect:{}},function(e,t){function i(e,t,i){var s=d[t.type]||{};return null==e?i||!t.def?null:t.def:(e=s.floor?~~e:parseFloat(e),isNaN(e)?t.def:s.mod?(e+s.mod)%s.mod:0>e?0:e>s.max?s.max:e)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(e,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[u[l].cache]=o[u[l].cache],n=s._rgba=o._rgba,!1):t}),n.length?("0,0,0,0"===n.join()&&e.extend(n,a.transparent),s):a[i]}function n(e,t,i){return i=(i+1)%1,1>6*i?e+6*(t-e)*i:1>2*i?t:2>3*i?e+6*(t-e)*(2/3-i):e}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],l=e.Color=function(t,i,s,n){return new e.Color.fn.parse(t,i,s,n)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},d={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},c=l.support={},p=e("

    ")[0],f=e.each;p.style.cssText="background-color:rgba(1,1,1,.5)",c.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),l.fn=e.extend(l.prototype,{parse:function(n,o,r,h){if(n===t)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=e(n).css(o),o=t);var d=this,c=e.type(n),p=this._rgba=[];return o!==t&&(n=[n,o,r,h],c="array"),"string"===c?this.parse(s(n)||a._default):"array"===c?(f(u.rgba.props,function(e,t){p[t.idx]=i(n[t.idx],t)}),this):"object"===c?(n instanceof l?f(u,function(e,t){n[t.cache]&&(d[t.cache]=n[t.cache].slice())}):f(u,function(t,s){var a=s.cache;f(s.props,function(e,t){if(!d[a]&&s.to){if("alpha"===e||null==n[e])return;d[a]=s.to(d._rgba)}d[a][t.idx]=i(n[e],t,!0)}),d[a]&&0>e.inArray(null,d[a].slice(0,3))&&(d[a][3]=1,s.from&&(d._rgba=s.from(d[a])))}),this):t},is:function(e){var i=l(e),s=!0,n=this;return f(u,function(e,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(e,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:t})),s}),s},_space:function(){var e=[],t=this;return f(u,function(i,s){t[s.cache]&&e.push(i)}),e.pop()},transition:function(e,t){var s=l(e),n=s._space(),a=u[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(e,n){var a=n.idx,o=r[a],l=s[a],u=d[n.type]||{};null!==l&&(null===o?h[a]=l:(u.mod&&(l-o>u.mod/2?o+=u.mod:o-l>u.mod/2&&(o-=u.mod)),h[a]=i((l-o)*t+o,n)))}),this[n](h)},blend:function(t){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(t)._rgba;return l(e.map(i,function(e,t){return(1-s)*n[t]+s*e}))},toRgbaString:function(){var t="rgba(",i=e.map(this._rgba,function(e,t){return null==e?t>2?1:0:e});return 1===i[3]&&(i.pop(),t="rgb("),t+i.join()+")"},toHslaString:function(){var t="hsla(",i=e.map(this.hsla(),function(e,t){return null==e&&(e=t>2?1:0),t&&3>t&&(e=Math.round(100*e)+"%"),e});return 1===i[3]&&(i.pop(),t="hsl("),t+i.join()+")"},toHexString:function(t){var i=this._rgba.slice(),s=i.pop();return t&&i.push(~~(255*s)),"#"+e.map(i,function(e){return e=(e||0).toString(16),1===e.length?"0"+e:e}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,u.hsla.to=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t,i,s=e[0]/255,n=e[1]/255,a=e[2]/255,o=e[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,u=r+h,d=.5*u;return t=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=d?l/u:l/(2-u),[Math.round(t)%360,i,d,null==o?1:o]},u.hsla.from=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t=e[0]/360,i=e[1],s=e[2],a=e[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,t+1/3)),Math.round(255*n(r,o,t)),Math.round(255*n(r,o,t-1/3)),a]},f(u,function(s,n){var a=n.props,o=n.cache,h=n.to,u=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===t)return this[o].slice();var n,r=e.type(s),d="array"===r||"object"===r?s:arguments,c=this[o].slice();return f(a,function(e,t){var s=d["object"===r?e:t.idx];null==s&&(s=c[t.idx]),c[t.idx]=i(s,t)}),u?(n=l(u(c)),n[o]=c,n):l(c)},f(a,function(t,i){l.fn[t]||(l.fn[t]=function(n){var a,o=e.type(n),h="alpha"===t?this._hsla?"hsla":"rgba":s,l=this[h](),u=l[i.idx];return"undefined"===o?u:("function"===o&&(n=n.call(this,u),o=e.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=u+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(t){var i=t.split(" ");f(i,function(t,i){e.cssHooks[i]={set:function(t,n){var a,o,r="";if("transparent"!==n&&("string"!==e.type(n)||(a=s(n)))){if(n=l(a||n),!c.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?t.parentNode:t;(""===r||"transparent"===r)&&o&&o.style;)try{r=e.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{t.style[i]=n}catch(h){}}},e.fx.step[i]=function(t){t.colorInit||(t.start=l(t.elem,i),t.end=l(t.end),t.colorInit=!0),e.cssHooks[i].set(t.elem,t.start.transition(t.end,t.pos))}})},l.hook(o),e.cssHooks.borderColor={expand:function(e){var t={};return f(["Top","Right","Bottom","Left"],function(i,s){t["border"+s+"Color"]=e}),t}},a=e.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(b),function(){function t(t){var i,s,n=t.ownerDocument.defaultView?t.ownerDocument.defaultView.getComputedStyle(t,null):t.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[e.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function i(t,i){var s,a,o={};for(s in i)a=i[s],t[s]!==a&&(n[s]||(e.fx.step[s]||!isNaN(parseFloat(a)))&&(o[s]=a));return o}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,i){e.fx.step[i]=function(e){("none"!==e.end&&!e.setAttr||1===e.pos&&!e.setAttr)&&(b.style(e.elem,i,e.end),e.setAttr=!0)}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e.effects.animateClass=function(n,a,o,r){var h=e.speed(a,o,r);return this.queue(function(){var a,o=e(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var i=e(this);return{el:i,start:t(this)}}),a=function(){e.each(s,function(e,t){n[t]&&o[t+"Class"](n[t])})},a(),l=l.map(function(){return this.end=t(this.el[0]),this.diff=i(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var t=this,i=e.Deferred(),s=e.extend({},h,{queue:!1,complete:function(){i.resolve(t)}});return this.el.animate(this.diff,s),i.promise()}),e.when.apply(e,l.get()).done(function(){a(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),h.complete.call(o[0])})})},e.fn.extend({addClass:function(t){return function(i,s,n,a){return s?e.effects.animateClass.call(this,{add:i},s,n,a):t.apply(this,arguments)}}(e.fn.addClass),removeClass:function(t){return function(i,s,n,a){return arguments.length>1?e.effects.animateClass.call(this,{remove:i},s,n,a):t.apply(this,arguments)}}(e.fn.removeClass),toggleClass:function(t){return function(i,s,n,a,o){return"boolean"==typeof s||void 0===s?n?e.effects.animateClass.call(this,s?{add:i}:{remove:i},n,a,o):t.apply(this,arguments):e.effects.animateClass.call(this,{toggle:i},s,n,a)}}(e.fn.toggleClass),switchClass:function(t,i,s,n,a){return e.effects.animateClass.call(this,{add:i,remove:t},s,n,a)}})}(),function(){function t(t,i,s,n){return e.isPlainObject(t)&&(i=t,t=t.effect),t={effect:t},null==i&&(i={}),e.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||e.fx.speeds[i])&&(n=s,s=i,i={}),e.isFunction(s)&&(n=s,s=null),i&&e.extend(t,i),s=s||i.duration,t.duration=e.fx.off?0:"number"==typeof s?s:s in e.fx.speeds?e.fx.speeds[s]:e.fx.speeds._default,t.complete=n||i.complete,t}function i(t){return!t||"number"==typeof t||e.fx.speeds[t]?!0:"string"!=typeof t||e.effects.effect[t]?e.isFunction(t)?!0:"object"!=typeof t||t.effect?!1:!0:!0}e.extend(e.effects,{version:"1.11.2",save:function(e,t){for(var i=0;t.length>i;i++)null!==t[i]&&e.data(y+t[i],e[0].style[t[i]])},restore:function(e,t){var i,s;for(s=0;t.length>s;s++)null!==t[s]&&(i=e.data(y+t[s]),void 0===i&&(i=""),e.css(t[s],i))},setMode:function(e,t){return"toggle"===t&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var i,s;switch(e[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=e[0]/t.height}switch(e[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=e[1]/t.width}return{x:s,y:i}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var i={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},s=e("

    ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:t.width(),height:t.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return t.wrap(s),(t[0]===a||e.contains(t[0],a))&&e(a).focus(),s=t.parent(),"static"===t.css("position")?(s.css({position:"relative"}),t.css({position:"relative"})):(e.extend(i,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,s){i[s]=t.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(n),s.css(i).show()},removeWrapper:function(t){var i=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s.mode,a=s.queue,o=e.effects.effect[s.effect];return e.fx.off||!o?n?this[n](s.duration,s.complete):this.each(function(){s.complete&&s.complete.call(this)}):a===!1?this.each(i):this.queue(a||"fx",i)},show:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="show",this.effect.call(this,n)}}(e.fn.show),hide:function(e){return function(s){if(i(s))return e.apply(this,arguments); +var n=t.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(e.fn.hide),toggle:function(e){return function(s){if(i(s)||"boolean"==typeof s)return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(e.fn.toggle),cssUnit:function(t){var i=this.css(t),s=[];return e.each(["em","px","%","pt"],function(e,t){i.indexOf(t)>0&&(s=[parseFloat(i),t])}),s}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,i){t[i]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return 0===e||1===e?e:-Math.pow(2,8*(e-1))*Math.sin((80*(e-1)-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){for(var t,i=4;((t=Math.pow(2,--i))-1)/11>e;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*t-2)/22-e,2)}}),e.each(t,function(t,i){e.easing["easeIn"+t]=i,e.easing["easeOut"+t]=function(e){return 1-i(1-e)},e.easing["easeInOut"+t]=function(e){return.5>e?i(2*e)/2:1-i(-2*e+2)/2}})}(),e.effects,e.effects.effect.blind=function(t,i){var s,n,a,o=e(this),r=/up|down|vertical/,h=/up|left|vertical|horizontal/,l=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(o,t.mode||"hide"),d=t.direction||"up",c=r.test(d),p=c?"height":"width",f=c?"top":"left",m=h.test(d),g={},v="show"===u;o.parent().is(".ui-effects-wrapper")?e.effects.save(o.parent(),l):e.effects.save(o,l),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n=s[p](),a=parseFloat(s.css(f))||0,g[p]=v?n:0,m||(o.css(c?"bottom":"right",0).css(c?"top":"left","auto").css({position:"absolute"}),g[f]=v?a:n+a),v&&(s.css(p,0),m||s.css(f,a+n)),s.animate(g,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){"hide"===u&&o.hide(),e.effects.restore(o,l),e.effects.removeWrapper(o),i()}})},e.effects.effect.bounce=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"effect"),l="hide"===h,u="show"===h,d=t.direction||"up",c=t.distance,p=t.times||5,f=2*p+(u||l?1:0),m=t.duration/f,g=t.easing,v="up"===d||"down"===d?"top":"left",y="up"===d||"left"===d,b=o.queue(),_=b.length;for((u||l)&&r.push("opacity"),e.effects.save(o,r),o.show(),e.effects.createWrapper(o),c||(c=o["top"===v?"outerHeight":"outerWidth"]()/3),u&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,y?2*-c:2*c).animate(a,m,g)),l&&(c/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g).animate(a,m,g),c=l?2*c:c/2;l&&(n={opacity:0},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}),_>1&&b.splice.apply(b,[1,0].concat(b.splice(_,f+1))),o.dequeue()},e.effects.effect.clip=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"hide"),l="show"===h,u=t.direction||"vertical",d="vertical"===u,c=d?"height":"width",p=d?"top":"left",f={};e.effects.save(o,r),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[c](),l&&(n.css(c,0),n.css(p,a/2)),f[c]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){l||o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}})},e.effects.effect.drop=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","opacity","height","width"],o=e.effects.setMode(n,t.mode||"hide"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h?"pos":"neg",d={opacity:r?1:0};e.effects.save(n,a),n.show(),e.effects.createWrapper(n),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===u?-s:s),d[l]=(r?"pos"===u?"+=":"-=":"pos"===u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.explode=function(t,i){function s(){b.push(this),b.length===d*c&&n()}function n(){p.css({visibility:"visible"}),e(b).remove(),m||p.hide(),i()}var a,o,r,h,l,u,d=t.pieces?Math.round(Math.sqrt(t.pieces)):3,c=d,p=e(this),f=e.effects.setMode(p,t.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/c),y=Math.ceil(p.outerHeight()/d),b=[];for(a=0;d>a;a++)for(h=g.top+a*y,u=a-(d-1)/2,o=0;c>o;o++)r=g.left+o*v,l=o-(c-1)/2,p.clone().appendTo("body").wrap("
    ").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*y}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:y,left:r+(m?l*v:0),top:h+(m?u*y:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:u*y),opacity:m?1:0},t.duration||500,t.easing,s)},e.effects.effect.fade=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:t.duration,easing:t.easing,complete:i})},e.effects.effect.fold=function(t,i){var s,n,a=e(this),o=["position","top","bottom","left","right","height","width"],r=e.effects.setMode(a,t.mode||"hide"),h="show"===r,l="hide"===r,u=t.size||15,d=/([0-9]+)%/.exec(u),c=!!t.horizFirst,p=h!==c,f=p?["width","height"]:["height","width"],m=t.duration/2,g={},v={};e.effects.save(a,o),a.show(),s=e.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],d&&(u=parseInt(d[1],10)/100*n[l?0:1]),h&&s.css(c?{height:0,width:u}:{height:u,width:0}),g[f[0]]=h?n[0]:u,v[f[1]]=h?n[1]:0,s.animate(g,m,t.easing).animate(v,m,t.easing,function(){l&&a.hide(),e.effects.restore(a,o),e.effects.removeWrapper(a),i()})},e.effects.effect.highlight=function(t,i){var s=e(this),n=["backgroundImage","backgroundColor","opacity"],a=e.effects.setMode(s,t.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),e.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===a&&s.hide(),e.effects.restore(s,n),i()}})},e.effects.effect.size=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],u=["fontSize"],d=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],c=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),f=t.restore||"effect"!==p,m=t.scale||"both",g=t.origin||["middle","center"],v=o.css("position"),y=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===t.mode&&"show"===p?(o.from=t.to||b,o.to=t.from||s):(o.from=t.from||("show"===p?b:s),o.to=t.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(y=y.concat(d),o.from=e.effects.setTransition(o,d,a.from.y,o.from),o.to=e.effects.setTransition(o,d,a.to.y,o.to)),a.from.x!==a.to.x&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,a.from.x,o.from),o.to=e.effects.setTransition(o,c,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(y=y.concat(u).concat(l),o.from=e.effects.setTransition(o,u,a.from.y,o.from),o.to=e.effects.setTransition(o,u,a.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=e.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(d=d.concat(["marginTop","marginBottom"]).concat(u),c=c.concat(["marginLeft","marginRight"]),l=r.concat(d).concat(c),o.find("*[width]").each(function(){var i=e(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&e.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=e.effects.setTransition(i,d,a.from.y,i.from),i.to=e.effects.setTransition(i,d,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=e.effects.setTransition(i,c,a.from.x,i.from),i.to=e.effects.setTransition(i,c,a.to.x,i.to)),i.css(i.from),i.animate(i.to,t.duration,t.easing,function(){f&&e.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),e.effects.restore(o,y),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,i){var s=parseInt(i,10),n=e?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),e.effects.removeWrapper(o),i()}})},e.effects.effect.scale=function(t,i){var s=e(this),n=e.extend(!0,{},t),a=e.effects.setMode(s,t.mode||"effect"),o=parseInt(t.percent,10)||(0===parseInt(t.percent,10)?0:"hide"===a?0:100),r=t.direction||"both",h=t.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},u={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=t.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*u.y,width:l.width*u.x,outerHeight:l.outerHeight*u.y,outerWidth:l.outerWidth*u.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},e.effects.effect.puff=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"hide"),a="hide"===n,o=parseInt(t.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(t)},e.effects.effect.pulsate=function(t,i){var s,n=e(this),a=e.effects.setMode(n,t.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(t.times||5)+(h?1:0),u=t.duration/l,d=0,c=n.queue(),p=c.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),d=1),s=1;l>s;s++)n.animate({opacity:d},u,t.easing),d=1-d;n.animate({opacity:d},u,t.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&c.splice.apply(c,[1,0].concat(c.splice(p,l+1))),n.dequeue()},e.effects.effect.shake=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","height","width"],o=e.effects.setMode(n,t.mode||"effect"),r=t.direction||"left",h=t.distance||20,l=t.times||3,u=2*l+1,d=Math.round(t.duration/u),c="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),y=v.length;for(e.effects.save(n,a),n.show(),e.effects.createWrapper(n),f[c]=(p?"-=":"+=")+h,m[c]=(p?"+=":"-=")+2*h,g[c]=(p?"-=":"+=")+2*h,n.animate(f,d,t.easing),s=1;l>s;s++)n.animate(m,d,t.easing).animate(g,d,t.easing);n.animate(m,d,t.easing).animate(f,d/2,t.easing).queue(function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}),y>1&&v.splice.apply(v,[1,0].concat(v.splice(y,u+1))),n.dequeue()},e.effects.effect.slide=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","width","height"],o=e.effects.setMode(n,t.mode||"show"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h,d={};e.effects.save(n,a),n.show(),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,u?isNaN(s)?"-"+s:-s:s),d[l]=(r?u?"+=":"-=":u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.transfer=function(t,i){var s=e(this),n=e(t.to),a="fixed"===n.css("position"),o=e("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),u={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},d=s.offset(),c=e("
    ").appendTo(document.body).addClass(t.className).css({top:d.top-r,left:d.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(u,t.duration,t.easing,function(){c.remove(),i()})}}); \ No newline at end of file diff --git a/webdata/mapdata/mcplus/images/conv30.png b/webdata/mapdata/mcplus/images/conv30.png new file mode 100644 index 0000000..a50f61f Binary files /dev/null and b/webdata/mapdata/mcplus/images/conv30.png differ diff --git a/webdata/mapdata/mcplus/images/conv40.png b/webdata/mapdata/mcplus/images/conv40.png new file mode 100644 index 0000000..2fe31a5 Binary files /dev/null and b/webdata/mapdata/mcplus/images/conv40.png differ diff --git a/webdata/mapdata/mcplus/images/conv50.png b/webdata/mapdata/mcplus/images/conv50.png new file mode 100644 index 0000000..cbab98b Binary files /dev/null and b/webdata/mapdata/mcplus/images/conv50.png differ diff --git a/webdata/mapdata/mcplus/images/heart30.png b/webdata/mapdata/mcplus/images/heart30.png new file mode 100644 index 0000000..c6067a7 Binary files /dev/null and b/webdata/mapdata/mcplus/images/heart30.png differ diff --git a/webdata/mapdata/mcplus/images/heart40.png b/webdata/mapdata/mcplus/images/heart40.png new file mode 100644 index 0000000..e79ba0a Binary files /dev/null and b/webdata/mapdata/mcplus/images/heart40.png differ diff --git a/webdata/mapdata/mcplus/images/heart50.png b/webdata/mapdata/mcplus/images/heart50.png new file mode 100644 index 0000000..26c2252 Binary files /dev/null and b/webdata/mapdata/mcplus/images/heart50.png differ diff --git a/webdata/mapdata/mcplus/images/index.html b/webdata/mapdata/mcplus/images/index.html new file mode 100644 index 0000000..f807e5f --- /dev/null +++ b/webdata/mapdata/mcplus/images/index.html @@ -0,0 +1,22 @@ +google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus/images + +

    google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus/images

    +
    +
    Google Code powered by Subversion + \ No newline at end of file diff --git a/webdata/mapdata/mcplus/images/m1.png b/webdata/mapdata/mcplus/images/m1.png new file mode 100644 index 0000000..329ff52 Binary files /dev/null and b/webdata/mapdata/mcplus/images/m1.png differ diff --git a/webdata/mapdata/mcplus/images/m2.png b/webdata/mapdata/mcplus/images/m2.png new file mode 100644 index 0000000..b999cbc Binary files /dev/null and b/webdata/mapdata/mcplus/images/m2.png differ diff --git a/webdata/mapdata/mcplus/images/m3.png b/webdata/mapdata/mcplus/images/m3.png new file mode 100644 index 0000000..9f30b30 Binary files /dev/null and b/webdata/mapdata/mcplus/images/m3.png differ diff --git a/webdata/mapdata/mcplus/images/m4.png b/webdata/mapdata/mcplus/images/m4.png new file mode 100644 index 0000000..0d3f826 Binary files /dev/null and b/webdata/mapdata/mcplus/images/m4.png differ diff --git a/webdata/mapdata/mcplus/images/m5.png b/webdata/mapdata/mcplus/images/m5.png new file mode 100644 index 0000000..61387d2 Binary files /dev/null and b/webdata/mapdata/mcplus/images/m5.png differ diff --git a/webdata/mapdata/mcplus/images/people35.png b/webdata/mapdata/mcplus/images/people35.png new file mode 100644 index 0000000..6a5a209 Binary files /dev/null and b/webdata/mapdata/mcplus/images/people35.png differ diff --git a/webdata/mapdata/mcplus/images/people45.png b/webdata/mapdata/mcplus/images/people45.png new file mode 100644 index 0000000..219c62e Binary files /dev/null and b/webdata/mapdata/mcplus/images/people45.png differ diff --git a/webdata/mapdata/mcplus/images/people55.png b/webdata/mapdata/mcplus/images/people55.png new file mode 100644 index 0000000..6e88d1e Binary files /dev/null and b/webdata/mapdata/mcplus/images/people55.png differ diff --git a/webdata/mapdata/mcplus/index.html b/webdata/mapdata/mcplus/index.html new file mode 100644 index 0000000..3b5fdd1 --- /dev/null +++ b/webdata/mapdata/mcplus/index.html @@ -0,0 +1,12 @@ +google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus + +

    google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus

    + +
    Google Code powered by Subversion + \ No newline at end of file diff --git a/webdata/mapdata/mcplus/src/data.json b/webdata/mapdata/mcplus/src/data.json new file mode 100644 index 0000000..0792c8f --- /dev/null +++ b/webdata/mapdata/mcplus/src/data.json @@ -0,0 +1,2188 @@ +var data = { "count": 10785236, + "photos": [{"photo_id": 27932, "photo_title": "Atardecer en Embalse", "photo_url": "http://www.panoramio.com/photo/27932", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/27932.jpg", "longitude": -64.404945, "latitude": -32.202924, "width": 500, "height": 375, "upload_date": "25 June 2006", "owner_id": 4483, "owner_name": "Miguel Coranti", "owner_url": "http://www.panoramio.com/user/4483"} +, +{"photo_id": 522084, "photo_title": "In Memoriam Antoine de Saint Exupéry", "photo_url": "http://www.panoramio.com/photo/522084", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/522084.jpg", "longitude": 17.470493, "latitude": 47.867077, "width": 500, "height": 350, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1578881, "photo_title": "Rosina Lamberti,Sunset,Templestowe , Victoria, Australia", "photo_url": "http://www.panoramio.com/photo/1578881", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1578881.jpg", "longitude": 145.141754, "latitude": -37.766372, "width": 500, "height": 474, "upload_date": "01 April 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 97671, "photo_title": "kin-dza-dza", "photo_url": "http://www.panoramio.com/photo/97671", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/97671.jpg", "longitude": 30.785408, "latitude": 46.639301, "width": 500, "height": 375, "upload_date": "09 December 2006", "owner_id": 13058, "owner_name": "Kyryl", "owner_url": "http://www.panoramio.com/user/13058"} +, +{"photo_id": 25514, "photo_title": "Arenal", "photo_url": "http://www.panoramio.com/photo/25514", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/25514.jpg", "longitude": -84.693432, "latitude": 10.479372, "width": 500, "height": 375, "upload_date": "17 June 2006", "owner_id": 4112, "owner_name": "Roberto Garcia", "owner_url": "http://www.panoramio.com/user/4112"} +, +{"photo_id": 57823, "photo_title": "Maria Alm", "photo_url": "http://www.panoramio.com/photo/57823", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57823.jpg", "longitude": 12.900009, "latitude": 47.409968, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 532693, "photo_title": "Wheatfield in afternoon light", "photo_url": "http://www.panoramio.com/photo/532693", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532693.jpg", "longitude": 11.272659, "latitude": 59.637472, "width": 500, "height": 333, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 57819, "photo_title": "Burg Hohenwerfen", "photo_url": "http://www.panoramio.com/photo/57819", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57819.jpg", "longitude": 13.189259, "latitude": 47.483221, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 1282387, "photo_title": "Thunderstorm in Martinique", "photo_url": "http://www.panoramio.com/photo/1282387", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1282387.jpg", "longitude": -61.013432, "latitude": 14.493688, "width": 500, "height": 400, "upload_date": "12 March 2007", "owner_id": 49870, "owner_name": "Jean-Michel Raggioli", "owner_url": "http://www.panoramio.com/user/49870"} +, +{"photo_id": 945976, "photo_title": "Al tard", "photo_url": "http://www.panoramio.com/photo/945976", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/945976.jpg", "longitude": 0.490866, "latitude": 40.903783, "width": 335, "height": 500, "upload_date": "21 February 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 73514, "photo_title": "Hintersee bei Ramsau", "photo_url": "http://www.panoramio.com/photo/73514", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/73514.jpg", "longitude": 12.852459, "latitude": 47.609519, "width": 500, "height": 333, "upload_date": "30 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 298967, "photo_title": "Antelope Canyon, Ray of Light", "photo_url": "http://www.panoramio.com/photo/298967", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/298967.jpg", "longitude": -111.407890, "latitude": 36.894037, "width": 500, "height": 375, "upload_date": "04 January 2007", "owner_id": 64388, "owner_name": "Artusi", "owner_url": "http://www.panoramio.com/user/64388"} +, +{"photo_id": 88151, "photo_title": "Val Verzasca - Switzerland", "photo_url": "http://www.panoramio.com/photo/88151", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/88151.jpg", "longitude": 8.838158, "latitude": 46.257746, "width": 500, "height": 375, "upload_date": "28 November 2006", "owner_id": 11098, "owner_name": "Michele Masnata", "owner_url": "http://www.panoramio.com/user/11098"} +, +{"photo_id": 6463, "photo_title": "Guggenheim and spider", "photo_url": "http://www.panoramio.com/photo/6463", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6463.jpg", "longitude": -2.933736, "latitude": 43.269159, "width": 500, "height": 375, "upload_date": "09 January 2006", "owner_id": 414, "owner_name": "Sonia Villegas", "owner_url": "http://www.panoramio.com/user/414"} +, +{"photo_id": 107980, "photo_title": "Mostar", "photo_url": "http://www.panoramio.com/photo/107980", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/107980.jpg", "longitude": 17.815200, "latitude": 43.337255, "width": 369, "height": 500, "upload_date": "10 December 2006", "owner_id": 12954, "owner_name": "ZiÄ™bol", "owner_url": "http://www.panoramio.com/user/12954"} +, +{"photo_id": 9439, "photo_title": "Bora Bora", "photo_url": "http://www.panoramio.com/photo/9439", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9439.jpg", "longitude": -151.750000, "latitude": -16.500000, "width": 500, "height": 375, "upload_date": "02 February 2006", "owner_id": 1600, "owner_name": "heavenearth", "owner_url": "http://www.panoramio.com/user/1600"} +, +{"photo_id": 673131, "photo_title": "Nivane in Ørsta", "photo_url": "http://www.panoramio.com/photo/673131", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/673131.jpg", "longitude": 6.108742, "latitude": 62.226676, "width": 500, "height": 334, "upload_date": "03 February 2007", "owner_id": 56091, "owner_name": "Kjetil Vaage Øie", "owner_url": "http://www.panoramio.com/user/56091"} +, +{"photo_id": 346269, "photo_title": "italy-toscany", "photo_url": "http://www.panoramio.com/photo/346269", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/346269.jpg", "longitude": 11.616282, "latitude": 43.064389, "width": 500, "height": 334, "upload_date": "08 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 290039, "photo_title": "Gentoo Penguins at Sunrise", "photo_url": "http://www.panoramio.com/photo/290039", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/290039.jpg", "longitude": -59.070311, "latitude": -52.430295, "width": 500, "height": 284, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 1870141, "photo_title": "Les Mines", "photo_url": "http://www.panoramio.com/photo/1870141", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1870141.jpg", "longitude": 1.314712, "latitude": 45.922199, "width": 500, "height": 379, "upload_date": "21 April 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 516809, "photo_title": "Az Å‘rszem", "photo_url": "http://www.panoramio.com/photo/516809", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/516809.jpg", "longitude": 18.239279, "latitude": 47.535341, "width": 500, "height": 286, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 67347, "photo_title": "Amanecer en el Salar de Uyuni", "photo_url": "http://www.panoramio.com/photo/67347", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/67347.jpg", "longitude": -67.549438, "latitude": -20.552438, "width": 500, "height": 375, "upload_date": "20 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 405822, "photo_title": "tulip", "photo_url": "http://www.panoramio.com/photo/405822", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405822.jpg", "longitude": 139.011619, "latitude": 37.871500, "width": 500, "height": 386, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 233619, "photo_title": "Warsaw Bridge 01 [www.wierzchon.com]", "photo_url": "http://www.panoramio.com/photo/233619", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/233619.jpg", "longitude": 21.035728, "latitude": 52.242353, "width": 500, "height": 500, "upload_date": "25 December 2006", "owner_id": 47836, "owner_name": "Andrzej Wierzchon", "owner_url": "http://www.panoramio.com/user/47836"} +, +{"photo_id": 1516726, "photo_title": "Облако над вулканом Камень. www.photo-sturm.ru", "photo_url": "http://www.panoramio.com/photo/1516726", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1516726.jpg", "longitude": 160.587502, "latitude": 56.081999, "width": 414, "height": 500, "upload_date": "27 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 70975, "photo_title": "Hospiz", "photo_url": "http://www.panoramio.com/photo/70975", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/70975.jpg", "longitude": 8.024461, "latitude": 46.245801, "width": 500, "height": 500, "upload_date": "26 October 2006", "owner_id": 9379, "owner_name": "Davide Bernacchi", "owner_url": "http://www.panoramio.com/user/9379"} +, +{"photo_id": 882660, "photo_title": "icy_chains_1_hdr_web", "photo_url": "http://www.panoramio.com/photo/882660", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/882660.jpg", "longitude": -79.798197, "latitude": 43.321353, "width": 500, "height": 333, "upload_date": "18 February 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 9363990, "photo_title": "Marble Cave", "photo_url": "http://www.panoramio.com/photo/9363990", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9363990.jpg", "longitude": -72.607527, "latitude": -46.647138, "width": 500, "height": 375, "upload_date": "14 April 2008", "owner_id": 947917, "owner_name": "Dejah", "owner_url": "http://www.panoramio.com/user/947917"} +, +{"photo_id": 1884507, "photo_title": "fukushimagata", "photo_url": "http://www.panoramio.com/photo/1884507", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1884507.jpg", "longitude": 139.243813, "latitude": 37.909669, "width": 500, "height": 384, "upload_date": "22 April 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1343502, "photo_title": "вулкан КарымÑкий", "photo_url": "http://www.panoramio.com/photo/1343502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1343502.jpg", "longitude": 159.480114, "latitude": 54.025419, "width": 500, "height": 334, "upload_date": "16 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 97723, "photo_title": "Torrent de pareis", "photo_url": "http://www.panoramio.com/photo/97723", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/97723.jpg", "longitude": 2.805762, "latitude": 39.852352, "width": 401, "height": 500, "upload_date": "09 December 2006", "owner_id": 13121, "owner_name": "Andreas G.M.", "owner_url": "http://www.panoramio.com/user/13121"} +, +{"photo_id": 537672, "photo_title": "Sr. da Pedra", "photo_url": "http://www.panoramio.com/photo/537672", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/537672.jpg", "longitude": -8.659008, "latitude": 41.068821, "width": 500, "height": 366, "upload_date": "23 January 2007", "owner_id": 115618, "owner_name": "Paulo J Moreira", "owner_url": "http://www.panoramio.com/user/115618"} +, +{"photo_id": 204924, "photo_title": "zaldiak", "photo_url": "http://www.panoramio.com/photo/204924", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/204924.jpg", "longitude": -1.806951, "latitude": 43.245140, "width": 500, "height": 346, "upload_date": "21 December 2006", "owner_id": 2575, "owner_name": "mikel ortega", "owner_url": "http://www.panoramio.com/user/2575"} +, +{"photo_id": 114795, "photo_title": "TIBAUM-BIZZAR", "photo_url": "http://www.panoramio.com/photo/114795", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/114795.jpg", "longitude": 7.706180, "latitude": 51.665741, "width": 334, "height": 500, "upload_date": "11 December 2006", "owner_id": 13121, "owner_name": "Andreas G.M.", "owner_url": "http://www.panoramio.com/user/13121"} +, +{"photo_id": 1287881, "photo_title": "Aurora borealis", "photo_url": "http://www.panoramio.com/photo/1287881", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1287881.jpg", "longitude": 44.215508, "latitude": 65.829148, "width": 500, "height": 205, "upload_date": "12 March 2007", "owner_id": 75359, "owner_name": "Andrey Larin", "owner_url": "http://www.panoramio.com/user/75359"} +, +{"photo_id": 1781717, "photo_title": "Water Cuts Rock", "photo_url": "http://www.panoramio.com/photo/1781717", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781717.jpg", "longitude": -113.047771, "latitude": 37.312154, "width": 333, "height": 500, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 196103, "photo_title": "albufera", "photo_url": "http://www.panoramio.com/photo/196103", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196103.jpg", "longitude": -0.323882, "latitude": 39.349166, "width": 332, "height": 500, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 266224, "photo_title": "Boulzojavri", "photo_url": "http://www.panoramio.com/photo/266224", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/266224.jpg", "longitude": 24.373169, "latitude": 68.908534, "width": 500, "height": 334, "upload_date": "30 December 2006", "owner_id": 56091, "owner_name": "Kjetil Vaage Øie", "owner_url": "http://www.panoramio.com/user/56091"} +, +{"photo_id": 6126294, "photo_title": "Richmond Deer", "photo_url": "http://www.panoramio.com/photo/6126294", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126294.jpg", "longitude": -0.275195, "latitude": 51.445890, "width": 489, "height": 500, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 168032, "photo_title": "Buci Seine - Looking Up", "photo_url": "http://www.panoramio.com/photo/168032", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/168032.jpg", "longitude": 2.336990, "latitude": 48.853891, "width": 500, "height": 357, "upload_date": "16 December 2006", "owner_id": 5684, "owner_name": "Brent Townshend", "owner_url": "http://www.panoramio.com/user/5684"} +, +{"photo_id": 1370932, "photo_title": "Mercury Bay Sunrise", "photo_url": "http://www.panoramio.com/photo/1370932", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1370932.jpg", "longitude": 175.699196, "latitude": -36.817685, "width": 500, "height": 470, "upload_date": "17 March 2007", "owner_id": 286729, "owner_name": "jimwitkowski", "owner_url": "http://www.panoramio.com/user/286729"} +, +{"photo_id": 120844, "photo_title": "Adelie-Prat- Kratzmaier", "photo_url": "http://www.panoramio.com/photo/120844", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/120844.jpg", "longitude": -59.683228, "latitude": -62.485684, "width": 500, "height": 351, "upload_date": "12 December 2006", "owner_id": 19856, "owner_name": "Juan Kratzmaier", "owner_url": "http://www.panoramio.com/user/19856"} +, +{"photo_id": 940294, "photo_title": "Infrared Mediterranean Heat", "photo_url": "http://www.panoramio.com/photo/940294", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/940294.jpg", "longitude": 25.376015, "latitude": 36.461537, "width": 500, "height": 332, "upload_date": "21 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 4446084, "photo_title": "Vizivarázs", "photo_url": "http://www.panoramio.com/photo/4446084", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4446084.jpg", "longitude": 17.504482, "latitude": 47.842773, "width": 367, "height": 500, "upload_date": "06 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 498352, "photo_title": "Wave", "photo_url": "http://www.panoramio.com/photo/498352", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/498352.jpg", "longitude": -112.005315, "latitude": 36.995972, "width": 500, "height": 333, "upload_date": "20 January 2007", "owner_id": 40260, "owner_name": "Don Albonico", "owner_url": "http://www.panoramio.com/user/40260"} +, +{"photo_id": 775893, "photo_title": "Leoparden", "photo_url": "http://www.panoramio.com/photo/775893", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/775893.jpg", "longitude": 36.046829, "latitude": -3.818353, "width": 500, "height": 336, "upload_date": "11 February 2007", "owner_id": 164434, "owner_name": "Achim Mittler", "owner_url": "http://www.panoramio.com/user/164434"} +, +{"photo_id": 665502, "photo_title": "Sunset Beach Walker", "photo_url": "http://www.panoramio.com/photo/665502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/665502.jpg", "longitude": -124.077530, "latitude": 44.519888, "width": 500, "height": 340, "upload_date": "03 February 2007", "owner_id": 107359, "owner_name": "Ron Cooper", "owner_url": "http://www.panoramio.com/user/107359"} +, +{"photo_id": 9021415, "photo_title": "Wat Suwan Kuha or Wat Tham, Phang Nga, Winner Unusual Location April 2008", "photo_url": "http://www.panoramio.com/photo/9021415", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9021415.jpg", "longitude": 98.471628, "latitude": 8.428840, "width": 500, "height": 334, "upload_date": "31 March 2008", "owner_id": 1077251, "owner_name": "picsonthemove", "owner_url": "http://www.panoramio.com/user/1077251"} +, +{"photo_id": 287244, "photo_title": "Landwasser-Viadukt - This is an unofficial photo point. Just follow the footpath up from the official one, until the clearing.", "photo_url": "http://www.panoramio.com/photo/287244", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/287244.jpg", "longitude": 9.675007, "latitude": 46.681229, "width": 337, "height": 500, "upload_date": "03 January 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 677366, "photo_title": "Oak tree in winter", "photo_url": "http://www.panoramio.com/photo/677366", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/677366.jpg", "longitude": 10.771065, "latitude": 59.663926, "width": 358, "height": 500, "upload_date": "03 February 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 196086, "photo_title": "albufera", "photo_url": "http://www.panoramio.com/photo/196086", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196086.jpg", "longitude": -0.323882, "latitude": 39.349166, "width": 500, "height": 332, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 4340931, "photo_title": "Cold morning", "photo_url": "http://www.panoramio.com/photo/4340931", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4340931.jpg", "longitude": 12.113349, "latitude": 49.342559, "width": 500, "height": 333, "upload_date": "31 August 2007", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 488, "photo_title": "Lagos de Montebello, México", "photo_url": "http://www.panoramio.com/photo/488", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/488.jpg", "longitude": -91.677904, "latitude": 16.111297, "width": 500, "height": 345, "upload_date": "31 August 2005", "owner_id": 7, "owner_name": "Eduardo Manchón", "owner_url": "http://www.panoramio.com/user/7"} +, +{"photo_id": 723666, "photo_title": "Majestically Still", "photo_url": "http://www.panoramio.com/photo/723666", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723666.jpg", "longitude": -116.175613, "latitude": 51.327608, "width": 500, "height": 332, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1081710, "photo_title": "Gjevilvatnet lake in Oppdal", "photo_url": "http://www.panoramio.com/photo/1081710", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1081710.jpg", "longitude": 9.412537, "latitude": 62.686749, "width": 500, "height": 333, "upload_date": "28 February 2007", "owner_id": 223406, "owner_name": "Sigmund Rise", "owner_url": "http://www.panoramio.com/user/223406"} +, +{"photo_id": 22575, "photo_title": "Lijiang River, near Yangshuo, China", "photo_url": "http://www.panoramio.com/photo/22575", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/22575.jpg", "longitude": 110.454826, "latitude": 24.962716, "width": 500, "height": 333, "upload_date": "05 June 2006", "owner_id": 3557, "owner_name": "Placebo", "owner_url": "http://www.panoramio.com/user/3557"} +, +{"photo_id": 2735754, "photo_title": "Después de la lluvia", "photo_url": "http://www.panoramio.com/photo/2735754", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2735754.jpg", "longitude": -73.241998, "latitude": -39.809583, "width": 360, "height": 500, "upload_date": "13 June 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 73515, "photo_title": "Kloster Höglwörth", "photo_url": "http://www.panoramio.com/photo/73515", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/73515.jpg", "longitude": 12.850227, "latitude": 47.815575, "width": 500, "height": 333, "upload_date": "30 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 723015, "photo_title": "Cape Flattery (infrared)", "photo_url": "http://www.panoramio.com/photo/723015", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723015.jpg", "longitude": -124.726700, "latitude": 48.385898, "width": 500, "height": 332, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1288595, "photo_title": "O'Keeffe ?", "photo_url": "http://www.panoramio.com/photo/1288595", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1288595.jpg", "longitude": 72.920637, "latitude": 4.038162, "width": 332, "height": 500, "upload_date": "12 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 1008304, "photo_title": "nyhavn", "photo_url": "http://www.panoramio.com/photo/1008304", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1008304.jpg", "longitude": 12.591190, "latitude": 55.679762, "width": 500, "height": 333, "upload_date": "24 February 2007", "owner_id": 2659, "owner_name": "ozalph", "owner_url": "http://www.panoramio.com/user/2659"} +, +{"photo_id": 19547, "photo_title": "Embarcador 1", "photo_url": "http://www.panoramio.com/photo/19547", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/19547.jpg", "longitude": 0.493140, "latitude": 40.904172, "width": 500, "height": 335, "upload_date": "07 May 2006", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 98115, "photo_title": "FREE-SPIRIT", "photo_url": "http://www.panoramio.com/photo/98115", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/98115.jpg", "longitude": 9.908917, "latitude": 50.487112, "width": 500, "height": 304, "upload_date": "10 December 2006", "owner_id": 13121, "owner_name": "Andreas G.M.", "owner_url": "http://www.panoramio.com/user/13121"} +, +{"photo_id": 9822056, "photo_title": "Reflection under the Bridge", "photo_url": "http://www.panoramio.com/photo/9822056", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9822056.jpg", "longitude": 103.853851, "latitude": 1.286973, "width": 333, "height": 500, "upload_date": "01 May 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 9117094, "photo_title": "Baron's Haugh, Scotland", "photo_url": "http://www.panoramio.com/photo/9117094", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9117094.jpg", "longitude": -3.986835, "latitude": 55.773532, "width": 500, "height": 337, "upload_date": "05 April 2008", "owner_id": 165346, "owner_name": "Alan Knox", "owner_url": "http://www.panoramio.com/user/165346"} +, +{"photo_id": 5342534, "photo_title": "Åszi pompa", "photo_url": "http://www.panoramio.com/photo/5342534", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5342534.jpg", "longitude": 15.964594, "latitude": 47.875426, "width": 500, "height": 334, "upload_date": "16 October 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2346129, "photo_title": "Pipacsálom", "photo_url": "http://www.panoramio.com/photo/2346129", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2346129.jpg", "longitude": 17.521820, "latitude": 47.748558, "width": 500, "height": 378, "upload_date": "22 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3749005, "photo_title": "Once in a Blue Moon....", "photo_url": "http://www.panoramio.com/photo/3749005", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3749005.jpg", "longitude": -105.654080, "latitude": 40.294560, "width": 374, "height": 500, "upload_date": "05 August 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 1360629, "photo_title": "Frente a la Cascada de Gujuli -103 m.-", "photo_url": "http://www.panoramio.com/photo/1360629", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1360629.jpg", "longitude": -2.909800, "latitude": 42.976199, "width": 333, "height": 500, "upload_date": "17 March 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 6129915, "photo_title": "A vadon szava", "photo_url": "http://www.panoramio.com/photo/6129915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6129915.jpg", "longitude": 17.521133, "latitude": 47.854408, "width": 500, "height": 325, "upload_date": "25 November 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 67183, "photo_title": "Laguna verde e Vulcano Licancabur", "photo_url": "http://www.panoramio.com/photo/67183", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/67183.jpg", "longitude": -67.819161, "latitude": -22.787696, "width": 500, "height": 370, "upload_date": "20 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 507571, "photo_title": "Mikor a harangszó is szebben hallik", "photo_url": "http://www.panoramio.com/photo/507571", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507571.jpg", "longitude": 17.684383, "latitude": 47.587873, "width": 396, "height": 500, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6685422, "photo_title": "Dawn at Bagan, Myanmar (Burma)", "photo_url": "http://www.panoramio.com/photo/6685422", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6685422.jpg", "longitude": 94.860935, "latitude": 21.169045, "width": 500, "height": 333, "upload_date": "25 December 2007", "owner_id": 1221287, "owner_name": "TS Jeung", "owner_url": "http://www.panoramio.com/user/1221287"} +, +{"photo_id": 3513121, "photo_title": "Báláim", "photo_url": "http://www.panoramio.com/photo/3513121", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3513121.jpg", "longitude": 17.481651, "latitude": 47.457576, "width": 419, "height": 500, "upload_date": "24 July 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 10574161, "photo_title": "Silhouette", "photo_url": "http://www.panoramio.com/photo/10574161", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10574161.jpg", "longitude": 148.662905, "latitude": -35.304724, "width": 500, "height": 346, "upload_date": "25 May 2008", "owner_id": 766550, "owner_name": "VFedele", "owner_url": "http://www.panoramio.com/user/766550"} +, +{"photo_id": 89190, "photo_title": "Mount Ararat, Yerevan, Armenia", "photo_url": "http://www.panoramio.com/photo/89190", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/89190.jpg", "longitude": 44.483900, "latitude": 40.195299, "width": 500, "height": 375, "upload_date": "30 November 2006", "owner_id": 11226, "owner_name": "Ardani", "owner_url": "http://www.panoramio.com/user/11226"} +, +{"photo_id": 1182305, "photo_title": "Dobel, Albrecht-Hütte", "photo_url": "http://www.panoramio.com/photo/1182305", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1182305.jpg", "longitude": 8.500500, "latitude": 48.793465, "width": 500, "height": 375, "upload_date": "05 March 2007", "owner_id": 66229, "owner_name": "Mast", "owner_url": "http://www.panoramio.com/user/66229"} +, +{"photo_id": 4258015, "photo_title": "Fényözön", "photo_url": "http://www.panoramio.com/photo/4258015", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4258015.jpg", "longitude": 16.391602, "latitude": 46.851269, "width": 333, "height": 500, "upload_date": "28 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1413, "photo_title": "Champlain Lookout", "photo_url": "http://www.panoramio.com/photo/1413", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1413.jpg", "longitude": -75.912872, "latitude": 45.507640, "width": 500, "height": 375, "upload_date": "06 October 2005", "owner_id": 273, "owner_name": "JC", "owner_url": "http://www.panoramio.com/user/273"} +, +{"photo_id": 1526763, "photo_title": "Gizeh Pyramids, Cairo", "photo_url": "http://www.panoramio.com/photo/1526763", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1526763.jpg", "longitude": 31.133537, "latitude": 29.966721, "width": 500, "height": 333, "upload_date": "27 March 2007", "owner_id": 59919, "owner_name": "xflo:w (http://www.xflo.net)", "owner_url": "http://www.panoramio.com/user/59919"} +, +{"photo_id": 8802900, "photo_title": "Martigues, miroir aux oiseaux", "photo_url": "http://www.panoramio.com/photo/8802900", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8802900.jpg", "longitude": 5.054559, "latitude": 43.405079, "width": 387, "height": 500, "upload_date": "24 March 2008", "owner_id": 629243, "owner_name": "Olivier Faugeras", "owner_url": "http://www.panoramio.com/user/629243"} +, +{"photo_id": 459515, "photo_title": "fire works", "photo_url": "http://www.panoramio.com/photo/459515", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459515.jpg", "longitude": 138.423271, "latitude": 38.069312, "width": 500, "height": 385, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 749464, "photo_title": "Gondola", "photo_url": "http://www.panoramio.com/photo/749464", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/749464.jpg", "longitude": 12.336917, "latitude": 45.434053, "width": 500, "height": 332, "upload_date": "09 February 2007", "owner_id": 159455, "owner_name": "©Franco Truscello", "owner_url": "http://www.panoramio.com/user/159455"} +, +{"photo_id": 422608, "photo_title": "tanada", "photo_url": "http://www.panoramio.com/photo/422608", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/422608.jpg", "longitude": 139.047089, "latitude": 37.449787, "width": 383, "height": 500, "upload_date": "14 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 85617, "photo_title": "Parque Natural de Calblanque", "photo_url": "http://www.panoramio.com/photo/85617", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/85617.jpg", "longitude": -0.739861, "latitude": 37.594104, "width": 332, "height": 500, "upload_date": "24 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 1089235, "photo_title": "NyáridézÅ‘", "photo_url": "http://www.panoramio.com/photo/1089235", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1089235.jpg", "longitude": 18.207092, "latitude": 47.318578, "width": 500, "height": 282, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 505229, "photo_title": "Etangs près de Dijon", "photo_url": "http://www.panoramio.com/photo/505229", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/505229.jpg", "longitude": 5.168552, "latitude": 47.312642, "width": 350, "height": 500, "upload_date": "20 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 679343, "photo_title": "melbourne sunset over the yarra river", "photo_url": "http://www.panoramio.com/photo/679343", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/679343.jpg", "longitude": 144.968119, "latitude": -37.819616, "width": 500, "height": 500, "upload_date": "04 February 2007", "owner_id": 146092, "owner_name": "sid1662", "owner_url": "http://www.panoramio.com/user/146092"} +, +{"photo_id": 436336, "photo_title": "myoujyousan", "photo_url": "http://www.panoramio.com/photo/436336", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436336.jpg", "longitude": 137.831554, "latitude": 36.911608, "width": 500, "height": 362, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 9733680, "photo_title": "Sydney", "photo_url": "http://www.panoramio.com/photo/9733680", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9733680.jpg", "longitude": 151.209834, "latitude": -33.848588, "width": 333, "height": 500, "upload_date": "28 April 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 7415625, "photo_title": "Në fushë të Pallaticesë", "photo_url": "http://www.panoramio.com/photo/7415625", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7415625.jpg", "longitude": 21.077271, "latitude": 42.011550, "width": 437, "height": 500, "upload_date": "28 January 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 5358174, "photo_title": "Morning Glory", "photo_url": "http://www.panoramio.com/photo/5358174", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5358174.jpg", "longitude": -110.843537, "latitude": 44.475020, "width": 500, "height": 348, "upload_date": "16 October 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 316199, "photo_title": "A lake on Gasherbrum glacier", "photo_url": "http://www.panoramio.com/photo/316199", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/316199.jpg", "longitude": 76.732550, "latitude": 35.877298, "width": 500, "height": 375, "upload_date": "06 January 2007", "owner_id": 65672, "owner_name": "www.turclubmai.ru", "owner_url": "http://www.panoramio.com/user/65672"} +, +{"photo_id": 400536, "photo_title": "Half Dome Mtn, Yosemite Nat Park, CA", "photo_url": "http://www.panoramio.com/photo/400536", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/400536.jpg", "longitude": -119.495888, "latitude": 37.811411, "width": 500, "height": 333, "upload_date": "12 January 2007", "owner_id": 85489, "owner_name": "Bruce MacIver", "owner_url": "http://www.panoramio.com/user/85489"} +, +{"photo_id": 2942693, "photo_title": "Tulips and Windmills", "photo_url": "http://www.panoramio.com/photo/2942693", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2942693.jpg", "longitude": 4.864798, "latitude": 52.594393, "width": 500, "height": 500, "upload_date": "25 June 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 9733633, "photo_title": "Oper-Sydney", "photo_url": "http://www.panoramio.com/photo/9733633", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9733633.jpg", "longitude": 151.216968, "latitude": -33.851702, "width": 500, "height": 333, "upload_date": "28 April 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 1800454, "photo_title": "Bombay Beach, Salton Sea, CA", "photo_url": "http://www.panoramio.com/photo/1800454", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1800454.jpg", "longitude": -115.729235, "latitude": 33.347316, "width": 500, "height": 407, "upload_date": "16 April 2007", "owner_id": 107613, "owner_name": "Tom Grubbe", "owner_url": "http://www.panoramio.com/user/107613"} +, +{"photo_id": 2558057, "photo_title": "Kin-dza-dza 2", "photo_url": "http://www.panoramio.com/photo/2558057", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2558057.jpg", "longitude": 30.785751, "latitude": 46.639301, "width": 500, "height": 375, "upload_date": "03 June 2007", "owner_id": 13058, "owner_name": "Kyryl", "owner_url": "http://www.panoramio.com/user/13058"} +, +{"photo_id": 7768089, "photo_title": "Isteni színjáték", "photo_url": "http://www.panoramio.com/photo/7768089", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7768089.jpg", "longitude": 17.507057, "latitude": 47.776425, "width": 500, "height": 334, "upload_date": "12 February 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1213006, "photo_title": "Twilight Drive", "photo_url": "http://www.panoramio.com/photo/1213006", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1213006.jpg", "longitude": -114.481916, "latitude": 51.095841, "width": 500, "height": 335, "upload_date": "07 March 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 395800, "photo_title": "Pic de Bure depuis le Pic de Gleize", "photo_url": "http://www.panoramio.com/photo/395800", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/395800.jpg", "longitude": 6.055870, "latitude": 44.610146, "width": 500, "height": 350, "upload_date": "12 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 11073609, "photo_title": "Sunrise in Koroni, by Kostas Andreopoulos", "photo_url": "http://www.panoramio.com/photo/11073609", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11073609.jpg", "longitude": 21.952747, "latitude": 36.797775, "width": 500, "height": 375, "upload_date": "09 June 2008", "owner_id": 1690483, "owner_name": "k.andre", "owner_url": "http://www.panoramio.com/user/1690483"} +, +{"photo_id": 6564418, "photo_title": "Baron's Haugh, Scotland", "photo_url": "http://www.panoramio.com/photo/6564418", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6564418.jpg", "longitude": -3.989239, "latitude": 55.772808, "width": 500, "height": 337, "upload_date": "19 December 2007", "owner_id": 165346, "owner_name": "Alan Knox", "owner_url": "http://www.panoramio.com/user/165346"} +, +{"photo_id": 10158925, "photo_title": "Lluvia púrpura ( Purple rain )", "photo_url": "http://www.panoramio.com/photo/10158925", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10158925.jpg", "longitude": -0.476360, "latitude": 39.612565, "width": 500, "height": 333, "upload_date": "12 May 2008", "owner_id": 787217, "owner_name": "♣ Víctor S de Lara ♣", "owner_url": "http://www.panoramio.com/user/787217"} +, +{"photo_id": 121574, "photo_title": "Moscú/Moscow - Catedral de San Basilio", "photo_url": "http://www.panoramio.com/photo/121574", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/121574.jpg", "longitude": 37.621951, "latitude": 55.753033, "width": 500, "height": 375, "upload_date": "12 December 2006", "owner_id": 17212, "owner_name": "javier herranz", "owner_url": "http://www.panoramio.com/user/17212"} +, +{"photo_id": 6012915, "photo_title": "Erleuchtung in Venedig", "photo_url": "http://www.panoramio.com/photo/6012915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6012915.jpg", "longitude": 12.340747, "latitude": 45.433364, "width": 500, "height": 333, "upload_date": "19 November 2007", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 346687, "photo_title": "namibia desert", "photo_url": "http://www.panoramio.com/photo/346687", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/346687.jpg", "longitude": 15.408325, "latitude": -24.729370, "width": 500, "height": 334, "upload_date": "08 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 1913758, "photo_title": "Cortona - Via Gino Severini", "photo_url": "http://www.panoramio.com/photo/1913758", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1913758.jpg", "longitude": 11.988916, "latitude": 43.273659, "width": 500, "height": 498, "upload_date": "24 April 2007", "owner_id": 193913, "owner_name": "Klesitz Piroska", "owner_url": "http://www.panoramio.com/user/193913"} +, +{"photo_id": 405843, "photo_title": "siroiwa", "photo_url": "http://www.panoramio.com/photo/405843", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405843.jpg", "longitude": 138.789682, "latitude": 37.726398, "width": 500, "height": 338, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 91375, "photo_title": "Burj Al Arab At Night", "photo_url": "http://www.panoramio.com/photo/91375", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/91375.jpg", "longitude": 55.187416, "latitude": 25.140312, "width": 255, "height": 500, "upload_date": "03 December 2006", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 940792, "photo_title": "Moraine Branch", "photo_url": "http://www.panoramio.com/photo/940792", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/940792.jpg", "longitude": -116.177502, "latitude": 51.325946, "width": 500, "height": 332, "upload_date": "21 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 58287, "photo_title": "Schloß Anif", "photo_url": "http://www.panoramio.com/photo/58287", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58287.jpg", "longitude": 13.068817, "latitude": 47.744540, "width": 500, "height": 333, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 194118, "photo_title": "Mount Fuji: Fuji-San", "photo_url": "http://www.panoramio.com/photo/194118", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/194118.jpg", "longitude": 138.727455, "latitude": 35.377294, "width": 500, "height": 332, "upload_date": "20 December 2006", "owner_id": 27882, "owner_name": "taoy", "owner_url": "http://www.panoramio.com/user/27882"} +, +{"photo_id": 5158892, "photo_title": "prati di Tires Alto Adige Südtirol south tyrol", "photo_url": "http://www.panoramio.com/photo/5158892", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5158892.jpg", "longitude": 11.557188, "latitude": 46.471044, "width": 500, "height": 429, "upload_date": "08 October 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 280123, "photo_title": "kaouki05", "photo_url": "http://www.panoramio.com/photo/280123", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/280123.jpg", "longitude": -9.799418, "latitude": 31.355662, "width": 328, "height": 500, "upload_date": "01 January 2007", "owner_id": 58867, "owner_name": "Lachaud Franck", "owner_url": "http://www.panoramio.com/user/58867"} +, +{"photo_id": 6789223, "photo_title": "Exploding sky", "photo_url": "http://www.panoramio.com/photo/6789223", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6789223.jpg", "longitude": -69.930505, "latitude": 12.522579, "width": 500, "height": 333, "upload_date": "30 December 2007", "owner_id": 89499, "owner_name": "Michael Braxenthaler", "owner_url": "http://www.panoramio.com/user/89499"} +, +{"photo_id": 3722547, "photo_title": "Morning fog in the Alps", "photo_url": "http://www.panoramio.com/photo/3722547", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3722547.jpg", "longitude": 10.591164, "latitude": 47.521142, "width": 500, "height": 333, "upload_date": "04 August 2007", "owner_id": 89499, "owner_name": "Michael Braxenthaler", "owner_url": "http://www.panoramio.com/user/89499"} +, +{"photo_id": 9530458, "photo_title": "Castillian cereal fields from Atienza walls", "photo_url": "http://www.panoramio.com/photo/9530458", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9530458.jpg", "longitude": -2.874470, "latitude": 41.198451, "width": 500, "height": 470, "upload_date": "20 April 2008", "owner_id": 134279, "owner_name": "4ullas", "owner_url": "http://www.panoramio.com/user/134279"} +, +{"photo_id": 2935974, "photo_title": "Atardecer tras el Anboto desde el Aitzgorri", "photo_url": "http://www.panoramio.com/photo/2935974", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2935974.jpg", "longitude": -2.324982, "latitude": 42.951240, "width": 500, "height": 331, "upload_date": "25 June 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 38587, "photo_title": "Blitz", "photo_url": "http://www.panoramio.com/photo/38587", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/38587.jpg", "longitude": 7.949853, "latitude": 48.489947, "width": 500, "height": 375, "upload_date": "13 August 2006", "owner_id": 6002, "owner_name": "Paul Feiler", "owner_url": "http://www.panoramio.com/user/6002"} +, +{"photo_id": 9312247, "photo_title": "Idrija - High water after rain", "photo_url": "http://www.panoramio.com/photo/9312247", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9312247.jpg", "longitude": 13.965683, "latitude": 45.955625, "width": 500, "height": 375, "upload_date": "12 April 2008", "owner_id": 763995, "owner_name": "Samo T.", "owner_url": "http://www.panoramio.com/user/763995"} +, +{"photo_id": 110409, "photo_title": "Laguna de Yanganuco", "photo_url": "http://www.panoramio.com/photo/110409", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/110409.jpg", "longitude": -77.640553, "latitude": -9.071585, "width": 330, "height": 500, "upload_date": "11 December 2006", "owner_id": 16323, "owner_name": "Luis Torres", "owner_url": "http://www.panoramio.com/user/16323"} +, +{"photo_id": 7609439, "photo_title": "FényfürdÅ‘", "photo_url": "http://www.panoramio.com/photo/7609439", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7609439.jpg", "longitude": 15.965366, "latitude": 47.877556, "width": 500, "height": 312, "upload_date": "05 February 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8599453, "photo_title": "Realidad comprimida", "photo_url": "http://www.panoramio.com/photo/8599453", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8599453.jpg", "longitude": -2.780957, "latitude": 43.033953, "width": 500, "height": 387, "upload_date": "17 March 2008", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 233921, "photo_title": "Mount Titlis, Engelberg, Switzerland www.titlis.ch / www.engelberg.ch/ www.berghuette.ch /www.brunnihuette.ch", "photo_url": "http://www.panoramio.com/photo/233921", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/233921.jpg", "longitude": 8.410742, "latitude": 46.841583, "width": 500, "height": 375, "upload_date": "25 December 2006", "owner_id": 47930, "owner_name": "werni", "owner_url": "http://www.panoramio.com/user/47930"} +, +{"photo_id": 561386, "photo_title": "the country", "photo_url": "http://www.panoramio.com/photo/561386", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/561386.jpg", "longitude": 138.871393, "latitude": 37.602196, "width": 500, "height": 383, "upload_date": "24 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1195112, "photo_title": "Tolar Grande", "photo_url": "http://www.panoramio.com/photo/1195112", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1195112.jpg", "longitude": -67.361984, "latitude": -24.545249, "width": 500, "height": 342, "upload_date": "06 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 5466129, "photo_title": "\"Lasciate ogne speranza, voi ch’intrate\". (\"Abandon all hope, ye who enter here\" ; \"Toi qui entre ici, abandonne toute espérance\".) Dante e il primo girone dell'Inferno (o Virgilio nella selva oscura, accanto all'ingresso dell'Inferno) (ou encore, plus prosaïquement, pêche dans le Jaunay en Vendée, le 21 octobre 2007 à l'aube d'un très froid matin d'automne). #129", "photo_url": "http://www.panoramio.com/photo/5466129", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5466129.jpg", "longitude": -1.901300, "latitude": 46.663398, "width": 500, "height": 281, "upload_date": "22 October 2007", "owner_id": 666755, "owner_name": "Armagnac", "owner_url": "http://www.panoramio.com/user/666755"} +, +{"photo_id": 57820, "photo_title": "Hallstatt 2", "photo_url": "http://www.panoramio.com/photo/57820", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57820.jpg", "longitude": 13.649054, "latitude": 47.555040, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 798312, "photo_title": "Riflettendo...", "photo_url": "http://www.panoramio.com/photo/798312", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/798312.jpg", "longitude": 7.677534, "latitude": 45.069925, "width": 500, "height": 332, "upload_date": "12 February 2007", "owner_id": 159455, "owner_name": "©Franco Truscello", "owner_url": "http://www.panoramio.com/user/159455"} +, +{"photo_id": 7401432, "photo_title": "07-12-18_\"Arterias del Bosque\" PIXELECTA", "photo_url": "http://www.panoramio.com/photo/7401432", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7401432.jpg", "longitude": -2.775679, "latitude": 43.005338, "width": 500, "height": 333, "upload_date": "27 January 2008", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 2584132, "photo_title": "Farm Tomita", "photo_url": "http://www.panoramio.com/photo/2584132", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2584132.jpg", "longitude": 142.426586, "latitude": 43.418889, "width": 500, "height": 375, "upload_date": "05 June 2007", "owner_id": 532882, "owner_name": "wisdomcomplex", "owner_url": "http://www.panoramio.com/user/532882"} +, +{"photo_id": 4670499, "photo_title": "El despertar de la naturaleza", "photo_url": "http://www.panoramio.com/photo/4670499", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4670499.jpg", "longitude": -73.227739, "latitude": -39.821285, "width": 500, "height": 371, "upload_date": "15 September 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 5133875, "photo_title": "Lumi Vardar", "photo_url": "http://www.panoramio.com/photo/5133875", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5133875.jpg", "longitude": 21.075597, "latitude": 42.006671, "width": 500, "height": 375, "upload_date": "06 October 2007", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 8309167, "photo_title": "Cueva de los Verdes", "photo_url": "http://www.panoramio.com/photo/8309167", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8309167.jpg", "longitude": -13.439734, "latitude": 29.161137, "width": 333, "height": 500, "upload_date": "05 March 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 1756166, "photo_title": "The Pantheon, Rome, Italy", "photo_url": "http://www.panoramio.com/photo/1756166", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1756166.jpg", "longitude": 12.476842, "latitude": 41.898540, "width": 376, "height": 500, "upload_date": "13 April 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 1831309, "photo_title": "Oak in blue - last one", "photo_url": "http://www.panoramio.com/photo/1831309", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1831309.jpg", "longitude": 10.771322, "latitude": 59.664143, "width": 326, "height": 500, "upload_date": "18 April 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 626487, "photo_title": "A harag napja", "photo_url": "http://www.panoramio.com/photo/626487", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/626487.jpg", "longitude": 15.919275, "latitude": 43.589468, "width": 500, "height": 333, "upload_date": "30 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 202162, "photo_title": "Monument Valley", "photo_url": "http://www.panoramio.com/photo/202162", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/202162.jpg", "longitude": -110.094552, "latitude": 36.976810, "width": 500, "height": 333, "upload_date": "21 December 2006", "owner_id": 40260, "owner_name": "Don Albonico", "owner_url": "http://www.panoramio.com/user/40260"} +, +{"photo_id": 791016, "photo_title": "Sossusvlei", "photo_url": "http://www.panoramio.com/photo/791016", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/791016.jpg", "longitude": 15.289364, "latitude": -24.730656, "width": 500, "height": 333, "upload_date": "12 February 2007", "owner_id": 12736, "owner_name": "www.sliwi.de", "owner_url": "http://www.panoramio.com/user/12736"} +, +{"photo_id": 9760518, "photo_title": "Eglise Notre-Dame de la Couture", "photo_url": "http://www.panoramio.com/photo/9760518", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9760518.jpg", "longitude": 0.596437, "latitude": 49.082510, "width": 375, "height": 500, "upload_date": "29 April 2008", "owner_id": 1275480, "owner_name": "Nicolas Aubé", "owner_url": "http://www.panoramio.com/user/1275480"} +, +{"photo_id": 2097684, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/2097684", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2097684.jpg", "longitude": -79.793916, "latitude": 43.299447, "width": 500, "height": 333, "upload_date": "06 May 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 6851021, "photo_title": "Lumi Vardar-Sunset", "photo_url": "http://www.panoramio.com/photo/6851021", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6851021.jpg", "longitude": 21.077871, "latitude": 42.007532, "width": 458, "height": 500, "upload_date": "02 January 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 8137868, "photo_title": "Sunset Trace at Kotchi, Korea", "photo_url": "http://www.panoramio.com/photo/8137868", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8137868.jpg", "longitude": 126.333847, "latitude": 36.498597, "width": 500, "height": 500, "upload_date": "27 February 2008", "owner_id": 1221287, "owner_name": "TS Jeung", "owner_url": "http://www.panoramio.com/user/1221287"} +, +{"photo_id": 382104, "photo_title": "Meteora", "photo_url": "http://www.panoramio.com/photo/382104", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/382104.jpg", "longitude": 21.616974, "latitude": 39.743626, "width": 500, "height": 500, "upload_date": "11 January 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 3399014, "photo_title": "Vue du Schneibstein vers l'Est", "photo_url": "http://www.panoramio.com/photo/3399014", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3399014.jpg", "longitude": 13.055191, "latitude": 47.562396, "width": 500, "height": 328, "upload_date": "19 July 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 29596, "photo_title": "Ciudad de Los Cielos", "photo_url": "http://www.panoramio.com/photo/29596", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/29596.jpg", "longitude": -72.545900, "latitude": -13.165304, "width": 500, "height": 375, "upload_date": "01 July 2006", "owner_id": 4483, "owner_name": "Miguel Coranti", "owner_url": "http://www.panoramio.com/user/4483"} +, +{"photo_id": 1269713, "photo_title": "Rainbow over OlskÃ¥rdvatnet near Kiberg, Finnmark, Norway", "photo_url": "http://www.panoramio.com/photo/1269713", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1269713.jpg", "longitude": 30.906601, "latitude": 70.295137, "width": 361, "height": 500, "upload_date": "11 March 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 507631, "photo_title": "Egy ábrándos reggelen", "photo_url": "http://www.panoramio.com/photo/507631", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507631.jpg", "longitude": 17.466667, "latitude": 47.866667, "width": 500, "height": 334, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 722974, "photo_title": "Airdrie Vortex", "photo_url": "http://www.panoramio.com/photo/722974", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/722974.jpg", "longitude": -114.087481, "latitude": 51.048544, "width": 500, "height": 323, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1118007, "photo_title": "Moraine Lake, Banff NP (Canada)", "photo_url": "http://www.panoramio.com/photo/1118007", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1118007.jpg", "longitude": -116.177673, "latitude": 51.328091, "width": 500, "height": 326, "upload_date": "02 March 2007", "owner_id": 229005, "owner_name": "mypictures4u.com", "owner_url": "http://www.panoramio.com/user/229005"} +, +{"photo_id": 1343943, "photo_title": "Andes Mountains.Patagonia.Argentina", "photo_url": "http://www.panoramio.com/photo/1343943", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1343943.jpg", "longitude": -72.422905, "latitude": -49.381814, "width": 500, "height": 375, "upload_date": "16 March 2007", "owner_id": 281428, "owner_name": "avni_", "owner_url": "http://www.panoramio.com/user/281428"} +, +{"photo_id": 5637365, "photo_title": "Northen lights", "photo_url": "http://www.panoramio.com/photo/5637365", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5637365.jpg", "longitude": 28.599129, "latitude": 66.247365, "width": 500, "height": 333, "upload_date": "30 October 2007", "owner_id": 897591, "owner_name": "markku pirttimaa www.karhukuusamo.com", "owner_url": "http://www.panoramio.com/user/897591"} +, +{"photo_id": 241562, "photo_title": "Süd-Ostisland", "photo_url": "http://www.panoramio.com/photo/241562", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/241562.jpg", "longitude": -17.512207, "latitude": 63.954261, "width": 500, "height": 326, "upload_date": "26 December 2006", "owner_id": 14774, "owner_name": "Frank Block", "owner_url": "http://www.panoramio.com/user/14774"} +, +{"photo_id": 48899, "photo_title": "Bellagio Fountain", "photo_url": "http://www.panoramio.com/photo/48899", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/48899.jpg", "longitude": -115.174227, "latitude": 36.112778, "width": 500, "height": 375, "upload_date": "16 September 2006", "owner_id": 7190, "owner_name": "Perry Tang", "owner_url": "http://www.panoramio.com/user/7190"} +, +{"photo_id": 49822, "photo_title": "Baños termales en Alhama de Granada", "photo_url": "http://www.panoramio.com/photo/49822", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/49822.jpg", "longitude": -3.983274, "latitude": 37.018248, "width": 374, "height": 500, "upload_date": "19 September 2006", "owner_id": 5477, "owner_name": "errece", "owner_url": "http://www.panoramio.com/user/5477"} +, +{"photo_id": 8248490, "photo_title": "Emmerald river", "photo_url": "http://www.panoramio.com/photo/8248490", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8248490.jpg", "longitude": 13.650362, "latitude": 46.340336, "width": 375, "height": 500, "upload_date": "02 March 2008", "owner_id": 763995, "owner_name": "Samo T.", "owner_url": "http://www.panoramio.com/user/763995"} +, +{"photo_id": 459528, "photo_title": "gassan", "photo_url": "http://www.panoramio.com/photo/459528", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459528.jpg", "longitude": 139.895782, "latitude": 38.282391, "width": 500, "height": 379, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 50203, "photo_title": "Die Hütte in Nyidalur an einem Septembermorgen ....", "photo_url": "http://www.panoramio.com/photo/50203", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/50203.jpg", "longitude": -18.132935, "latitude": 64.762124, "width": 500, "height": 299, "upload_date": "20 September 2006", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 51502, "photo_title": "eclipse", "photo_url": "http://www.panoramio.com/photo/51502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/51502.jpg", "longitude": -0.121665, "latitude": 51.500969, "width": 500, "height": 375, "upload_date": "24 September 2006", "owner_id": 6645, "owner_name": "JesusVillalba", "owner_url": "http://www.panoramio.com/user/6645"} +, +{"photo_id": 3671663, "photo_title": "Urbia traspuesta de sol, desde Aizkorri", "photo_url": "http://www.panoramio.com/photo/3671663", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3671663.jpg", "longitude": -2.324831, "latitude": 42.951271, "width": 500, "height": 298, "upload_date": "02 August 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 1928780, "photo_title": "God is looking", "photo_url": "http://www.panoramio.com/photo/1928780", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1928780.jpg", "longitude": 19.952137, "latitude": 50.106075, "width": 500, "height": 379, "upload_date": "25 April 2007", "owner_id": 12954, "owner_name": "ZiÄ™bol", "owner_url": "http://www.panoramio.com/user/12954"} +, +{"photo_id": 10068109, "photo_title": "#2 Steinerne Brücke über Lendkanal, Stone Bridge over Lendkanal, Klagenfurt, Austria", "photo_url": "http://www.panoramio.com/photo/10068109", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10068109.jpg", "longitude": 14.284313, "latitude": 46.620436, "width": 376, "height": 500, "upload_date": "09 May 2008", "owner_id": 1077251, "owner_name": "picsonthemove", "owner_url": "http://www.panoramio.com/user/1077251"} +, +{"photo_id": 8730264, "photo_title": "Large wave hits the North Pier, Tynemouth - Easter 2008", "photo_url": "http://www.panoramio.com/photo/8730264", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8730264.jpg", "longitude": -1.420702, "latitude": 55.020727, "width": 434, "height": 500, "upload_date": "22 March 2008", "owner_id": 1107262, "owner_name": "bobpercy", "owner_url": "http://www.panoramio.com/user/1107262"} +, +{"photo_id": 330436, "photo_title": "bolivia salar-de-uyuni", "photo_url": "http://www.panoramio.com/photo/330436", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/330436.jpg", "longitude": -67.876625, "latitude": -20.180046, "width": 500, "height": 334, "upload_date": "07 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 10287647, "photo_title": "A moment of silence * Honorable mention may contest*", "photo_url": "http://www.panoramio.com/photo/10287647", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10287647.jpg", "longitude": 6.177192, "latitude": 52.218099, "width": 500, "height": 413, "upload_date": "16 May 2008", "owner_id": 523564, "owner_name": "Luud Riphagen", "owner_url": "http://www.panoramio.com/user/523564"} +, +{"photo_id": 436323, "photo_title": "zeikan", "photo_url": "http://www.panoramio.com/photo/436323", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436323.jpg", "longitude": 139.057925, "latitude": 37.930016, "width": 500, "height": 381, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 298350, "photo_title": "What are you looking at ?", "photo_url": "http://www.panoramio.com/photo/298350", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/298350.jpg", "longitude": -109.276510, "latitude": -27.125567, "width": 500, "height": 332, "upload_date": "04 January 2007", "owner_id": 57893, "owner_name": "ThoiryK", "owner_url": "http://www.panoramio.com/user/57893"} +, +{"photo_id": 85618, "photo_title": "Minas de Mazarrón", "photo_url": "http://www.panoramio.com/photo/85618", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/85618.jpg", "longitude": -1.331406, "latitude": 37.599544, "width": 500, "height": 334, "upload_date": "24 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 3804107, "photo_title": "_Feloeka on the Nile_ (Aswan - Egypt)", "photo_url": "http://www.panoramio.com/photo/3804107", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3804107.jpg", "longitude": 32.887723, "latitude": 24.095443, "width": 500, "height": 350, "upload_date": "08 August 2007", "owner_id": 366746, "owner_name": "T NL", "owner_url": "http://www.panoramio.com/user/366746"} +, +{"photo_id": 369885, "photo_title": "Monarque on the beach", "photo_url": "http://www.panoramio.com/photo/369885", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/369885.jpg", "longitude": -70.563126, "latitude": 43.308816, "width": 500, "height": 371, "upload_date": "10 January 2007", "owner_id": 78738, "owner_name": "Nicola Vachon", "owner_url": "http://www.panoramio.com/user/78738"} +, +{"photo_id": 4819425, "photo_title": "Zeeland Magic, 1", "photo_url": "http://www.panoramio.com/photo/4819425", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4819425.jpg", "longitude": 3.479254, "latitude": 51.501169, "width": 492, "height": 500, "upload_date": "22 September 2007", "owner_id": 213866, "owner_name": "Nicolas Mertens", "owner_url": "http://www.panoramio.com/user/213866"} +, +{"photo_id": 88122, "photo_title": "Arpy Lake - Aosta Valley - Italy", "photo_url": "http://www.panoramio.com/photo/88122", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/88122.jpg", "longitude": 6.999636, "latitude": 45.723008, "width": 375, "height": 500, "upload_date": "28 November 2006", "owner_id": 11098, "owner_name": "Michele Masnata", "owner_url": "http://www.panoramio.com/user/11098"} +, +{"photo_id": 10219582, "photo_title": "MITTENS ALONG THE ROAD", "photo_url": "http://www.panoramio.com/photo/10219582", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10219582.jpg", "longitude": -110.091248, "latitude": 36.970810, "width": 500, "height": 462, "upload_date": "14 May 2008", "owner_id": 864987, "owner_name": "antorenz", "owner_url": "http://www.panoramio.com/user/864987"} +, +{"photo_id": 558167, "photo_title": "Táltostánc", "photo_url": "http://www.panoramio.com/photo/558167", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/558167.jpg", "longitude": 18.001614, "latitude": 47.409038, "width": 417, "height": 500, "upload_date": "24 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 7113068, "photo_title": "Bálavár", "photo_url": "http://www.panoramio.com/photo/7113068", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7113068.jpg", "longitude": 17.522507, "latitude": 47.775560, "width": 500, "height": 336, "upload_date": "14 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2920885, "photo_title": "Rainbow", "photo_url": "http://www.panoramio.com/photo/2920885", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2920885.jpg", "longitude": 10.620818, "latitude": 47.770960, "width": 375, "height": 500, "upload_date": "24 June 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 2499825, "photo_title": "Rosina lamberti,sunset, templestowe", "photo_url": "http://www.panoramio.com/photo/2499825", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2499825.jpg", "longitude": 145.143299, "latitude": -37.770104, "width": 500, "height": 359, "upload_date": "01 June 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 4536639, "photo_title": "Lago di Carezza", "photo_url": "http://www.panoramio.com/photo/4536639", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4536639.jpg", "longitude": 11.575298, "latitude": 46.410227, "width": 500, "height": 393, "upload_date": "09 September 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 314957, "photo_title": "\"He it is, who coming after me...\" - St. John Baptist on the Charles Bridge ", "photo_url": "http://www.panoramio.com/photo/314957", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/314957.jpg", "longitude": 14.410307, "latitude": 50.086597, "width": 335, "height": 500, "upload_date": "06 January 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 507214, "photo_title": "A változás ideje", "photo_url": "http://www.panoramio.com/photo/507214", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507214.jpg", "longitude": 17.980499, "latitude": 47.390912, "width": 500, "height": 335, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 5551561, "photo_title": "New light old trees26-10-2007", "photo_url": "http://www.panoramio.com/photo/5551561", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5551561.jpg", "longitude": -5.663366, "latitude": 55.390130, "width": 338, "height": 500, "upload_date": "26 October 2007", "owner_id": 599676, "owner_name": "mossip", "owner_url": "http://www.panoramio.com/user/599676"} +, +{"photo_id": 67338, "photo_title": "Salar de Uyuni", "photo_url": "http://www.panoramio.com/photo/67338", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/67338.jpg", "longitude": -67.539825, "latitude": -20.439882, "width": 375, "height": 500, "upload_date": "20 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 436354, "photo_title": "oonogame", "photo_url": "http://www.panoramio.com/photo/436354", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436354.jpg", "longitude": 138.461380, "latitude": 38.311760, "width": 387, "height": 500, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 10068358, "photo_title": "#08 Reflections in Lendkanal, Klagenfurt, Scenery June 2008", "photo_url": "http://www.panoramio.com/photo/10068358", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10068358.jpg", "longitude": 14.294415, "latitude": 46.622326, "width": 375, "height": 500, "upload_date": "09 May 2008", "owner_id": 1077251, "owner_name": "picsonthemove", "owner_url": "http://www.panoramio.com/user/1077251"} +, +{"photo_id": 1440137, "photo_title": "Horseshoe Bend", "photo_url": "http://www.panoramio.com/photo/1440137", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1440137.jpg", "longitude": -111.510887, "latitude": 36.882641, "width": 500, "height": 391, "upload_date": "22 March 2007", "owner_id": 286729, "owner_name": "jimwitkowski", "owner_url": "http://www.panoramio.com/user/286729"} +, +{"photo_id": 4809439, "photo_title": "Going Nowhere Fast", "photo_url": "http://www.panoramio.com/photo/4809439", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4809439.jpg", "longitude": -119.013970, "latitude": 38.211420, "width": 375, "height": 500, "upload_date": "21 September 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 7806281, "photo_title": "Moon&Mosque", "photo_url": "http://www.panoramio.com/photo/7806281", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7806281.jpg", "longitude": 21.138296, "latitude": 41.960958, "width": 500, "height": 344, "upload_date": "13 February 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 821388, "photo_title": "Aurora Borealis with frosty fog from the sea in front", "photo_url": "http://www.panoramio.com/photo/821388", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/821388.jpg", "longitude": 23.229733, "latitude": 69.962616, "width": 500, "height": 256, "upload_date": "14 February 2007", "owner_id": 56091, "owner_name": "Kjetil Vaage Øie", "owner_url": "http://www.panoramio.com/user/56091"} +, +{"photo_id": 946841, "photo_title": "Maroon Bells", "photo_url": "http://www.panoramio.com/photo/946841", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/946841.jpg", "longitude": -106.948385, "latitude": 39.095030, "width": 500, "height": 375, "upload_date": "21 February 2007", "owner_id": 163881, "owner_name": "faisasy", "owner_url": "http://www.panoramio.com/user/163881"} +, +{"photo_id": 3719882, "photo_title": "Puesta de Sol(Oest.Portugal)", "photo_url": "http://www.panoramio.com/photo/3719882", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3719882.jpg", "longitude": -9.286709, "latitude": 39.392428, "width": 375, "height": 500, "upload_date": "04 August 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 3418114, "photo_title": "Fény-Kép", "photo_url": "http://www.panoramio.com/photo/3418114", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3418114.jpg", "longitude": 17.511692, "latitude": 47.837127, "width": 500, "height": 333, "upload_date": "20 July 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 255257, "photo_title": "Croatia, Brela - Sunset on the Beach - near \"Kamen Brela\" rock, symbol of this adriatic town", "photo_url": "http://www.panoramio.com/photo/255257", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/255257.jpg", "longitude": 16.922604, "latitude": 43.372309, "width": 500, "height": 332, "upload_date": "28 December 2006", "owner_id": 52119, "owner_name": "RomanV", "owner_url": "http://www.panoramio.com/user/52119"} +, +{"photo_id": 2346040, "photo_title": "Huncut fények", "photo_url": "http://www.panoramio.com/photo/2346040", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2346040.jpg", "longitude": 15.539217, "latitude": 47.670589, "width": 500, "height": 334, "upload_date": "22 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1235900, "photo_title": "Fog, Hemlocks and Cedars ", "photo_url": "http://www.panoramio.com/photo/1235900", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1235900.jpg", "longitude": -131.682816, "latitude": 52.885706, "width": 500, "height": 352, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 111554, "photo_title": "Lahna", "photo_url": "http://www.panoramio.com/photo/111554", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/111554.jpg", "longitude": 27.557831, "latitude": 42.550551, "width": 500, "height": 357, "upload_date": "11 December 2006", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 280112, "photo_title": "dune02", "photo_url": "http://www.panoramio.com/photo/280112", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/280112.jpg", "longitude": -3.985291, "latitude": 31.156408, "width": 500, "height": 338, "upload_date": "01 January 2007", "owner_id": 58867, "owner_name": "Lachaud Franck", "owner_url": "http://www.panoramio.com/user/58867"} +, +{"photo_id": 5984, "photo_title": "Chott El Jerid", "photo_url": "http://www.panoramio.com/photo/5984", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5984.jpg", "longitude": 8.358536, "latitude": 33.715202, "width": 347, "height": 500, "upload_date": "17 December 2005", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 25513, "photo_title": "Catarata Rio Celeste", "photo_url": "http://www.panoramio.com/photo/25513", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/25513.jpg", "longitude": -85.046539, "latitude": 10.643400, "width": 375, "height": 500, "upload_date": "17 June 2006", "owner_id": 4112, "owner_name": "Roberto Garcia", "owner_url": "http://www.panoramio.com/user/4112"} +, +{"photo_id": 35502, "photo_title": "roques", "photo_url": "http://www.panoramio.com/photo/35502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/35502.jpg", "longitude": -66.774902, "latitude": 11.802834, "width": 500, "height": 375, "upload_date": "29 July 2006", "owner_id": 3360, "owner_name": "ozzy", "owner_url": "http://www.panoramio.com/user/3360"} +, +{"photo_id": 1656020, "photo_title": "Palmeras", "photo_url": "http://www.panoramio.com/photo/1656020", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1656020.jpg", "longitude": -1.211929, "latitude": 37.935804, "width": 500, "height": 333, "upload_date": "06 April 2007", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 58341, "photo_title": "Lio Piccolo - Palazzetto Boldú", "photo_url": "http://www.panoramio.com/photo/58341", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58341.jpg", "longitude": 12.489095, "latitude": 45.490615, "width": 500, "height": 333, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 416310, "photo_title": "Lake of Glass Falls", "photo_url": "http://www.panoramio.com/photo/416310", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/416310.jpg", "longitude": -105.664272, "latitude": 40.283192, "width": 500, "height": 374, "upload_date": "13 January 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 8148031, "photo_title": "Der Morgen in der Camargue .....", "photo_url": "http://www.panoramio.com/photo/8148031", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8148031.jpg", "longitude": 4.451180, "latitude": 43.507102, "width": 500, "height": 351, "upload_date": "27 February 2008", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 1088575, "photo_title": "Lampion", "photo_url": "http://www.panoramio.com/photo/1088575", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1088575.jpg", "longitude": 17.698631, "latitude": 47.521374, "width": 500, "height": 397, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 771169, "photo_title": "Bloodred evening sky, near Zutphen", "photo_url": "http://www.panoramio.com/photo/771169", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/771169.jpg", "longitude": 6.110770, "latitude": 52.113681, "width": 500, "height": 500, "upload_date": "11 February 2007", "owner_id": 161254, "owner_name": "fotoartistry", "owner_url": "http://www.panoramio.com/user/161254"} +, +{"photo_id": 2334149, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/2334149", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2334149.jpg", "longitude": 0.493269, "latitude": 40.904204, "width": 500, "height": 304, "upload_date": "21 May 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 41688, "photo_title": "Unbelieveable sunrise colors at Lofoten", "photo_url": "http://www.panoramio.com/photo/41688", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/41688.jpg", "longitude": 14.256134, "latitude": 68.239368, "width": 500, "height": 375, "upload_date": "26 August 2006", "owner_id": 3404, "owner_name": "Csongor Böröczky", "owner_url": "http://www.panoramio.com/user/3404"} +, +{"photo_id": 6953, "photo_title": "Last moment of the day", "photo_url": "http://www.panoramio.com/photo/6953", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6953.jpg", "longitude": 2.191944, "latitude": 41.578599, "width": 500, "height": 320, "upload_date": "16 January 2006", "owner_id": 414, "owner_name": "Sonia Villegas", "owner_url": "http://www.panoramio.com/user/414"} +, +{"photo_id": 10895432, "photo_title": "КарагайÑÐºÐ°Ñ ÑоÑна", "photo_url": "http://www.panoramio.com/photo/10895432", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10895432.jpg", "longitude": 57.886791, "latitude": 51.644708, "width": 333, "height": 500, "upload_date": "04 June 2008", "owner_id": 904057, "owner_name": "Б.Ярцев", "owner_url": "http://www.panoramio.com/user/904057"} +, +{"photo_id": 1446812, "photo_title": "Elfland", "photo_url": "http://www.panoramio.com/photo/1446812", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1446812.jpg", "longitude": 17.808323, "latitude": 47.349408, "width": 345, "height": 500, "upload_date": "22 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4898495, "photo_title": "Elfendel", "photo_url": "http://www.panoramio.com/photo/4898495", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4898495.jpg", "longitude": 17.724380, "latitude": 47.261058, "width": 500, "height": 325, "upload_date": "25 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 911298, "photo_title": "View from Nordenskiöldtoppen, Svalbard", "photo_url": "http://www.panoramio.com/photo/911298", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/911298.jpg", "longitude": 15.314941, "latitude": 78.179588, "width": 500, "height": 287, "upload_date": "20 February 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 2169236, "photo_title": "sunset", "photo_url": "http://www.panoramio.com/photo/2169236", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2169236.jpg", "longitude": 145.128708, "latitude": -37.759859, "width": 333, "height": 500, "upload_date": "11 May 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 237466, "photo_title": "wierzchon.com warsaw podzamcze", "photo_url": "http://www.panoramio.com/photo/237466", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/237466.jpg", "longitude": 21.011347, "latitude": 52.253852, "width": 335, "height": 500, "upload_date": "26 December 2006", "owner_id": 47836, "owner_name": "Andrzej Wierzchon", "owner_url": "http://www.panoramio.com/user/47836"} +, +{"photo_id": 355519, "photo_title": "chile laguna miscanti", "photo_url": "http://www.panoramio.com/photo/355519", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/355519.jpg", "longitude": -67.798347, "latitude": -23.758010, "width": 500, "height": 334, "upload_date": "09 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 58360, "photo_title": "Castello di Toblino", "photo_url": "http://www.panoramio.com/photo/58360", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58360.jpg", "longitude": 10.966415, "latitude": 46.054173, "width": 500, "height": 333, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 10511168, "photo_title": "Në Fush të Pallaticës", "photo_url": "http://www.panoramio.com/photo/10511168", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10511168.jpg", "longitude": 21.075296, "latitude": 42.007692, "width": 500, "height": 413, "upload_date": "23 May 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 572526, "photo_title": "Farm by Osafjorden in the first sun of the day", "photo_url": "http://www.panoramio.com/photo/572526", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/572526.jpg", "longitude": 6.998119, "latitude": 60.563101, "width": 500, "height": 353, "upload_date": "25 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 5303687, "photo_title": "Fátyoltánc", "photo_url": "http://www.panoramio.com/photo/5303687", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5303687.jpg", "longitude": 15.934725, "latitude": 47.915997, "width": 500, "height": 334, "upload_date": "14 October 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 370324, "photo_title": "Rainbow_by_bkm", "photo_url": "http://www.panoramio.com/photo/370324", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/370324.jpg", "longitude": 6.453094, "latitude": 62.636926, "width": 500, "height": 344, "upload_date": "10 January 2007", "owner_id": 78923, "owner_name": "bj00rn", "owner_url": "http://www.panoramio.com/user/78923"} +, +{"photo_id": 7996369, "photo_title": "Bled - Church on the island", "photo_url": "http://www.panoramio.com/photo/7996369", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7996369.jpg", "longitude": 14.084473, "latitude": 46.360671, "width": 375, "height": 500, "upload_date": "21 February 2008", "owner_id": 763995, "owner_name": "Samo T.", "owner_url": "http://www.panoramio.com/user/763995"} +, +{"photo_id": 498385, "photo_title": "Rainbow Falls in Sun", "photo_url": "http://www.panoramio.com/photo/498385", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/498385.jpg", "longitude": -119.084823, "latitude": 37.601771, "width": 407, "height": 500, "upload_date": "20 January 2007", "owner_id": 107613, "owner_name": "Tom Grubbe", "owner_url": "http://www.panoramio.com/user/107613"} +, +{"photo_id": 571110, "photo_title": "Nordlys - Aurora Borealis - over Vadsø", "photo_url": "http://www.panoramio.com/photo/571110", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/571110.jpg", "longitude": 29.815350, "latitude": 70.075649, "width": 500, "height": 332, "upload_date": "25 January 2007", "owner_id": 121482, "owner_name": "Jens Gressmyr", "owner_url": "http://www.panoramio.com/user/121482"} +, +{"photo_id": 3904502, "photo_title": "Una notte di fuoco - a night of fire ", "photo_url": "http://www.panoramio.com/photo/3904502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3904502.jpg", "longitude": 11.337290, "latitude": 46.461257, "width": 500, "height": 360, "upload_date": "13 August 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 1835001, "photo_title": "Вулкан ЖупановÑкий. РаÑÑвет", "photo_url": "http://www.panoramio.com/photo/1835001", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1835001.jpg", "longitude": 158.595543, "latitude": 53.496828, "width": 500, "height": 341, "upload_date": "19 April 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 91931, "photo_title": "Plitvice (Croacia)", "photo_url": "http://www.panoramio.com/photo/91931", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/91931.jpg", "longitude": 15.599556, "latitude": 44.851975, "width": 500, "height": 375, "upload_date": "04 December 2006", "owner_id": 11403, "owner_name": "Arnáiz", "owner_url": "http://www.panoramio.com/user/11403"} +, +{"photo_id": 515905, "photo_title": "A figyelÅ‘", "photo_url": "http://www.panoramio.com/photo/515905", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/515905.jpg", "longitude": 17.625675, "latitude": 47.565060, "width": 500, "height": 345, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 7444056, "photo_title": "Ragyogás II.", "photo_url": "http://www.panoramio.com/photo/7444056", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7444056.jpg", "longitude": 16.385422, "latitude": 46.850095, "width": 333, "height": 500, "upload_date": "29 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1674082, "photo_title": "STATUA LIBERTA'", "photo_url": "http://www.panoramio.com/photo/1674082", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1674082.jpg", "longitude": -74.042444, "latitude": 40.689229, "width": 500, "height": 375, "upload_date": "07 April 2007", "owner_id": 135078, "owner_name": "Fabio Belli FABIOSO", "owner_url": "http://www.panoramio.com/user/135078"} +, +{"photo_id": 798846, "photo_title": "Panther Rock, Antelope Canyon, AZ", "photo_url": "http://www.panoramio.com/photo/798846", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/798846.jpg", "longitude": -111.391668, "latitude": 36.878728, "width": 376, "height": 500, "upload_date": "12 February 2007", "owner_id": 52440, "owner_name": "Hank Waxman", "owner_url": "http://www.panoramio.com/user/52440"} +, +{"photo_id": 21458, "photo_title": "The way of dreams (Aletschgletsher)", "photo_url": "http://www.panoramio.com/photo/21458", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/21458.jpg", "longitude": 7.976074, "latitude": 46.544694, "width": 500, "height": 375, "upload_date": "29 May 2006", "owner_id": 3404, "owner_name": "Csongor Böröczky", "owner_url": "http://www.panoramio.com/user/3404"} +, +{"photo_id": 691681, "photo_title": "PANORAMIO - Ilha das Cabras - by Wolfgang Wodeck", "photo_url": "http://www.panoramio.com/photo/691681", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/691681.jpg", "longitude": -48.628750, "latitude": -26.989624, "width": 500, "height": 333, "upload_date": "04 February 2007", "owner_id": 103166, "owner_name": "Wolfgang Wodeck", "owner_url": "http://www.panoramio.com/user/103166"} +, +{"photo_id": 564451, "photo_title": "Gewitter über Schutterwald", "photo_url": "http://www.panoramio.com/photo/564451", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/564451.jpg", "longitude": 7.887470, "latitude": 48.453409, "width": 500, "height": 333, "upload_date": "25 January 2007", "owner_id": 121083, "owner_name": "Alexandra Buss", "owner_url": "http://www.panoramio.com/user/121083"} +, +{"photo_id": 1430151, "photo_title": "Burano", "photo_url": "http://www.panoramio.com/photo/1430151", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1430151.jpg", "longitude": 12.416686, "latitude": 45.485966, "width": 500, "height": 365, "upload_date": "21 March 2007", "owner_id": 193913, "owner_name": "Klesitz Piroska", "owner_url": "http://www.panoramio.com/user/193913"} +, +{"photo_id": 3156915, "photo_title": "Brussels - Grand Place", "photo_url": "http://www.panoramio.com/photo/3156915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3156915.jpg", "longitude": 4.352152, "latitude": 50.846658, "width": 500, "height": 375, "upload_date": "07 July 2007", "owner_id": 138691, "owner_name": "Josep Maria Alegre", "owner_url": "http://www.panoramio.com/user/138691"} +, +{"photo_id": 6126516, "photo_title": "Richmond Deer", "photo_url": "http://www.panoramio.com/photo/6126516", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126516.jpg", "longitude": -0.279776, "latitude": 51.448565, "width": 500, "height": 294, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 679356, "photo_title": "sulphur crested cockatoos", "photo_url": "http://www.panoramio.com/photo/679356", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/679356.jpg", "longitude": 150.363181, "latitude": -33.718234, "width": 500, "height": 500, "upload_date": "04 February 2007", "owner_id": 146092, "owner_name": "sid1662", "owner_url": "http://www.panoramio.com/user/146092"} +, +{"photo_id": 462324, "photo_title": "Yucca", "photo_url": "http://www.panoramio.com/photo/462324", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/462324.jpg", "longitude": -106.259680, "latitude": 32.797448, "width": 500, "height": 500, "upload_date": "17 January 2007", "owner_id": 93560, "owner_name": "Alex Petrov", "owner_url": "http://www.panoramio.com/user/93560"} +, +{"photo_id": 9528831, "photo_title": "maldives", "photo_url": "http://www.panoramio.com/photo/9528831", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9528831.jpg", "longitude": 73.454686, "latitude": 3.845837, "width": 500, "height": 335, "upload_date": "20 April 2008", "owner_id": 647076, "owner_name": "garethohara", "owner_url": "http://www.panoramio.com/user/647076"} +, +{"photo_id": 11825351, "photo_title": " ARC Buque Escuela Gloria. ARC School Ship Gloria. by (((Jose Daniel))) ", "photo_url": "http://www.panoramio.com/photo/11825351", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11825351.jpg", "longitude": -75.539761, "latitude": 10.410917, "width": 500, "height": 392, "upload_date": "05 July 2008", "owner_id": 1611883, "owner_name": "(((Jose Daniel)))", "owner_url": "http://www.panoramio.com/user/1611883"} +, +{"photo_id": 459614, "photo_title": "seaside line", "photo_url": "http://www.panoramio.com/photo/459614", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459614.jpg", "longitude": 138.801785, "latitude": 37.756669, "width": 500, "height": 383, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 771974, "photo_title": "Retired Boat", "photo_url": "http://www.panoramio.com/photo/771974", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/771974.jpg", "longitude": 25.427610, "latitude": 36.427576, "width": 500, "height": 332, "upload_date": "11 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1781649, "photo_title": "Fall in Yosemite Valley", "photo_url": "http://www.panoramio.com/photo/1781649", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781649.jpg", "longitude": -119.609270, "latitude": 37.735290, "width": 500, "height": 400, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 8491500, "photo_title": "Horsetail Falls at Sunset", "photo_url": "http://www.panoramio.com/photo/8491500", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8491500.jpg", "longitude": -119.623947, "latitude": 37.723512, "width": 333, "height": 500, "upload_date": "12 March 2008", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 9505599, "photo_title": "#9 Penguins at Boulders Beach, Simon’s Town, Scenery May08", "photo_url": "http://www.panoramio.com/photo/9505599", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9505599.jpg", "longitude": 18.450642, "latitude": -34.196443, "width": 500, "height": 489, "upload_date": "19 April 2008", "owner_id": 1077251, "owner_name": "picsonthemove", "owner_url": "http://www.panoramio.com/user/1077251"} +, +{"photo_id": 1320563, "photo_title": "Pirates on anchor", "photo_url": "http://www.panoramio.com/photo/1320563", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1320563.jpg", "longitude": 39.311485, "latitude": -5.724799, "width": 316, "height": 500, "upload_date": "14 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 2381962, "photo_title": "Uluru,Northern Territory,Australia-Rosina lamberti", "photo_url": "http://www.panoramio.com/photo/2381962", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2381962.jpg", "longitude": 131.054878, "latitude": -25.326959, "width": 500, "height": 274, "upload_date": "25 May 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 92102, "photo_title": "Briksdalsbreen (Norway)", "photo_url": "http://www.panoramio.com/photo/92102", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/92102.jpg", "longitude": 6.887054, "latitude": 61.664788, "width": 500, "height": 375, "upload_date": "05 December 2006", "owner_id": 11403, "owner_name": "Arnáiz", "owner_url": "http://www.panoramio.com/user/11403"} +, +{"photo_id": 7012377, "photo_title": "Kanyarfények", "photo_url": "http://www.panoramio.com/photo/7012377", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7012377.jpg", "longitude": 17.517700, "latitude": 47.760445, "width": 500, "height": 334, "upload_date": "09 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 422769, "photo_title": "hazaki2", "photo_url": "http://www.panoramio.com/photo/422769", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/422769.jpg", "longitude": 138.862553, "latitude": 37.711410, "width": 500, "height": 333, "upload_date": "14 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 4558763, "photo_title": "Corsica - West Coast", "photo_url": "http://www.panoramio.com/photo/4558763", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4558763.jpg", "longitude": 8.640404, "latitude": 42.255205, "width": 500, "height": 342, "upload_date": "10 September 2007", "owner_id": 49870, "owner_name": "Jean-Michel Raggioli", "owner_url": "http://www.panoramio.com/user/49870"} +, +{"photo_id": 374479, "photo_title": "Corinthos", "photo_url": "http://www.panoramio.com/photo/374479", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/374479.jpg", "longitude": 22.997131, "latitude": 37.925514, "width": 375, "height": 500, "upload_date": "10 January 2007", "owner_id": 74407, "owner_name": "Yeoman", "owner_url": "http://www.panoramio.com/user/74407"} +, +{"photo_id": 2421991, "photo_title": "\"Different\" Arch", "photo_url": "http://www.panoramio.com/photo/2421991", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2421991.jpg", "longitude": -109.499032, "latitude": 38.744118, "width": 500, "height": 333, "upload_date": "27 May 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 945978, "photo_title": "L'Ebre", "photo_url": "http://www.panoramio.com/photo/945978", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/945978.jpg", "longitude": 0.495501, "latitude": 40.905015, "width": 500, "height": 377, "upload_date": "21 February 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 48449, "photo_title": "Montserrat", "photo_url": "http://www.panoramio.com/photo/48449", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/48449.jpg", "longitude": 1.840060, "latitude": 41.593702, "width": 500, "height": 337, "upload_date": "15 September 2006", "owner_id": 5477, "owner_name": "errece", "owner_url": "http://www.panoramio.com/user/5477"} +, +{"photo_id": 572483, "photo_title": "wheatfield in autumn", "photo_url": "http://www.panoramio.com/photo/572483", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/572483.jpg", "longitude": 11.278152, "latitude": 59.644760, "width": 500, "height": 351, "upload_date": "25 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 2060897, "photo_title": "Mid Coolum", "photo_url": "http://www.panoramio.com/photo/2060897", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2060897.jpg", "longitude": 153.097685, "latitude": -26.540052, "width": 500, "height": 336, "upload_date": "04 May 2007", "owner_id": 411736, "owner_name": "Nixpix", "owner_url": "http://www.panoramio.com/user/411736"} +, +{"photo_id": 6327146, "photo_title": "Winterwald beim \"Widi\" - a thin sheet of ice (messi 06)", "photo_url": "http://www.panoramio.com/photo/6327146", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6327146.jpg", "longitude": 7.381070, "latitude": 47.015670, "width": 500, "height": 363, "upload_date": "06 December 2007", "owner_id": 162722, "owner_name": "©polytropos", "owner_url": "http://www.panoramio.com/user/162722"} +, +{"photo_id": 36476, "photo_title": "Bergbach", "photo_url": "http://www.panoramio.com/photo/36476", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36476.jpg", "longitude": 13.911953, "latitude": 47.634164, "width": 375, "height": 500, "upload_date": "02 August 2006", "owner_id": 5703, "owner_name": "dancer", "owner_url": "http://www.panoramio.com/user/5703"} +, +{"photo_id": 436366, "photo_title": "sunset", "photo_url": "http://www.panoramio.com/photo/436366", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436366.jpg", "longitude": 138.857231, "latitude": 37.828497, "width": 500, "height": 351, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 701842, "photo_title": "Singapore Skyline @ Night", "photo_url": "http://www.panoramio.com/photo/701842", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/701842.jpg", "longitude": 103.855486, "latitude": 1.288897, "width": 500, "height": 324, "upload_date": "05 February 2007", "owner_id": 20398, "owner_name": "boerx", "owner_url": "http://www.panoramio.com/user/20398"} +, +{"photo_id": 6086623, "photo_title": "Lángoló repce", "photo_url": "http://www.panoramio.com/photo/6086623", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6086623.jpg", "longitude": 17.784977, "latitude": 47.660994, "width": 500, "height": 334, "upload_date": "23 November 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1595617, "photo_title": "Rosina lamberti,Templestowe,Victoria,Australia", "photo_url": "http://www.panoramio.com/photo/1595617", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1595617.jpg", "longitude": 145.137978, "latitude": -37.774785, "width": 500, "height": 354, "upload_date": "02 April 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 74727, "photo_title": "ama dablam in background", "photo_url": "http://www.panoramio.com/photo/74727", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/74727.jpg", "longitude": 86.826496, "latitude": 27.904631, "width": 500, "height": 334, "upload_date": "02 November 2006", "owner_id": 9812, "owner_name": "wsm earp", "owner_url": "http://www.panoramio.com/user/9812"} +, +{"photo_id": 36086, "photo_title": "Рим. двор Ватикана", "photo_url": "http://www.panoramio.com/photo/36086", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36086.jpg", "longitude": 12.454505, "latitude": 41.905695, "width": 500, "height": 444, "upload_date": "31 July 2006", "owner_id": 5641, "owner_name": "sergey duhanin", "owner_url": "http://www.panoramio.com/user/5641"} +, +{"photo_id": 2066940, "photo_title": "Unbelievable ice sculptures", "photo_url": "http://www.panoramio.com/photo/2066940", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2066940.jpg", "longitude": -73.264389, "latitude": -50.009063, "width": 500, "height": 333, "upload_date": "04 May 2007", "owner_id": 3316, "owner_name": "kristine hannon (www.traveltheglobe.be)", "owner_url": "http://www.panoramio.com/user/3316"} +, +{"photo_id": 1759754, "photo_title": "On the way for the heat wave", "photo_url": "http://www.panoramio.com/photo/1759754", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1759754.jpg", "longitude": -12.734528, "latitude": 20.208079, "width": 500, "height": 331, "upload_date": "13 April 2007", "owner_id": 121377, "owner_name": "Philippe Buffard", "owner_url": "http://www.panoramio.com/user/121377"} +, +{"photo_id": 5717808, "photo_title": "Moonlight @ Eglisau", "photo_url": "http://www.panoramio.com/photo/5717808", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5717808.jpg", "longitude": 8.521459, "latitude": 47.575035, "width": 500, "height": 331, "upload_date": "05 November 2007", "owner_id": 436351, "owner_name": "Sunpixx", "owner_url": "http://www.panoramio.com/user/436351"} +, +{"photo_id": 44853, "photo_title": "Airfocus20050501DSC_3416l", "photo_url": "http://www.panoramio.com/photo/44853", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/44853.jpg", "longitude": 7.663361, "latitude": 50.287009, "width": 500, "height": 332, "upload_date": "02 September 2006", "owner_id": 6703, "owner_name": "Peter Jansen", "owner_url": "http://www.panoramio.com/user/6703"} +, +{"photo_id": 57403, "photo_title": "Burano 2", "photo_url": "http://www.panoramio.com/photo/57403", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57403.jpg", "longitude": 12.420173, "latitude": 45.485365, "width": 500, "height": 331, "upload_date": "04 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 13130, "photo_title": "Agde - Painted wall", "photo_url": "http://www.panoramio.com/photo/13130", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/13130.jpg", "longitude": 3.471251, "latitude": 43.312314, "width": 500, "height": 375, "upload_date": "25 February 2006", "owner_id": 1981, "owner_name": "Eric Medvet", "owner_url": "http://www.panoramio.com/user/1981"} +, +{"photo_id": 7375236, "photo_title": "le Loir en crue à Briollay, janvier 2008. #276", "photo_url": "http://www.panoramio.com/photo/7375236", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7375236.jpg", "longitude": -0.500618, "latitude": 47.557827, "width": 500, "height": 338, "upload_date": "26 January 2008", "owner_id": 666755, "owner_name": "Armagnac", "owner_url": "http://www.panoramio.com/user/666755"} +, +{"photo_id": 3851701, "photo_title": "Mailbox", "photo_url": "http://www.panoramio.com/photo/3851701", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3851701.jpg", "longitude": -73.475790, "latitude": 44.528271, "width": 500, "height": 333, "upload_date": "10 August 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 1235904, "photo_title": "Ripples", "photo_url": "http://www.panoramio.com/photo/1235904", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1235904.jpg", "longitude": -131.616211, "latitude": 52.834299, "width": 330, "height": 500, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 50646, "photo_title": "Ice Cave", "photo_url": "http://www.panoramio.com/photo/50646", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/50646.jpg", "longitude": -118.052559, "latitude": 52.678620, "width": 500, "height": 375, "upload_date": "21 September 2006", "owner_id": 7190, "owner_name": "Perry Tang", "owner_url": "http://www.panoramio.com/user/7190"} +, +{"photo_id": 617458, "photo_title": "Pescador", "photo_url": "http://www.panoramio.com/photo/617458", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/617458.jpg", "longitude": 0.492368, "latitude": 40.904091, "width": 500, "height": 334, "upload_date": "29 January 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 52724, "photo_title": "Sunrise Gythio", "photo_url": "http://www.panoramio.com/photo/52724", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/52724.jpg", "longitude": 22.574501, "latitude": 36.755665, "width": 500, "height": 333, "upload_date": "26 September 2006", "owner_id": 7464, "owner_name": "Pieter", "owner_url": "http://www.panoramio.com/user/7464"} +, +{"photo_id": 289855, "photo_title": "Coronation Island Colours", "photo_url": "http://www.panoramio.com/photo/289855", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/289855.jpg", "longitude": -45.703125, "latitude": -60.705448, "width": 500, "height": 335, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 5649263, "photo_title": "Naab im Herbst", "photo_url": "http://www.panoramio.com/photo/5649263", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5649263.jpg", "longitude": 12.070885, "latitude": 49.298711, "width": 500, "height": 329, "upload_date": "31 October 2007", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 110750, "photo_title": "The Peter and Paul Fortress. Panoramic view (180°) from The Palace Quay. — Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ (180°) панорама ПетропавловÑкой крепоÑти Ñ Ð”Ð²Ð¾Ñ€Ñ†Ð¾Ð²Ð¾Ð¹ набережной.", "photo_url": "http://www.panoramio.com/photo/110750", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/110750.jpg", "longitude": 30.317802, "latitude": 59.946930, "width": 500, "height": 31, "upload_date": "11 December 2006", "owner_id": 12103, "owner_name": "Roman Sobolenko", "owner_url": "http://www.panoramio.com/user/12103"} +, +{"photo_id": 1870028, "photo_title": "Tour Moretti", "photo_url": "http://www.panoramio.com/photo/1870028", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1870028.jpg", "longitude": 2.247775, "latitude": 48.889175, "width": 500, "height": 395, "upload_date": "21 April 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 52752, "photo_title": "Sun and Clouds in Naphlion", "photo_url": "http://www.panoramio.com/photo/52752", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/52752.jpg", "longitude": 22.792425, "latitude": 37.562405, "width": 333, "height": 500, "upload_date": "26 September 2006", "owner_id": 7464, "owner_name": "Pieter", "owner_url": "http://www.panoramio.com/user/7464"} +, +{"photo_id": 2256672, "photo_title": "En algún punto", "photo_url": "http://www.panoramio.com/photo/2256672", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2256672.jpg", "longitude": -2.579153, "latitude": 42.493436, "width": 500, "height": 331, "upload_date": "17 May 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 519209, "photo_title": "Armageddon", "photo_url": "http://www.panoramio.com/photo/519209", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/519209.jpg", "longitude": 17.627563, "latitude": 47.664809, "width": 500, "height": 334, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 10175554, "photo_title": "Vessel to eternity", "photo_url": "http://www.panoramio.com/photo/10175554", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10175554.jpg", "longitude": 119.670467, "latitude": 11.089976, "width": 500, "height": 363, "upload_date": "13 May 2008", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 11138384, "photo_title": "Lac des Joncs, reflets", "photo_url": "http://www.panoramio.com/photo/11138384", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11138384.jpg", "longitude": 6.946986, "latitude": 46.513176, "width": 500, "height": 375, "upload_date": "12 June 2008", "owner_id": 1430484, "owner_name": "tiopepe8", "owner_url": "http://www.panoramio.com/user/1430484"} +, +{"photo_id": 204255, "photo_title": "Old farm by Osafjorden", "photo_url": "http://www.panoramio.com/photo/204255", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/204255.jpg", "longitude": 6.998978, "latitude": 60.564197, "width": 500, "height": 368, "upload_date": "21 December 2006", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 3871571, "photo_title": "St. Bartholomä am Königssee", "photo_url": "http://www.panoramio.com/photo/3871571", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3871571.jpg", "longitude": 12.973351, "latitude": 47.545220, "width": 500, "height": 375, "upload_date": "11 August 2007", "owner_id": 424589, "owner_name": "PeSchn", "owner_url": "http://www.panoramio.com/user/424589"} +, +{"photo_id": 5358166, "photo_title": "Mooney Falls", "photo_url": "http://www.panoramio.com/photo/5358166", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5358166.jpg", "longitude": -112.709148, "latitude": 36.262849, "width": 500, "height": 335, "upload_date": "16 October 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 600797, "photo_title": "Living (?) in Hong Kong", "photo_url": "http://www.panoramio.com/photo/600797", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/600797.jpg", "longitude": 113.935831, "latitude": 22.279794, "width": 500, "height": 334, "upload_date": "28 January 2007", "owner_id": 20398, "owner_name": "boerx", "owner_url": "http://www.panoramio.com/user/20398"} +, +{"photo_id": 6459385, "photo_title": "Alternativ Future", "photo_url": "http://www.panoramio.com/photo/6459385", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6459385.jpg", "longitude": 17.598467, "latitude": 47.645846, "width": 500, "height": 325, "upload_date": "13 December 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 522010, "photo_title": "Hyperion", "photo_url": "http://www.panoramio.com/photo/522010", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/522010.jpg", "longitude": 17.562933, "latitude": 47.632545, "width": 500, "height": 353, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4942642, "photo_title": "Förgeteg elött", "photo_url": "http://www.panoramio.com/photo/4942642", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4942642.jpg", "longitude": 17.807121, "latitude": 47.646887, "width": 500, "height": 334, "upload_date": "27 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 223798, "photo_title": "Kachemak Bay Moonrise", "photo_url": "http://www.panoramio.com/photo/223798", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/223798.jpg", "longitude": -151.426835, "latitude": 59.680146, "width": 500, "height": 333, "upload_date": "24 December 2006", "owner_id": 45308, "owner_name": "Mike Cavaroc", "owner_url": "http://www.panoramio.com/user/45308"} +, +{"photo_id": 1946961, "photo_title": "Három \"Grácia\"", "photo_url": "http://www.panoramio.com/photo/1946961", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1946961.jpg", "longitude": 18.273354, "latitude": 47.577684, "width": 500, "height": 290, "upload_date": "27 April 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 821342, "photo_title": "Northern Lights seen from Alta", "photo_url": "http://www.panoramio.com/photo/821342", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/821342.jpg", "longitude": 23.234882, "latitude": 69.962969, "width": 500, "height": 346, "upload_date": "14 February 2007", "owner_id": 56091, "owner_name": "Kjetil Vaage Øie", "owner_url": "http://www.panoramio.com/user/56091"} +, +{"photo_id": 9831100, "photo_title": "Repcepásztor", "photo_url": "http://www.panoramio.com/photo/9831100", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9831100.jpg", "longitude": 18.213100, "latitude": 47.567956, "width": 500, "height": 334, "upload_date": "01 May 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8294907, "photo_title": "Winds of Change", "photo_url": "http://www.panoramio.com/photo/8294907", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8294907.jpg", "longitude": -112.007847, "latitude": 36.993299, "width": 333, "height": 500, "upload_date": "04 March 2008", "owner_id": 107292, "owner_name": "Kevin Mikkelsen", "owner_url": "http://www.panoramio.com/user/107292"} +, +{"photo_id": 7388668, "photo_title": "jak dobrze wstać ...", "photo_url": "http://www.panoramio.com/photo/7388668", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7388668.jpg", "longitude": 15.746498, "latitude": 51.848929, "width": 500, "height": 353, "upload_date": "27 January 2008", "owner_id": 889535, "owner_name": "yossarian01", "owner_url": "http://www.panoramio.com/user/889535"} +, +{"photo_id": 617471, "photo_title": "Rio", "photo_url": "http://www.panoramio.com/photo/617471", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/617471.jpg", "longitude": 0.493505, "latitude": 40.904318, "width": 500, "height": 335, "upload_date": "29 January 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 259612, "photo_title": "Miss Liberty, NY/NJ Harbor", "photo_url": "http://www.panoramio.com/photo/259612", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/259612.jpg", "longitude": -74.039698, "latitude": 40.687472, "width": 357, "height": 500, "upload_date": "29 December 2006", "owner_id": 52440, "owner_name": "Hank Waxman", "owner_url": "http://www.panoramio.com/user/52440"} +, +{"photo_id": 2282545, "photo_title": "San Remo Scorcio di San Siro", "photo_url": "http://www.panoramio.com/photo/2282545", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2282545.jpg", "longitude": 7.773911, "latitude": 43.818234, "width": 500, "height": 459, "upload_date": "18 May 2007", "owner_id": 60898, "owner_name": "esseil", "owner_url": "http://www.panoramio.com/user/60898"} +, +{"photo_id": 84795, "photo_title": "0032", "photo_url": "http://www.panoramio.com/photo/84795", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/84795.jpg", "longitude": 25.830574, "latitude": -20.889688, "width": 500, "height": 334, "upload_date": "22 November 2006", "owner_id": 10637, "owner_name": "Carles Campsolinas Dresaire", "owner_url": "http://www.panoramio.com/user/10637"} +, +{"photo_id": 6205, "photo_title": "Valencia III", "photo_url": "http://www.panoramio.com/photo/6205", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6205.jpg", "longitude": -0.352764, "latitude": 39.456143, "width": 500, "height": 375, "upload_date": "28 December 2005", "owner_id": 414, "owner_name": "Sonia Villegas", "owner_url": "http://www.panoramio.com/user/414"} +, +{"photo_id": 5255997, "photo_title": "Az alkonyvigyázó", "photo_url": "http://www.panoramio.com/photo/5255997", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5255997.jpg", "longitude": 17.417107, "latitude": 46.942762, "width": 500, "height": 334, "upload_date": "12 October 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4214336, "photo_title": "船家 ship On Li river", "photo_url": "http://www.panoramio.com/photo/4214336", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4214336.jpg", "longitude": 110.342388, "latitude": 25.215347, "width": 500, "height": 313, "upload_date": "26 August 2007", "owner_id": 161470, "owner_name": "John Su", "owner_url": "http://www.panoramio.com/user/161470"} +, +{"photo_id": 611660, "photo_title": "Tikehau Ile aux oiseaux JC", "photo_url": "http://www.panoramio.com/photo/611660", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/611660.jpg", "longitude": -148.098224, "latitude": -14.974528, "width": 375, "height": 500, "upload_date": "29 January 2007", "owner_id": 131113, "owner_name": "Lair Jean Claude", "owner_url": "http://www.panoramio.com/user/131113"} +, +{"photo_id": 9822041, "photo_title": "Singapore", "photo_url": "http://www.panoramio.com/photo/9822041", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9822041.jpg", "longitude": 103.855219, "latitude": 1.288907, "width": 500, "height": 333, "upload_date": "01 May 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 126820, "photo_title": "Taj Mahal - colores", "photo_url": "http://www.panoramio.com/photo/126820", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/126820.jpg", "longitude": 78.042165, "latitude": 27.172871, "width": 500, "height": 385, "upload_date": "12 December 2006", "owner_id": 10456, "owner_name": "eulogio", "owner_url": "http://www.panoramio.com/user/10456"} +, +{"photo_id": 112504, "photo_title": "V-01009", "photo_url": "http://www.panoramio.com/photo/112504", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/112504.jpg", "longitude": 12.335946, "latitude": 45.438213, "width": 500, "height": 500, "upload_date": "11 December 2006", "owner_id": 17599, "owner_name": "Dmitry Andreev", "owner_url": "http://www.panoramio.com/user/17599"} +, +{"photo_id": 1898139, "photo_title": "Ein sehr menschenähnlicher Baum (http://www.redbubble.com/products/configure/1935618)", "photo_url": "http://www.panoramio.com/photo/1898139", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1898139.jpg", "longitude": 13.158177, "latitude": 52.456836, "width": 375, "height": 500, "upload_date": "23 April 2007", "owner_id": 311327, "owner_name": "www.einkauf.tk", "owner_url": "http://www.panoramio.com/user/311327"} +, +{"photo_id": 57813, "photo_title": "Hallstatt 1", "photo_url": "http://www.panoramio.com/photo/57813", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57813.jpg", "longitude": 13.652229, "latitude": 47.551274, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 533476, "photo_title": "Comet McNaught 220107 02", "photo_url": "http://www.panoramio.com/photo/533476", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/533476.jpg", "longitude": 18.371286, "latitude": -33.964363, "width": 328, "height": 500, "upload_date": "22 January 2007", "owner_id": 2748, "owner_name": "WirelessMonkey", "owner_url": "http://www.panoramio.com/user/2748"} +, +{"photo_id": 507370, "photo_title": "The Silence", "photo_url": "http://www.panoramio.com/photo/507370", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507370.jpg", "longitude": 17.497959, "latitude": 47.781328, "width": 465, "height": 500, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2422269, "photo_title": "Grand Trees", "photo_url": "http://www.panoramio.com/photo/2422269", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2422269.jpg", "longitude": -112.124019, "latitude": 36.062942, "width": 500, "height": 333, "upload_date": "27 May 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 2808348, "photo_title": "Blind River reflection", "photo_url": "http://www.panoramio.com/photo/2808348", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2808348.jpg", "longitude": -82.973557, "latitude": 46.193141, "width": 500, "height": 305, "upload_date": "18 June 2007", "owner_id": 555551, "owner_name": "Marilyn Whiteley", "owner_url": "http://www.panoramio.com/user/555551"} +, +{"photo_id": 2534183, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/2534183", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2534183.jpg", "longitude": -69.934587, "latitude": -37.382844, "width": 500, "height": 335, "upload_date": "02 June 2007", "owner_id": 527160, "owner_name": "legui83", "owner_url": "http://www.panoramio.com/user/527160"} +, +{"photo_id": 1008446, "photo_title": "budamist", "photo_url": "http://www.panoramio.com/photo/1008446", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1008446.jpg", "longitude": 19.078649, "latitude": 47.516737, "width": 500, "height": 341, "upload_date": "24 February 2007", "owner_id": 2659, "owner_name": "ozalph", "owner_url": "http://www.panoramio.com/user/2659"} +, +{"photo_id": 2935385, "photo_title": "temporale sul mare di riccione", "photo_url": "http://www.panoramio.com/photo/2935385", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2935385.jpg", "longitude": 12.644491, "latitude": 43.964836, "width": 333, "height": 500, "upload_date": "25 June 2007", "owner_id": 267377, "owner_name": "Valter Galvani", "owner_url": "http://www.panoramio.com/user/267377"} +, +{"photo_id": 7586398, "photo_title": "Al vuelo", "photo_url": "http://www.panoramio.com/photo/7586398", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7586398.jpg", "longitude": -73.152337, "latitude": -37.114747, "width": 375, "height": 500, "upload_date": "04 February 2008", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 7624042, "photo_title": "Fairyland 11", "photo_url": "http://www.panoramio.com/photo/7624042", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7624042.jpg", "longitude": 6.067650, "latitude": 52.224684, "width": 352, "height": 500, "upload_date": "06 February 2008", "owner_id": 523564, "owner_name": "Luud Riphagen", "owner_url": "http://www.panoramio.com/user/523564"} +, +{"photo_id": 1186930, "photo_title": "Вид Ñ Ð³Ð¾Ñ€Ñ‹ Демерджи - Demergi mountain view", "photo_url": "http://www.panoramio.com/photo/1186930", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1186930.jpg", "longitude": 34.413729, "latitude": 44.749903, "width": 500, "height": 338, "upload_date": "05 March 2007", "owner_id": 244932, "owner_name": "Andrey Jitkov", "owner_url": "http://www.panoramio.com/user/244932"} +, +{"photo_id": 565512, "photo_title": "The staircase star", "photo_url": "http://www.panoramio.com/photo/565512", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/565512.jpg", "longitude": 5.646222, "latitude": 46.261262, "width": 500, "height": 331, "upload_date": "25 January 2007", "owner_id": 121377, "owner_name": "Philippe Buffard", "owner_url": "http://www.panoramio.com/user/121377"} +, +{"photo_id": 3566705, "photo_title": "Pattaya - Big Buddha and seven headed Naga", "photo_url": "http://www.panoramio.com/photo/3566705", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3566705.jpg", "longitude": 100.868155, "latitude": 12.915027, "width": 500, "height": 375, "upload_date": "28 July 2007", "owner_id": 716245, "owner_name": "—Dragon-64— ✈", "owner_url": "http://www.panoramio.com/user/716245"} +, +{"photo_id": 50113, "photo_title": "New York Skyline Panorama", "photo_url": "http://www.panoramio.com/photo/50113", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/50113.jpg", "longitude": -73.997775, "latitude": 40.696581, "width": 500, "height": 55, "upload_date": "20 September 2006", "owner_id": 4957, "owner_name": "Ken Gibson", "owner_url": "http://www.panoramio.com/user/4957"} +, +{"photo_id": 74726, "photo_title": "nuptse 1 sunset", "photo_url": "http://www.panoramio.com/photo/74726", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/74726.jpg", "longitude": 86.865978, "latitude": 27.979243, "width": 500, "height": 334, "upload_date": "02 November 2006", "owner_id": 9812, "owner_name": "wsm earp", "owner_url": "http://www.panoramio.com/user/9812"} +, +{"photo_id": 10552400, "photo_title": "Second Prize \"Travel\" May Contest, HDR, May 2008", "photo_url": "http://www.panoramio.com/photo/10552400", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10552400.jpg", "longitude": -3.705075, "latitude": 47.787960, "width": 500, "height": 333, "upload_date": "24 May 2008", "owner_id": 979901, "owner_name": "DiggaTwigga", "owner_url": "http://www.panoramio.com/user/979901"} +, +{"photo_id": 1605229, "photo_title": "Holdfényáhítat", "photo_url": "http://www.panoramio.com/photo/1605229", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1605229.jpg", "longitude": 17.748413, "latitude": 47.555214, "width": 400, "height": 500, "upload_date": "02 April 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 34669, "photo_title": "Paisaje otoñal - La Rioja - España", "photo_url": "http://www.panoramio.com/photo/34669", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/34669.jpg", "longitude": -2.864685, "latitude": 42.328664, "width": 500, "height": 326, "upload_date": "26 July 2006", "owner_id": 5487, "owner_name": "Joaquín Ramirez", "owner_url": "http://www.panoramio.com/user/5487"} +, +{"photo_id": 4596134, "photo_title": "Le vieux Nice, mars 2007", "photo_url": "http://www.panoramio.com/photo/4596134", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4596134.jpg", "longitude": 7.277198, "latitude": 43.696704, "width": 368, "height": 500, "upload_date": "12 September 2007", "owner_id": 629243, "owner_name": "Olivier Faugeras", "owner_url": "http://www.panoramio.com/user/629243"} +, +{"photo_id": 10576294, "photo_title": "Plaza de Bolívar, Bogotá. 1st. prize Panoramio Contest, May 08.(((Jose Daniel)))", "photo_url": "http://www.panoramio.com/photo/10576294", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10576294.jpg", "longitude": -74.075629, "latitude": 4.597867, "width": 500, "height": 338, "upload_date": "25 May 2008", "owner_id": 1611883, "owner_name": "(((Jose Daniel)))", "owner_url": "http://www.panoramio.com/user/1611883"} +, +{"photo_id": 522151, "photo_title": "Jó volt ott", "photo_url": "http://www.panoramio.com/photo/522151", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/522151.jpg", "longitude": 17.611084, "latitude": 47.602401, "width": 500, "height": 354, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4247476, "photo_title": "Blick vom Zuckerhut", "photo_url": "http://www.panoramio.com/photo/4247476", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4247476.jpg", "longitude": -43.156872, "latitude": -22.948909, "width": 500, "height": 375, "upload_date": "28 August 2007", "owner_id": 496676, "owner_name": "Quasebart", "owner_url": "http://www.panoramio.com/user/496676"} +, +{"photo_id": 5472461, "photo_title": "Lapland", "photo_url": "http://www.panoramio.com/photo/5472461", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5472461.jpg", "longitude": 29.187653, "latitude": 66.189241, "width": 500, "height": 327, "upload_date": "22 October 2007", "owner_id": 912031, "owner_name": "Kimmo Lyytikäinen", "owner_url": "http://www.panoramio.com/user/912031"} +, +{"photo_id": 472802, "photo_title": "Golden Gate Bridge", "photo_url": "http://www.panoramio.com/photo/472802", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/472802.jpg", "longitude": -122.481366, "latitude": 37.827644, "width": 500, "height": 305, "upload_date": "18 January 2007", "owner_id": 100907, "owner_name": "Julia Wahl", "owner_url": "http://www.panoramio.com/user/100907"} +, +{"photo_id": 506118, "photo_title": "Overcast Pier, Hearst State Beach", "photo_url": "http://www.panoramio.com/photo/506118", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/506118.jpg", "longitude": -121.187868, "latitude": 35.643016, "width": 500, "height": 343, "upload_date": "20 January 2007", "owner_id": 107613, "owner_name": "Tom Grubbe", "owner_url": "http://www.panoramio.com/user/107613"} +, +{"photo_id": 1420841, "photo_title": "Poland ", "photo_url": "http://www.panoramio.com/photo/1420841", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1420841.jpg", "longitude": 20.630060, "latitude": 52.073123, "width": 500, "height": 377, "upload_date": "20 March 2007", "owner_id": 234038, "owner_name": "Jacek M.", "owner_url": "http://www.panoramio.com/user/234038"} +, +{"photo_id": 4088401, "photo_title": "Bird at Hogsback - 198812", "photo_url": "http://www.panoramio.com/photo/4088401", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4088401.jpg", "longitude": -124.339828, "latitude": 47.440860, "width": 500, "height": 355, "upload_date": "21 August 2007", "owner_id": 765658, "owner_name": "Larry Workman QIN", "owner_url": "http://www.panoramio.com/user/765658"} +, +{"photo_id": 8049018, "photo_title": "Eastern Sierra Sunset", "photo_url": "http://www.panoramio.com/photo/8049018", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8049018.jpg", "longitude": -119.220543, "latitude": 38.031698, "width": 500, "height": 333, "upload_date": "23 February 2008", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 103324, "photo_title": "Lua em São Paulo", "photo_url": "http://www.panoramio.com/photo/103324", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/103324.jpg", "longitude": -46.652606, "latitude": -23.545394, "width": 500, "height": 333, "upload_date": "10 December 2006", "owner_id": 14733, "owner_name": "Luiz Henrique Assunção", "owner_url": "http://www.panoramio.com/user/14733"} +, +{"photo_id": 5694626, "photo_title": "Lake of Varese - Moon and Venus before dawn", "photo_url": "http://www.panoramio.com/photo/5694626", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5694626.jpg", "longitude": 8.717716, "latitude": 45.839025, "width": 339, "height": 500, "upload_date": "02 November 2007", "owner_id": 933456, "owner_name": "© Marco De Candido", "owner_url": "http://www.panoramio.com/user/933456"} +, +{"photo_id": 1235876, "photo_title": "Logs on Lake Moraine", "photo_url": "http://www.panoramio.com/photo/1235876", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1235876.jpg", "longitude": -116.180420, "latitude": 51.326321, "width": 330, "height": 500, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 6999770, "photo_title": "Mountain range of Pindos", "photo_url": "http://www.panoramio.com/photo/6999770", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6999770.jpg", "longitude": 21.553481, "latitude": 39.498345, "width": 500, "height": 333, "upload_date": "09 January 2008", "owner_id": 242446, "owner_name": "Ntinos Lagos", "owner_url": "http://www.panoramio.com/user/242446"} +, +{"photo_id": 405727, "photo_title": "awagatake", "photo_url": "http://www.panoramio.com/photo/405727", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405727.jpg", "longitude": 139.042454, "latitude": 37.563222, "width": 500, "height": 380, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1488363, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/1488363", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1488363.jpg", "longitude": 138.454514, "latitude": 38.308932, "width": 500, "height": 384, "upload_date": "25 March 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 841001, "photo_title": "Central Balkan", "photo_url": "http://www.panoramio.com/photo/841001", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/841001.jpg", "longitude": 24.963917, "latitude": 42.679306, "width": 500, "height": 357, "upload_date": "16 February 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 57406, "photo_title": "Burano 4", "photo_url": "http://www.panoramio.com/photo/57406", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57406.jpg", "longitude": 12.419465, "latitude": 45.484567, "width": 500, "height": 333, "upload_date": "04 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 1900891, "photo_title": "Peggys Cove, Nova Scotia La barca ...", "photo_url": "http://www.panoramio.com/photo/1900891", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1900891.jpg", "longitude": -63.918285, "latitude": 44.490873, "width": 375, "height": 500, "upload_date": "24 April 2007", "owner_id": 401966, "owner_name": "Syl de Canada", "owner_url": "http://www.panoramio.com/user/401966"} +, +{"photo_id": 2135721, "photo_title": " Coteau Landing (près de Valleyfield 3)", "photo_url": "http://www.panoramio.com/photo/2135721", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2135721.jpg", "longitude": -74.211960, "latitude": 45.253622, "width": 500, "height": 375, "upload_date": "08 May 2007", "owner_id": 401966, "owner_name": "Syl de Canada", "owner_url": "http://www.panoramio.com/user/401966"} +, +{"photo_id": 426155, "photo_title": "2007'01'14-Aucanada-0233", "photo_url": "http://www.panoramio.com/photo/426155", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/426155.jpg", "longitude": 3.169695, "latitude": 39.837627, "width": 500, "height": 335, "upload_date": "14 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 4868548, "photo_title": "Goodbye my dear", "photo_url": "http://www.panoramio.com/photo/4868548", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4868548.jpg", "longitude": 16.693211, "latitude": 43.183025, "width": 500, "height": 500, "upload_date": "24 September 2007", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 47069, "photo_title": "Laguna del Inca", "photo_url": "http://www.panoramio.com/photo/47069", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/47069.jpg", "longitude": -70.130786, "latitude": -32.834759, "width": 500, "height": 333, "upload_date": "11 September 2006", "owner_id": 6961, "owner_name": "Santiago Rios", "owner_url": "http://www.panoramio.com/user/6961"} +, +{"photo_id": 1781731, "photo_title": "The Subway", "photo_url": "http://www.panoramio.com/photo/1781731", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781731.jpg", "longitude": -113.052578, "latitude": 37.310448, "width": 500, "height": 333, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 2279, "photo_title": "Empire State Building", "photo_url": "http://www.panoramio.com/photo/2279", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2279.jpg", "longitude": -73.987073, "latitude": 40.744924, "width": 378, "height": 500, "upload_date": "08 October 2005", "owner_id": 220, "owner_name": "Jeff T. Alu", "owner_url": "http://www.panoramio.com/user/220"} +, +{"photo_id": 1277992, "photo_title": "Cologne-Köln - Dom im Hintergrund der Hohenzollernbrücke bei Nacht (by night)", "photo_url": "http://www.panoramio.com/photo/1277992", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1277992.jpg", "longitude": 6.967220, "latitude": 50.940826, "width": 500, "height": 375, "upload_date": "11 March 2007", "owner_id": 113678, "owner_name": "Canada-Fan", "owner_url": "http://www.panoramio.com/user/113678"} +, +{"photo_id": 207638, "photo_title": "Sunrise at Mont Saint Michel (1 of 2), august 2001", "photo_url": "http://www.panoramio.com/photo/207638", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/207638.jpg", "longitude": -1.509504, "latitude": 48.633547, "width": 331, "height": 500, "upload_date": "21 December 2006", "owner_id": 18925, "owner_name": "Marco Ferrari", "owner_url": "http://www.panoramio.com/user/18925"} +, +{"photo_id": 1452569, "photo_title": "Desierto de La Tatacoa (zona roja)", "photo_url": "http://www.panoramio.com/photo/1452569", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1452569.jpg", "longitude": -75.166667, "latitude": 3.333333, "width": 500, "height": 333, "upload_date": "22 March 2007", "owner_id": 5487, "owner_name": "Joaquín Ramirez", "owner_url": "http://www.panoramio.com/user/5487"} +, +{"photo_id": 3502890, "photo_title": "Monasteries in Meteora", "photo_url": "http://www.panoramio.com/photo/3502890", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3502890.jpg", "longitude": 21.627445, "latitude": 39.712601, "width": 480, "height": 500, "upload_date": "24 July 2007", "owner_id": 686703, "owner_name": "Thodoris Kliafas", "owner_url": "http://www.panoramio.com/user/686703"} +, +{"photo_id": 595505, "photo_title": "Burlington_Village_Square", "photo_url": "http://www.panoramio.com/photo/595505", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/595505.jpg", "longitude": -79.796180, "latitude": 43.326192, "width": 500, "height": 333, "upload_date": "27 January 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 60984, "photo_title": "Ventisquero P. Moreno", "photo_url": "http://www.panoramio.com/photo/60984", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/60984.jpg", "longitude": -73.051872, "latitude": -50.488641, "width": 500, "height": 328, "upload_date": "13 October 2006", "owner_id": 8409, "owner_name": "Hector Fabian Garrido", "owner_url": "http://www.panoramio.com/user/8409"} +, +{"photo_id": 6654030, "photo_title": "Va por un incomprendido Vincent Willem van Gogh", "photo_url": "http://www.panoramio.com/photo/6654030", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6654030.jpg", "longitude": 4.776306, "latitude": 51.477962, "width": 500, "height": 375, "upload_date": "24 December 2007", "owner_id": 804986, "owner_name": "VERJAGA", "owner_url": "http://www.panoramio.com/user/804986"} +, +{"photo_id": 3018575, "photo_title": "Abrasado", "photo_url": "http://www.panoramio.com/photo/3018575", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3018575.jpg", "longitude": -73.279324, "latitude": -39.838002, "width": 500, "height": 375, "upload_date": "29 June 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 521039, "photo_title": "Fátyolos narancslátomás", "photo_url": "http://www.panoramio.com/photo/521039", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/521039.jpg", "longitude": 17.463455, "latitude": 47.850146, "width": 500, "height": 291, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 208239, "photo_title": "Nuvola danzante, Svizzera 2002", "photo_url": "http://www.panoramio.com/photo/208239", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/208239.jpg", "longitude": 7.321701, "latitude": 46.219515, "width": 334, "height": 500, "upload_date": "22 December 2006", "owner_id": 18925, "owner_name": "Marco Ferrari", "owner_url": "http://www.panoramio.com/user/18925"} +, +{"photo_id": 6443936, "photo_title": "Pajkos vizek", "photo_url": "http://www.panoramio.com/photo/6443936", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6443936.jpg", "longitude": 15.934124, "latitude": 47.915019, "width": 500, "height": 334, "upload_date": "12 December 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 7467941, "photo_title": "A day off for the soul...", "photo_url": "http://www.panoramio.com/photo/7467941", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7467941.jpg", "longitude": -75.126133, "latitude": 40.970106, "width": 500, "height": 375, "upload_date": "30 January 2008", "owner_id": 89499, "owner_name": "Michael Braxenthaler", "owner_url": "http://www.panoramio.com/user/89499"} +, +{"photo_id": 800436, "photo_title": "Eiffel Tower", "photo_url": "http://www.panoramio.com/photo/800436", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/800436.jpg", "longitude": 2.294576, "latitude": 48.858249, "width": 500, "height": 386, "upload_date": "13 February 2007", "owner_id": 165346, "owner_name": "Alan Knox", "owner_url": "http://www.panoramio.com/user/165346"} +, +{"photo_id": 479673, "photo_title": "Summit of Gogsøyra", "photo_url": "http://www.panoramio.com/photo/479673", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/479673.jpg", "longitude": 8.147736, "latitude": 62.642606, "width": 500, "height": 333, "upload_date": "18 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 5378753, "photo_title": "Alps", "photo_url": "http://www.panoramio.com/photo/5378753", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5378753.jpg", "longitude": 6.847916, "latitude": 45.913840, "width": 500, "height": 500, "upload_date": "17 October 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 382413, "photo_title": "kilimanjaro sunset", "photo_url": "http://www.panoramio.com/photo/382413", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/382413.jpg", "longitude": 37.382355, "latitude": -3.046583, "width": 500, "height": 375, "upload_date": "11 January 2007", "owner_id": 6105, "owner_name": "hackltom", "owner_url": "http://www.panoramio.com/user/6105"} +, +{"photo_id": 290784, "photo_title": "Tormenta Bahía de Pollensa", "photo_url": "http://www.panoramio.com/photo/290784", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/290784.jpg", "longitude": 3.116437, "latitude": 39.928440, "width": 500, "height": 285, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 519904, "photo_title": "Dombok között felhÅ‘k alatt", "photo_url": "http://www.panoramio.com/photo/519904", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/519904.jpg", "longitude": 18.680878, "latitude": 47.631851, "width": 500, "height": 314, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 181264, "photo_title": "deer cave", "photo_url": "http://www.panoramio.com/photo/181264", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/181264.jpg", "longitude": 114.824553, "latitude": 4.024121, "width": 428, "height": 500, "upload_date": "18 December 2006", "owner_id": 9198, "owner_name": "Caveranger", "owner_url": "http://www.panoramio.com/user/9198"} +, +{"photo_id": 323533, "photo_title": "Elevador e Mercado Modelo Ssa Ba Br", "photo_url": "http://www.panoramio.com/photo/323533", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/323533.jpg", "longitude": -38.512552, "latitude": -12.974261, "width": 500, "height": 333, "upload_date": "06 January 2007", "owner_id": 63291, "owner_name": "Gastón Dapik", "owner_url": "http://www.panoramio.com/user/63291"} +, +{"photo_id": 512513, "photo_title": "Égi tűz", "photo_url": "http://www.panoramio.com/photo/512513", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/512513.jpg", "longitude": 17.481308, "latitude": 47.796148, "width": 500, "height": 334, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 10237287, "photo_title": "Kentriki's Woods, by Kostas Andreopoulos", "photo_url": "http://www.panoramio.com/photo/10237287", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10237287.jpg", "longitude": 21.916909, "latitude": 38.569223, "width": 500, "height": 375, "upload_date": "14 May 2008", "owner_id": 1690483, "owner_name": "k.andre", "owner_url": "http://www.panoramio.com/user/1690483"} +, +{"photo_id": 52847, "photo_title": "153 The Forth Bridge (Railway) over the Firth of Forth", "photo_url": "http://www.panoramio.com/photo/52847", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/52847.jpg", "longitude": -3.392672, "latitude": 56.007656, "width": 375, "height": 500, "upload_date": "26 September 2006", "owner_id": 7633, "owner_name": "Daniel Meyer", "owner_url": "http://www.panoramio.com/user/7633"} +, +{"photo_id": 11105192, "photo_title": "A bird is free", "photo_url": "http://www.panoramio.com/photo/11105192", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11105192.jpg", "longitude": -6.953058, "latitude": 52.773901, "width": 375, "height": 500, "upload_date": "11 June 2008", "owner_id": 1867220, "owner_name": "Aubrey :)", "owner_url": "http://www.panoramio.com/user/1867220"} +, +{"photo_id": 196039, "photo_title": "espigón", "photo_url": "http://www.panoramio.com/photo/196039", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196039.jpg", "longitude": -3.801688, "latitude": 43.461606, "width": 332, "height": 500, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 70865, "photo_title": "Cataratas de Iguazu", "photo_url": "http://www.panoramio.com/photo/70865", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/70865.jpg", "longitude": -54.440818, "latitude": -25.688447, "width": 374, "height": 500, "upload_date": "26 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 6188760, "photo_title": "Vihar elött", "photo_url": "http://www.panoramio.com/photo/6188760", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6188760.jpg", "longitude": 17.462082, "latitude": 47.843579, "width": 500, "height": 330, "upload_date": "28 November 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 286439, "photo_title": "Rusted Car Along Route 66", "photo_url": "http://www.panoramio.com/photo/286439", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/286439.jpg", "longitude": -109.804788, "latitude": 35.050024, "width": 500, "height": 333, "upload_date": "03 January 2007", "owner_id": 45308, "owner_name": "Mike Cavaroc", "owner_url": "http://www.panoramio.com/user/45308"} +, +{"photo_id": 1283563, "photo_title": "Kalalau beach", "photo_url": "http://www.panoramio.com/photo/1283563", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1283563.jpg", "longitude": -159.667397, "latitude": 22.164196, "width": 330, "height": 500, "upload_date": "12 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 1336919, "photo_title": "Neuschwanstein", "photo_url": "http://www.panoramio.com/photo/1336919", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1336919.jpg", "longitude": 10.750465, "latitude": 47.553128, "width": 500, "height": 371, "upload_date": "15 March 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 1343841, "photo_title": "Turning Torsoe in the fog", "photo_url": "http://www.panoramio.com/photo/1343841", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1343841.jpg", "longitude": 12.968073, "latitude": 55.613165, "width": 332, "height": 500, "upload_date": "16 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 4976484, "photo_title": "Le Bout du Monde avant l'orage", "photo_url": "http://www.panoramio.com/photo/4976484", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4976484.jpg", "longitude": 6.867528, "latitude": 46.108618, "width": 500, "height": 375, "upload_date": "29 September 2007", "owner_id": 359127, "owner_name": "wx", "owner_url": "http://www.panoramio.com/user/359127"} +, +{"photo_id": 1195113, "photo_title": "Берег Сетуни 2 - Setun riverbank 2", "photo_url": "http://www.panoramio.com/photo/1195113", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1195113.jpg", "longitude": 37.486424, "latitude": 55.719367, "width": 332, "height": 500, "upload_date": "06 March 2007", "owner_id": 244932, "owner_name": "Andrey Jitkov", "owner_url": "http://www.panoramio.com/user/244932"} +, +{"photo_id": 1549176, "photo_title": "ErdÅ‘tűz", "photo_url": "http://www.panoramio.com/photo/1549176", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1549176.jpg", "longitude": 17.767639, "latitude": 47.582084, "width": 500, "height": 268, "upload_date": "29 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2127008, "photo_title": "Thunderstorm over Thunderbolt", "photo_url": "http://www.panoramio.com/photo/2127008", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2127008.jpg", "longitude": -111.586761, "latitude": 41.605303, "width": 500, "height": 329, "upload_date": "08 May 2007", "owner_id": 395804, "owner_name": "Ralph Maughan", "owner_url": "http://www.panoramio.com/user/395804"} +, +{"photo_id": 2421940, "photo_title": "Twisted Ideas", "photo_url": "http://www.panoramio.com/photo/2421940", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2421940.jpg", "longitude": -112.105286, "latitude": 36.059681, "width": 500, "height": 333, "upload_date": "27 May 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 8197305, "photo_title": "Mar Fantasma", "photo_url": "http://www.panoramio.com/photo/8197305", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8197305.jpg", "longitude": -71.699395, "latitude": -33.407478, "width": 500, "height": 346, "upload_date": "29 February 2008", "owner_id": 730217, "owner_name": "C.e.C.v", "owner_url": "http://www.panoramio.com/user/730217"} +, +{"photo_id": 6126299, "photo_title": "Richmond Squirrel", "photo_url": "http://www.panoramio.com/photo/6126299", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126299.jpg", "longitude": -0.277609, "latitude": 51.448003, "width": 500, "height": 500, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 55016, "photo_title": "Jacaré-do-pantanal. Vazante do Capivari (Caiman crocodilus yacare)", "photo_url": "http://www.panoramio.com/photo/55016", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/55016.jpg", "longitude": -56.258326, "latitude": -18.771278, "width": 500, "height": 333, "upload_date": "30 September 2006", "owner_id": 7562, "owner_name": "Marcelo E. Salgado", "owner_url": "http://www.panoramio.com/user/7562"} +, +{"photo_id": 1640188, "photo_title": "Diagonal", "photo_url": "http://www.panoramio.com/photo/1640188", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1640188.jpg", "longitude": 20.428219, "latitude": 48.953621, "width": 408, "height": 500, "upload_date": "05 April 2007", "owner_id": 346103, "owner_name": "lacitot", "owner_url": "http://www.panoramio.com/user/346103"} +, +{"photo_id": 2935837, "photo_title": "Aitzgorri. Atardecer mirando al sureste", "photo_url": "http://www.panoramio.com/photo/2935837", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2935837.jpg", "longitude": -2.324939, "latitude": 42.951271, "width": 500, "height": 323, "upload_date": "25 June 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 355622, "photo_title": "newfoundland iceberg", "photo_url": "http://www.panoramio.com/photo/355622", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/355622.jpg", "longitude": -54.733200, "latitude": 49.710939, "width": 500, "height": 334, "upload_date": "09 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 202578, "photo_title": "Abant Lake (1), Bolu", "photo_url": "http://www.panoramio.com/photo/202578", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/202578.jpg", "longitude": 31.286316, "latitude": 40.612128, "width": 500, "height": 317, "upload_date": "21 December 2006", "owner_id": 2351, "owner_name": "Serdar Bilecen", "owner_url": "http://www.panoramio.com/user/2351"} +, +{"photo_id": 9653590, "photo_title": "Secret Gate, Kentriki - [ PANORAMIO APRIL 08 WINNERS]...by Fotinos", "photo_url": "http://www.panoramio.com/photo/9653590", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9653590.jpg", "longitude": 21.914872, "latitude": 38.571189, "width": 375, "height": 500, "upload_date": "24 April 2008", "owner_id": 1640258, "owner_name": "fotinos andreopoulos", "owner_url": "http://www.panoramio.com/user/1640258"} +, +{"photo_id": 2371950, "photo_title": "Dietro l'Isola dei Conigli", "photo_url": "http://www.panoramio.com/photo/2371950", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2371950.jpg", "longitude": 12.552137, "latitude": 35.514553, "width": 500, "height": 375, "upload_date": "24 May 2007", "owner_id": 476623, "owner_name": "Giulio Botticelli", "owner_url": "http://www.panoramio.com/user/476623"} +, +{"photo_id": 1340803, "photo_title": "Huge oak in monochrome", "photo_url": "http://www.panoramio.com/photo/1340803", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1340803.jpg", "longitude": 11.187515, "latitude": 59.548763, "width": 500, "height": 493, "upload_date": "15 March 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 520878, "photo_title": "Farewell", "photo_url": "http://www.panoramio.com/photo/520878", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/520878.jpg", "longitude": 17.466202, "latitude": 47.870186, "width": 415, "height": 500, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4738479, "photo_title": "\"Sovány szárcsavágta\"", "photo_url": "http://www.panoramio.com/photo/4738479", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4738479.jpg", "longitude": 17.571602, "latitude": 47.633354, "width": 500, "height": 347, "upload_date": "18 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2395577, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/2395577", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2395577.jpg", "longitude": -79.844792, "latitude": 43.300310, "width": 500, "height": 333, "upload_date": "25 May 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 2470351, "photo_title": "Swans", "photo_url": "http://www.panoramio.com/photo/2470351", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2470351.jpg", "longitude": 23.713217, "latitude": 56.965614, "width": 500, "height": 332, "upload_date": "30 May 2007", "owner_id": 116556, "owner_name": "Pavels Dunaicevs", "owner_url": "http://www.panoramio.com/user/116556"} +, +{"photo_id": 6348257, "photo_title": "Sunset-pallatic", "photo_url": "http://www.panoramio.com/photo/6348257", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6348257.jpg", "longitude": 21.060791, "latitude": 42.004790, "width": 500, "height": 424, "upload_date": "07 December 2007", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 10248178, "photo_title": "LA LUZ DE LA MAÑANA", "photo_url": "http://www.panoramio.com/photo/10248178", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10248178.jpg", "longitude": -2.554321, "latitude": 43.209805, "width": 465, "height": 500, "upload_date": "15 May 2008", "owner_id": 1487989, "owner_name": "mesias", "owner_url": "http://www.panoramio.com/user/1487989"} +, +{"photo_id": 1177785, "photo_title": "Angkor Tom Dawn", "photo_url": "http://www.panoramio.com/photo/1177785", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1177785.jpg", "longitude": 103.858910, "latitude": 13.441383, "width": 401, "height": 500, "upload_date": "05 March 2007", "owner_id": 243825, "owner_name": "DarrinJ", "owner_url": "http://www.panoramio.com/user/243825"} +, +{"photo_id": 4785924, "photo_title": "Antelope Canyon", "photo_url": "http://www.panoramio.com/photo/4785924", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4785924.jpg", "longitude": -111.369422, "latitude": 36.853678, "width": 500, "height": 335, "upload_date": "20 September 2007", "owner_id": 464343, "owner_name": "yves floret", "owner_url": "http://www.panoramio.com/user/464343"} +, +{"photo_id": 459592, "photo_title": "nojiriko", "photo_url": "http://www.panoramio.com/photo/459592", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459592.jpg", "longitude": 138.140202, "latitude": 36.857510, "width": 500, "height": 383, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 377931, "photo_title": "Baobab Avenue after sunset", "photo_url": "http://www.panoramio.com/photo/377931", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/377931.jpg", "longitude": 44.418486, "latitude": -20.250874, "width": 500, "height": 333, "upload_date": "11 January 2007", "owner_id": 70471, "owner_name": "David Thyberg", "owner_url": "http://www.panoramio.com/user/70471"} +, +{"photo_id": 170330, "photo_title": "Petit Palais - Looking Up", "photo_url": "http://www.panoramio.com/photo/170330", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/170330.jpg", "longitude": 2.315115, "latitude": 48.866011, "width": 500, "height": 355, "upload_date": "17 December 2006", "owner_id": 5684, "owner_name": "Brent Townshend", "owner_url": "http://www.panoramio.com/user/5684"} +, +{"photo_id": 5628541, "photo_title": "Pittsburgh", "photo_url": "http://www.panoramio.com/photo/5628541", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5628541.jpg", "longitude": -80.018985, "latitude": 40.438406, "width": 500, "height": 325, "upload_date": "30 October 2007", "owner_id": 31761, "owner_name": "Buck Cash", "owner_url": "http://www.panoramio.com/user/31761"} +, +{"photo_id": 51101, "photo_title": "Morgenstimmung zwischen Bru und Bordeyri ...", "photo_url": "http://www.panoramio.com/photo/51101", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/51101.jpg", "longitude": -21.099930, "latitude": 65.205068, "width": 500, "height": 272, "upload_date": "23 September 2006", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 4352968, "photo_title": "Coucher du soleil sur le lac du Môle", "photo_url": "http://www.panoramio.com/photo/4352968", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4352968.jpg", "longitude": 6.426079, "latitude": 46.137084, "width": 500, "height": 374, "upload_date": "03 September 2007", "owner_id": 359127, "owner_name": "wx", "owner_url": "http://www.panoramio.com/user/359127"} +, +{"photo_id": 2345674, "photo_title": "Ãlomvölgy", "photo_url": "http://www.panoramio.com/photo/2345674", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2345674.jpg", "longitude": 17.791328, "latitude": 47.343243, "width": 500, "height": 334, "upload_date": "22 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3521484, "photo_title": "Ki korán kel...", "photo_url": "http://www.panoramio.com/photo/3521484", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3521484.jpg", "longitude": 17.514782, "latitude": 47.744980, "width": 500, "height": 334, "upload_date": "25 July 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8868820, "photo_title": "Burime ne malin Shar-Winner March contest -2008 \"Scenery\" Categorie", "photo_url": "http://www.panoramio.com/photo/8868820", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8868820.jpg", "longitude": 20.884666, "latitude": 42.060318, "width": 375, "height": 500, "upload_date": "26 March 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 206560, "photo_title": "Sumela Monastery", "photo_url": "http://www.panoramio.com/photo/206560", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/206560.jpg", "longitude": 39.608116, "latitude": 40.770012, "width": 500, "height": 375, "upload_date": "21 December 2006", "owner_id": 2351, "owner_name": "Serdar Bilecen", "owner_url": "http://www.panoramio.com/user/2351"} +, +{"photo_id": 1488354, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/1488354", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1488354.jpg", "longitude": 138.213072, "latitude": 37.829921, "width": 500, "height": 336, "upload_date": "25 March 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 3334377, "photo_title": "ROSENGARTEN", "photo_url": "http://www.panoramio.com/photo/3334377", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3334377.jpg", "longitude": 11.591349, "latitude": 46.411603, "width": 500, "height": 375, "upload_date": "15 July 2007", "owner_id": 584241, "owner_name": "irene.italy", "owner_url": "http://www.panoramio.com/user/584241"} +, +{"photo_id": 12668091, "photo_title": "lago di Fedaia - 2008 August NPC subject Reflecting on reflection", "photo_url": "http://www.panoramio.com/photo/12668091", "photo_file_url": "http://static4.bareka.com/photos/medium/12668091.jpg", "longitude": 11.864547, "latitude": 46.460164, "width": 385, "height": 500, "upload_date": "31 July 2008", "owner_id": 6033, "owner_name": "â–º Marco Vanzo", "owner_url": "http://www.panoramio.com/user/6033"} +, +{"photo_id": 11177556, "photo_title": "Early morning ... :)", "photo_url": "http://www.panoramio.com/photo/11177556", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11177556.jpg", "longitude": 168.307543, "latitude": -46.578215, "width": 500, "height": 340, "upload_date": "13 June 2008", "owner_id": 1256771, "owner_name": "Zsuzsanna W", "owner_url": "http://www.panoramio.com/user/1256771"} +, +{"photo_id": 67333, "photo_title": "Laguna Colorada", "photo_url": "http://www.panoramio.com/photo/67333", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/67333.jpg", "longitude": -67.798176, "latitude": -22.217285, "width": 375, "height": 500, "upload_date": "20 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 2850309, "photo_title": "Single tree...", "photo_url": "http://www.panoramio.com/photo/2850309", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2850309.jpg", "longitude": 33.571987, "latitude": 27.130876, "width": 500, "height": 375, "upload_date": "20 June 2007", "owner_id": 399963, "owner_name": "Victor Galanin", "owner_url": "http://www.panoramio.com/user/399963"} +, +{"photo_id": 1286406, "photo_title": "Creation", "photo_url": "http://www.panoramio.com/photo/1286406", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1286406.jpg", "longitude": 35.109558, "latitude": -1.460337, "width": 500, "height": 456, "upload_date": "12 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 4136208, "photo_title": "Mesél az erdÅ‘", "photo_url": "http://www.panoramio.com/photo/4136208", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4136208.jpg", "longitude": 18.062897, "latitude": 47.274105, "width": 500, "height": 334, "upload_date": "23 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8476696, "photo_title": "Coucher de soleil sur Silhouette, Seychelles. Panoramio and ATP first CONTEST, March 2008, category Travel : awarded \"Runner Up\" (second Prize). Many thanks to all voters. #434", "photo_url": "http://www.panoramio.com/photo/8476696", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8476696.jpg", "longitude": 55.493660, "latitude": -4.563249, "width": 500, "height": 339, "upload_date": "12 March 2008", "owner_id": 666755, "owner_name": "Armagnac", "owner_url": "http://www.panoramio.com/user/666755"} +, +{"photo_id": 6189344, "photo_title": "Retenue Courchevel", "photo_url": "http://www.panoramio.com/photo/6189344", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6189344.jpg", "longitude": 6.654494, "latitude": 45.385908, "width": 500, "height": 335, "upload_date": "28 November 2007", "owner_id": 464343, "owner_name": "yves floret", "owner_url": "http://www.panoramio.com/user/464343"} +, +{"photo_id": 6934835, "photo_title": "I feel shivers down my spine... (Coucher de soleil hivernal au cimetière du Père Lachaise)", "photo_url": "http://www.panoramio.com/photo/6934835", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6934835.jpg", "longitude": 2.389634, "latitude": 48.862132, "width": 500, "height": 384, "upload_date": "06 January 2008", "owner_id": 629243, "owner_name": "Olivier Faugeras", "owner_url": "http://www.panoramio.com/user/629243"} +, +{"photo_id": 4214329, "photo_title": "Sunrise of Huangshan", "photo_url": "http://www.panoramio.com/photo/4214329", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4214329.jpg", "longitude": 118.282928, "latitude": 30.139189, "width": 500, "height": 313, "upload_date": "26 August 2007", "owner_id": 161470, "owner_name": "John Su", "owner_url": "http://www.panoramio.com/user/161470"} +, +{"photo_id": 8846650, "photo_title": "Vette Tempestose - Winner of Panoramio Contest of March 2008 - Travel category", "photo_url": "http://www.panoramio.com/photo/8846650", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8846650.jpg", "longitude": 8.456469, "latitude": 45.886752, "width": 500, "height": 215, "upload_date": "25 March 2008", "owner_id": 634000, "owner_name": "© Massimo De Candido", "owner_url": "http://www.panoramio.com/user/634000"} +, +{"photo_id": 945986, "photo_title": "Xerta taronja", "photo_url": "http://www.panoramio.com/photo/945986", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/945986.jpg", "longitude": 0.483055, "latitude": 40.909102, "width": 500, "height": 377, "upload_date": "21 February 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 5108615, "photo_title": "El Vado Lake, 1", "photo_url": "http://www.panoramio.com/photo/5108615", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5108615.jpg", "longitude": -106.755394, "latitude": 36.594858, "width": 500, "height": 490, "upload_date": "05 October 2007", "owner_id": 213866, "owner_name": "Nicolas Mertens", "owner_url": "http://www.panoramio.com/user/213866"} +, +{"photo_id": 6095512, "photo_title": "before the snow came - Thunersee - in bad weather", "photo_url": "http://www.panoramio.com/photo/6095512", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6095512.jpg", "longitude": 7.641592, "latitude": 46.744566, "width": 500, "height": 374, "upload_date": "24 November 2007", "owner_id": 635422, "owner_name": "♫ Swissmay", "owner_url": "http://www.panoramio.com/user/635422"} +, +{"photo_id": 1541286, "photo_title": "Wave3", "photo_url": "http://www.panoramio.com/photo/1541286", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1541286.jpg", "longitude": -112.007471, "latitude": 36.994755, "width": 333, "height": 500, "upload_date": "29 March 2007", "owner_id": 40260, "owner_name": "Don Albonico", "owner_url": "http://www.panoramio.com/user/40260"} +, +{"photo_id": 11309226, "photo_title": "Sunset on Portsea", "photo_url": "http://www.panoramio.com/photo/11309226", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11309226.jpg", "longitude": 144.695692, "latitude": -38.330766, "width": 500, "height": 357, "upload_date": "18 June 2008", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 76734, "photo_title": "Buitre leonado", "photo_url": "http://www.panoramio.com/photo/76734", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/76734.jpg", "longitude": -5.662347, "latitude": 36.522413, "width": 500, "height": 375, "upload_date": "05 November 2006", "owner_id": 473, "owner_name": "Juanlu", "owner_url": "http://www.panoramio.com/user/473"} +, +{"photo_id": 196037, "photo_title": "camello", "photo_url": "http://www.panoramio.com/photo/196037", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196037.jpg", "longitude": -3.776196, "latitude": 43.470686, "width": 500, "height": 332, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 1338852, "photo_title": "Stairs down to Praia dé Paraiso", "photo_url": "http://www.panoramio.com/photo/1338852", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1338852.jpg", "longitude": -8.475040, "latitude": 37.096924, "width": 332, "height": 500, "upload_date": "15 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 1269734, "photo_title": "Frosty fishermans boat, Nesseby, Finnmark, Norway", "photo_url": "http://www.panoramio.com/photo/1269734", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1269734.jpg", "longitude": 28.851471, "latitude": 70.144796, "width": 500, "height": 323, "upload_date": "11 March 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 1075687, "photo_title": "Lake Como sunset", "photo_url": "http://www.panoramio.com/photo/1075687", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1075687.jpg", "longitude": 9.285164, "latitude": 46.009839, "width": 500, "height": 332, "upload_date": "28 February 2007", "owner_id": 107359, "owner_name": "Ron Cooper", "owner_url": "http://www.panoramio.com/user/107359"} +, +{"photo_id": 58363, "photo_title": "Sonnenuntergang bei Bardolino", "photo_url": "http://www.panoramio.com/photo/58363", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58363.jpg", "longitude": 10.714073, "latitude": 45.556372, "width": 500, "height": 333, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 890788, "photo_title": "KapliÄka", "photo_url": "http://www.panoramio.com/photo/890788", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/890788.jpg", "longitude": 18.222713, "latitude": 49.491950, "width": 500, "height": 333, "upload_date": "19 February 2007", "owner_id": 187280, "owner_name": "Radek ÄŒampa", "owner_url": "http://www.panoramio.com/user/187280"} +, +{"photo_id": 8730610, "photo_title": "Antelope Canyon", "photo_url": "http://www.panoramio.com/photo/8730610", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8730610.jpg", "longitude": -111.415787, "latitude": 36.918058, "width": 375, "height": 500, "upload_date": "22 March 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 3008013, "photo_title": "Infrared Mood of Peyto Lake", "photo_url": "http://www.panoramio.com/photo/3008013", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3008013.jpg", "longitude": -116.509409, "latitude": 51.717989, "width": 500, "height": 334, "upload_date": "29 June 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 565018, "photo_title": "Another one sunset in dubulti", "photo_url": "http://www.panoramio.com/photo/565018", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/565018.jpg", "longitude": 23.765488, "latitude": 56.971626, "width": 500, "height": 333, "upload_date": "25 January 2007", "owner_id": 116556, "owner_name": "Pavels Dunaicevs", "owner_url": "http://www.panoramio.com/user/116556"} +, +{"photo_id": 2217257, "photo_title": "Csermely", "photo_url": "http://www.panoramio.com/photo/2217257", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2217257.jpg", "longitude": 17.986851, "latitude": 47.273755, "width": 500, "height": 334, "upload_date": "14 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3008041, "photo_title": "Lake Louise", "photo_url": "http://www.panoramio.com/photo/3008041", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3008041.jpg", "longitude": -116.219387, "latitude": 51.417409, "width": 500, "height": 335, "upload_date": "29 June 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 636724, "photo_title": "Bora Bora JC", "photo_url": "http://www.panoramio.com/photo/636724", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/636724.jpg", "longitude": -151.714239, "latitude": -16.475926, "width": 500, "height": 375, "upload_date": "31 January 2007", "owner_id": 131113, "owner_name": "Lair Jean Claude", "owner_url": "http://www.panoramio.com/user/131113"} +, +{"photo_id": 511806, "photo_title": "EzüsterdÅ‘", "photo_url": "http://www.panoramio.com/photo/511806", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/511806.jpg", "longitude": 17.748070, "latitude": 47.273056, "width": 366, "height": 500, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 727360, "photo_title": "Hot croissant for breakfast - Crescent sunrise", "photo_url": "http://www.panoramio.com/photo/727360", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/727360.jpg", "longitude": 19.053833, "latitude": 47.605512, "width": 500, "height": 311, "upload_date": "07 February 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 5148235, "photo_title": "shinagawa", "photo_url": "http://www.panoramio.com/photo/5148235", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5148235.jpg", "longitude": 139.741459, "latitude": 35.627460, "width": 500, "height": 500, "upload_date": "07 October 2007", "owner_id": 128403, "owner_name": "mechanics", "owner_url": "http://www.panoramio.com/user/128403"} +, +{"photo_id": 2082127, "photo_title": "Rejtelmes Szigetköz", "photo_url": "http://www.panoramio.com/photo/2082127", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2082127.jpg", "longitude": 17.508516, "latitude": 47.850088, "width": 500, "height": 316, "upload_date": "05 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1589607, "photo_title": "Baalbek - Temple of Bacchus - Giant Columns", "photo_url": "http://www.panoramio.com/photo/1589607", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1589607.jpg", "longitude": 36.204404, "latitude": 34.006228, "width": 500, "height": 283, "upload_date": "01 April 2007", "owner_id": 73104, "owner_name": "zerega", "owner_url": "http://www.panoramio.com/user/73104"} +, +{"photo_id": 410991, "photo_title": "Burj al Arab", "photo_url": "http://www.panoramio.com/photo/410991", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/410991.jpg", "longitude": 55.187352, "latitude": 25.139282, "width": 500, "height": 342, "upload_date": "13 January 2007", "owner_id": 82662, "owner_name": "Sven Goelles", "owner_url": "http://www.panoramio.com/user/82662"} +, +{"photo_id": 6012, "photo_title": "Rastoke", "photo_url": "http://www.panoramio.com/photo/6012", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6012.jpg", "longitude": 15.584493, "latitude": 45.119144, "width": 343, "height": 500, "upload_date": "18 December 2005", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 4989314, "photo_title": "Range of Light", "photo_url": "http://www.panoramio.com/photo/4989314", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4989314.jpg", "longitude": -118.597283, "latitude": 37.234360, "width": 500, "height": 357, "upload_date": "29 September 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 2115987, "photo_title": "La Croix de Brume", "photo_url": "http://www.panoramio.com/photo/2115987", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2115987.jpg", "longitude": 0.341520, "latitude": 44.859519, "width": 409, "height": 500, "upload_date": "07 May 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 229544, "photo_title": "VRT RTBf Toren", "photo_url": "http://www.panoramio.com/photo/229544", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/229544.jpg", "longitude": 4.401634, "latitude": 50.852972, "width": 333, "height": 500, "upload_date": "24 December 2006", "owner_id": 7464, "owner_name": "Pieter", "owner_url": "http://www.panoramio.com/user/7464"} +, +{"photo_id": 58283, "photo_title": "Weg", "photo_url": "http://www.panoramio.com/photo/58283", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58283.jpg", "longitude": 12.898464, "latitude": 48.059496, "width": 500, "height": 333, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 112110, "photo_title": "Toronto_CN-Tower", "photo_url": "http://www.panoramio.com/photo/112110", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/112110.jpg", "longitude": -79.386907, "latitude": 43.641805, "width": 500, "height": 375, "upload_date": "11 December 2006", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 4446966, "photo_title": "Ãlmodó folyó", "photo_url": "http://www.panoramio.com/photo/4446966", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4446966.jpg", "longitude": 17.454357, "latitude": 47.881470, "width": 500, "height": 375, "upload_date": "06 September 2007", "owner_id": 182660, "owner_name": "Bálint Tünde", "owner_url": "http://www.panoramio.com/user/182660"} +, +{"photo_id": 91966, "photo_title": "Bled (Slovenia)", "photo_url": "http://www.panoramio.com/photo/91966", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/91966.jpg", "longitude": 14.087219, "latitude": 46.358184, "width": 500, "height": 375, "upload_date": "04 December 2006", "owner_id": 11403, "owner_name": "Arnáiz", "owner_url": "http://www.panoramio.com/user/11403"} +, +{"photo_id": 6013503, "photo_title": "Kapelle bei Böhmenkirch", "photo_url": "http://www.panoramio.com/photo/6013503", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6013503.jpg", "longitude": 9.943142, "latitude": 48.694756, "width": 500, "height": 375, "upload_date": "19 November 2007", "owner_id": 424589, "owner_name": "PeSchn", "owner_url": "http://www.panoramio.com/user/424589"} +, +{"photo_id": 1781593, "photo_title": "Medusa's Sandbox", "photo_url": "http://www.panoramio.com/photo/1781593", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781593.jpg", "longitude": -112.006624, "latitude": 36.995852, "width": 375, "height": 500, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 704119, "photo_title": "Izzó Adria", "photo_url": "http://www.panoramio.com/photo/704119", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/704119.jpg", "longitude": 17.056789, "latitude": 43.272206, "width": 500, "height": 285, "upload_date": "05 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 85624, "photo_title": "Isla del Fraile Ãguilas", "photo_url": "http://www.panoramio.com/photo/85624", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/85624.jpg", "longitude": -0.722609, "latitude": 37.924329, "width": 500, "height": 298, "upload_date": "24 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 52350, "photo_title": "Cataratas del Iguazú. Brasil", "photo_url": "http://www.panoramio.com/photo/52350", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/52350.jpg", "longitude": -54.439831, "latitude": -25.687422, "width": 500, "height": 333, "upload_date": "25 September 2006", "owner_id": 6961, "owner_name": "Santiago Rios", "owner_url": "http://www.panoramio.com/user/6961"} +, +{"photo_id": 36482, "photo_title": "Rovinj Harbour", "photo_url": "http://www.panoramio.com/photo/36482", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36482.jpg", "longitude": 13.632714, "latitude": 45.083938, "width": 500, "height": 332, "upload_date": "02 August 2006", "owner_id": 5703, "owner_name": "dancer", "owner_url": "http://www.panoramio.com/user/5703"} +, +{"photo_id": 7251846, "photo_title": "Azért a víz az úr", "photo_url": "http://www.panoramio.com/photo/7251846", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7251846.jpg", "longitude": 17.629623, "latitude": 47.687334, "width": 500, "height": 329, "upload_date": "20 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1551756, "photo_title": "Templestowe", "photo_url": "http://www.panoramio.com/photo/1551756", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1551756.jpg", "longitude": 145.116667, "latitude": -37.750000, "width": 500, "height": 298, "upload_date": "30 March 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 2397841, "photo_title": "Storm Season II", "photo_url": "http://www.panoramio.com/photo/2397841", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2397841.jpg", "longitude": -122.439870, "latitude": 37.427928, "width": 407, "height": 500, "upload_date": "26 May 2007", "owner_id": 107613, "owner_name": "Tom Grubbe", "owner_url": "http://www.panoramio.com/user/107613"} +, +{"photo_id": 1237915, "photo_title": "Chlum u Trebone", "photo_url": "http://www.panoramio.com/photo/1237915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1237915.jpg", "longitude": 14.923811, "latitude": 48.960159, "width": 500, "height": 429, "upload_date": "09 March 2007", "owner_id": 235166, "owner_name": "jirivrobel", "owner_url": "http://www.panoramio.com/user/235166"} +, +{"photo_id": 359324, "photo_title": "Abstraktion in der Kirche von Mogno, Tessin .......", "photo_url": "http://www.panoramio.com/photo/359324", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/359324.jpg", "longitude": 8.663492, "latitude": 46.430966, "width": 500, "height": 380, "upload_date": "09 January 2007", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 483742, "photo_title": "Venus at Haleakala", "photo_url": "http://www.panoramio.com/photo/483742", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/483742.jpg", "longitude": -156.239491, "latitude": 20.707468, "width": 500, "height": 375, "upload_date": "18 January 2007", "owner_id": 100907, "owner_name": "Julia Wahl", "owner_url": "http://www.panoramio.com/user/100907"} +, +{"photo_id": 1087397, "photo_title": "Fjellbjerk (Betula) Snøhetta mountain in the background", "photo_url": "http://www.panoramio.com/photo/1087397", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1087397.jpg", "longitude": 9.555531, "latitude": 62.240111, "width": 500, "height": 333, "upload_date": "28 February 2007", "owner_id": 223406, "owner_name": "Sigmund Rise", "owner_url": "http://www.panoramio.com/user/223406"} +, +{"photo_id": 2846123, "photo_title": "新潟 å°åƒè°·ã€€é¢¨èˆ¹ä¸€æ†ã€€2003 niigata ojiya balloon riot Fireworks", "photo_url": "http://www.panoramio.com/photo/2846123", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2846123.jpg", "longitude": 138.791313, "latitude": 37.289350, "width": 500, "height": 497, "upload_date": "20 June 2007", "owner_id": 446937, "owner_name": "y_komatsu", "owner_url": "http://www.panoramio.com/user/446937"} +, +{"photo_id": 2533559, "photo_title": "Great Idea ! Don´t do it !!!", "photo_url": "http://www.panoramio.com/photo/2533559", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2533559.jpg", "longitude": -35.036988, "latitude": -6.241628, "width": 500, "height": 308, "upload_date": "02 June 2007", "owner_id": 1908, "owner_name": "Cleber Lima", "owner_url": "http://www.panoramio.com/user/1908"} +, +{"photo_id": 86246, "photo_title": "Salinas de Santa Pola", "photo_url": "http://www.panoramio.com/photo/86246", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/86246.jpg", "longitude": -0.528374, "latitude": 38.230090, "width": 500, "height": 333, "upload_date": "25 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 405740, "photo_title": "fudoutaki", "photo_url": "http://www.panoramio.com/photo/405740", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405740.jpg", "longitude": 139.502249, "latitude": 37.580909, "width": 500, "height": 394, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 12848417, "photo_title": "Niedrigwasser an der Elbe-Dresden", "photo_url": "http://www.panoramio.com/photo/12848417", "photo_file_url": "http://static2.bareka.com/photos/medium/12848417.jpg", "longitude": 13.745323, "latitude": 51.055093, "width": 500, "height": 268, "upload_date": "05 August 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 291091, "photo_title": "Imperia Porto Maurizio Puesta del Sol al Prino", "photo_url": "http://www.panoramio.com/photo/291091", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/291091.jpg", "longitude": 8.006684, "latitude": 43.869312, "width": 500, "height": 465, "upload_date": "03 January 2007", "owner_id": 60898, "owner_name": "esseil", "owner_url": "http://www.panoramio.com/user/60898"} +, +{"photo_id": 1183261, "photo_title": "Az óperencián innen", "photo_url": "http://www.panoramio.com/photo/1183261", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1183261.jpg", "longitude": 15.823574, "latitude": 43.708462, "width": 500, "height": 312, "upload_date": "05 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1637150, "photo_title": "Vista del Misti por encima de las nubes", "photo_url": "http://www.panoramio.com/photo/1637150", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1637150.jpg", "longitude": -71.414566, "latitude": -16.300040, "width": 500, "height": 333, "upload_date": "05 April 2007", "owner_id": 328178, "owner_name": "Mariví Jiménez", "owner_url": "http://www.panoramio.com/user/328178"} +, +{"photo_id": 507703, "photo_title": "Csendes vizek", "photo_url": "http://www.panoramio.com/photo/507703", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507703.jpg", "longitude": 17.568769, "latitude": 47.633586, "width": 500, "height": 349, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 55100, "photo_title": "Ballesvikskardet", "photo_url": "http://www.panoramio.com/photo/55100", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/55100.jpg", "longitude": 17.122707, "latitude": 69.352910, "width": 500, "height": 375, "upload_date": "30 September 2006", "owner_id": 3574, "owner_name": "blackone", "owner_url": "http://www.panoramio.com/user/3574"} +, +{"photo_id": 291648, "photo_title": "Galway Cathedral", "photo_url": "http://www.panoramio.com/photo/291648", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/291648.jpg", "longitude": -9.057664, "latitude": 53.275627, "width": 500, "height": 336, "upload_date": "03 January 2007", "owner_id": 61285, "owner_name": "kamil krawczak", "owner_url": "http://www.panoramio.com/user/61285"} +, +{"photo_id": 5285701, "photo_title": "Another South Sister reflecting in Sparks Lake", "photo_url": "http://www.panoramio.com/photo/5285701", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5285701.jpg", "longitude": -121.737549, "latitude": 44.014176, "width": 500, "height": 334, "upload_date": "13 October 2007", "owner_id": 128746, "owner_name": "© Michael Hatten", "owner_url": "http://www.panoramio.com/user/128746"} +, +{"photo_id": 761958, "photo_title": "Lake Oulujärvi", "photo_url": "http://www.panoramio.com/photo/761958", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/761958.jpg", "longitude": 27.339649, "latitude": 64.231986, "width": 375, "height": 500, "upload_date": "10 February 2007", "owner_id": 151444, "owner_name": "Timo Rossi", "owner_url": "http://www.panoramio.com/user/151444"} +, +{"photo_id": 3853459, "photo_title": "Its great to be a swan on Hawn Pawn!", "photo_url": "http://www.panoramio.com/photo/3853459", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3853459.jpg", "longitude": -71.154628, "latitude": 42.470625, "width": 389, "height": 500, "upload_date": "10 August 2007", "owner_id": 286174, "owner_name": "kamaly", "owner_url": "http://www.panoramio.com/user/286174"} +, +{"photo_id": 4610197, "photo_title": "Yosemite Valley with Fallen Redwood from V11", "photo_url": "http://www.panoramio.com/photo/4610197", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4610197.jpg", "longitude": -119.661703, "latitude": 37.717214, "width": 500, "height": 281, "upload_date": "12 September 2007", "owner_id": 339677, "owner_name": "Chip Stephan", "owner_url": "http://www.panoramio.com/user/339677"} +, +{"photo_id": 5700759, "photo_title": "Crete senesi", "photo_url": "http://www.panoramio.com/photo/5700759", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5700759.jpg", "longitude": 11.448483, "latitude": 43.280205, "width": 500, "height": 304, "upload_date": "02 November 2007", "owner_id": 158718, "owner_name": "giulio colla", "owner_url": "http://www.panoramio.com/user/158718"} +, +{"photo_id": 1391775, "photo_title": "Arboles al atardecer en Chapala - Trees at sunset in Chapala Lake", "photo_url": "http://www.panoramio.com/photo/1391775", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1391775.jpg", "longitude": -102.775211, "latitude": 20.308730, "width": 500, "height": 341, "upload_date": "19 March 2007", "owner_id": 291650, "owner_name": "J.Ernesto Ortiz Razo", "owner_url": "http://www.panoramio.com/user/291650"} +, +{"photo_id": 57514, "photo_title": "Limone 1", "photo_url": "http://www.panoramio.com/photo/57514", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57514.jpg", "longitude": 10.792179, "latitude": 45.816298, "width": 500, "height": 333, "upload_date": "04 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 2602937, "photo_title": "Alone", "photo_url": "http://www.panoramio.com/photo/2602937", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2602937.jpg", "longitude": -4.001770, "latitude": 31.174035, "width": 500, "height": 320, "upload_date": "06 June 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 117465, "photo_title": "New York in the Afternoon...from Soho.. by Jeremiah Christopher", "photo_url": "http://www.panoramio.com/photo/117465", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/117465.jpg", "longitude": -74.003212, "latitude": 40.724059, "width": 500, "height": 375, "upload_date": "11 December 2006", "owner_id": 16869, "owner_name": "Jeremiah Christopher", "owner_url": "http://www.panoramio.com/user/16869"} +, +{"photo_id": 1331707, "photo_title": "Kastellet (Copenhagen fortress), Aerial", "photo_url": "http://www.panoramio.com/photo/1331707", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1331707.jpg", "longitude": 12.594967, "latitude": 55.691230, "width": 500, "height": 332, "upload_date": "15 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 11853382, "photo_title": "Railroads by Sunset/ Schienen bei Sonnenuntergang", "photo_url": "http://www.panoramio.com/photo/11853382", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11853382.jpg", "longitude": 8.283455, "latitude": 51.692644, "width": 500, "height": 332, "upload_date": "06 July 2008", "owner_id": 564436, "owner_name": "Thomas Splietker", "owner_url": "http://www.panoramio.com/user/564436"} +, +{"photo_id": 1558288, "photo_title": "Notre-Dame et Tour Saint Jacques", "photo_url": "http://www.panoramio.com/photo/1558288", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1558288.jpg", "longitude": 2.354808, "latitude": 48.850399, "width": 500, "height": 333, "upload_date": "30 March 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 7601425, "photo_title": "Venezianische Impressionen", "photo_url": "http://www.panoramio.com/photo/7601425", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7601425.jpg", "longitude": 12.337024, "latitude": 45.432280, "width": 500, "height": 385, "upload_date": "05 February 2008", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 36386, "photo_title": "Half Dome Cables", "photo_url": "http://www.panoramio.com/photo/36386", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36386.jpg", "longitude": -119.530735, "latitude": 37.746710, "width": 333, "height": 500, "upload_date": "02 August 2006", "owner_id": 5684, "owner_name": "Brent Townshend", "owner_url": "http://www.panoramio.com/user/5684"} +, +{"photo_id": 1089570, "photo_title": "Titokzatos reggel", "photo_url": "http://www.panoramio.com/photo/1089570", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1089570.jpg", "longitude": 17.467575, "latitude": 47.870532, "width": 500, "height": 331, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 575276, "photo_title": "Sunrise", "photo_url": "http://www.panoramio.com/photo/575276", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/575276.jpg", "longitude": 2.288809, "latitude": 48.861892, "width": 500, "height": 349, "upload_date": "26 January 2007", "owner_id": 123518, "owner_name": "ERic Pouhier ericpouhier.com", "owner_url": "http://www.panoramio.com/user/123518"} +, +{"photo_id": 486480, "photo_title": "Monte Generoso", "photo_url": "http://www.panoramio.com/photo/486480", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/486480.jpg", "longitude": 9.015055, "latitude": 45.924826, "width": 428, "height": 500, "upload_date": "19 January 2007", "owner_id": 24068, "owner_name": "Daniele Nasi", "owner_url": "http://www.panoramio.com/user/24068"} +, +{"photo_id": 1100378, "photo_title": "Rensbekksetra (summer pasture)", "photo_url": "http://www.panoramio.com/photo/1100378", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1100378.jpg", "longitude": 9.293404, "latitude": 62.712731, "width": 500, "height": 255, "upload_date": "01 March 2007", "owner_id": 223406, "owner_name": "Sigmund Rise", "owner_url": "http://www.panoramio.com/user/223406"} +, +{"photo_id": 5844316, "photo_title": "Hikarigaoka IMA", "photo_url": "http://www.panoramio.com/photo/5844316", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5844316.jpg", "longitude": 139.630048, "latitude": 35.758154, "width": 500, "height": 326, "upload_date": "11 November 2007", "owner_id": 558055, "owner_name": "www.tokyoform.com", "owner_url": "http://www.panoramio.com/user/558055"} +, +{"photo_id": 1345372, "photo_title": "Sunset, Foeniculum vulgare (fennel, is one likely candidate)", "photo_url": "http://www.panoramio.com/photo/1345372", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1345372.jpg", "longitude": 10.727119, "latitude": 55.205080, "width": 332, "height": 500, "upload_date": "16 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 1317735, "photo_title": "Motu of Bora Bora", "photo_url": "http://www.panoramio.com/photo/1317735", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1317735.jpg", "longitude": -151.698360, "latitude": -16.495843, "width": 500, "height": 355, "upload_date": "14 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 1012093, "photo_title": "Sunrise from the east side of Longs Peak", "photo_url": "http://www.panoramio.com/photo/1012093", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1012093.jpg", "longitude": -105.542564, "latitude": 40.274549, "width": 374, "height": 500, "upload_date": "25 February 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 5035419, "photo_title": "Basilica de San Basilio (Moscow)", "photo_url": "http://www.panoramio.com/photo/5035419", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5035419.jpg", "longitude": 37.622852, "latitude": 55.752622, "width": 398, "height": 500, "upload_date": "01 October 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 799910, "photo_title": "A Dramatic Turn of the Yangtze River", "photo_url": "http://www.panoramio.com/photo/799910", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/799910.jpg", "longitude": 99.272633, "latitude": 28.255552, "width": 500, "height": 226, "upload_date": "13 February 2007", "owner_id": 164125, "owner_name": "DannyXu", "owner_url": "http://www.panoramio.com/user/164125"} +, +{"photo_id": 765388, "photo_title": "Leh", "photo_url": "http://www.panoramio.com/photo/765388", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/765388.jpg", "longitude": 77.587509, "latitude": 34.164943, "width": 500, "height": 333, "upload_date": "10 February 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 2875857, "photo_title": "Elgol, Isle of Skye", "photo_url": "http://www.panoramio.com/photo/2875857", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2875857.jpg", "longitude": -6.107025, "latitude": 57.150023, "width": 500, "height": 500, "upload_date": "22 June 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 840915, "photo_title": "Island of The Day Before", "photo_url": "http://www.panoramio.com/photo/840915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/840915.jpg", "longitude": 27.436638, "latitude": 42.441448, "width": 500, "height": 333, "upload_date": "16 February 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 1459925, "photo_title": "The last ray", "photo_url": "http://www.panoramio.com/photo/1459925", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1459925.jpg", "longitude": -110.134850, "latitude": 36.955379, "width": 500, "height": 290, "upload_date": "23 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 872177, "photo_title": "Sahara Desert sunrise, Chott el Jerid, near Kebili, Tunisia, 1/2007", "photo_url": "http://www.panoramio.com/photo/872177", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/872177.jpg", "longitude": 8.475866, "latitude": 33.930898, "width": 500, "height": 375, "upload_date": "18 February 2007", "owner_id": 183521, "owner_name": "SteveT", "owner_url": "http://www.panoramio.com/user/183521"} +, +{"photo_id": 405753, "photo_title": "sinanogawa", "photo_url": "http://www.panoramio.com/photo/405753", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405753.jpg", "longitude": 138.822384, "latitude": 37.268589, "width": 500, "height": 386, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 548240, "photo_title": "Old Bagan 2002", "photo_url": "http://www.panoramio.com/photo/548240", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/548240.jpg", "longitude": 94.825230, "latitude": 21.137026, "width": 500, "height": 375, "upload_date": "23 January 2007", "owner_id": 64758, "owner_name": "Joly David", "owner_url": "http://www.panoramio.com/user/64758"} +, +{"photo_id": 4868105, "photo_title": "Bled lake", "photo_url": "http://www.panoramio.com/photo/4868105", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4868105.jpg", "longitude": 14.104900, "latitude": 46.369793, "width": 500, "height": 333, "upload_date": "24 September 2007", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 549396, "photo_title": "RÃ¥kneset on Storfjellet island, Røst", "photo_url": "http://www.panoramio.com/photo/549396", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/549396.jpg", "longitude": 11.932955, "latitude": 67.457456, "width": 500, "height": 375, "upload_date": "23 January 2007", "owner_id": 95799, "owner_name": "Owen Morgan", "owner_url": "http://www.panoramio.com/user/95799"} +, +{"photo_id": 196121, "photo_title": "canallave", "photo_url": "http://www.panoramio.com/photo/196121", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196121.jpg", "longitude": -3.960571, "latitude": 43.452358, "width": 500, "height": 332, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 2422299, "photo_title": "Pacific Weather", "photo_url": "http://www.panoramio.com/photo/2422299", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2422299.jpg", "longitude": -124.097099, "latitude": 44.345704, "width": 500, "height": 333, "upload_date": "27 May 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 821291, "photo_title": "Храм ВаÑÐ¸Ð»Ð¸Ñ Ð‘Ð»Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ (МоÑква, ноÑбрь 2006 года)", "photo_url": "http://www.panoramio.com/photo/821291", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/821291.jpg", "longitude": 37.622954, "latitude": 55.752613, "width": 500, "height": 375, "upload_date": "14 February 2007", "owner_id": 55593, "owner_name": "pokatut.photosight.ru", "owner_url": "http://www.panoramio.com/user/55593"} +, +{"photo_id": 3545143, "photo_title": "Rainbow (Regnbue)", "photo_url": "http://www.panoramio.com/photo/3545143", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3545143.jpg", "longitude": 8.598175, "latitude": 62.904445, "width": 500, "height": 223, "upload_date": "26 July 2007", "owner_id": 343934, "owner_name": "Asbjørn999", "owner_url": "http://www.panoramio.com/user/343934"} +, +{"photo_id": 1794618, "photo_title": "TúlélÅ‘k", "photo_url": "http://www.panoramio.com/photo/1794618", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1794618.jpg", "longitude": 20.803127, "latitude": 48.014157, "width": 399, "height": 500, "upload_date": "15 April 2007", "owner_id": 346103, "owner_name": "lacitot", "owner_url": "http://www.panoramio.com/user/346103"} +, +{"photo_id": 3904091, "photo_title": "Hajnali utakon", "photo_url": "http://www.panoramio.com/photo/3904091", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3904091.jpg", "longitude": 17.512014, "latitude": 47.850319, "width": 500, "height": 334, "upload_date": "13 August 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 5649508, "photo_title": "Quiet morning", "photo_url": "http://www.panoramio.com/photo/5649508", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5649508.jpg", "longitude": 12.190876, "latitude": 49.357446, "width": 500, "height": 333, "upload_date": "31 October 2007", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 7938965, "photo_title": "Pattaya - Big Buddha - Big Buddha Hill", "photo_url": "http://www.panoramio.com/photo/7938965", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7938965.jpg", "longitude": 100.868343, "latitude": 12.914107, "width": 500, "height": 375, "upload_date": "19 February 2008", "owner_id": 716245, "owner_name": "—Dragon-64— ✈", "owner_url": "http://www.panoramio.com/user/716245"} +, +{"photo_id": 497056, "photo_title": "Japanese Garden maple", "photo_url": "http://www.panoramio.com/photo/497056", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/497056.jpg", "longitude": -122.707999, "latitude": 45.518810, "width": 500, "height": 300, "upload_date": "20 January 2007", "owner_id": 107359, "owner_name": "Ron Cooper", "owner_url": "http://www.panoramio.com/user/107359"} +, +{"photo_id": 438699, "photo_title": "White Sand Dunes", "photo_url": "http://www.panoramio.com/photo/438699", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/438699.jpg", "longitude": -106.262083, "latitude": 32.799324, "width": 371, "height": 500, "upload_date": "15 January 2007", "owner_id": 93560, "owner_name": "Alex Petrov", "owner_url": "http://www.panoramio.com/user/93560"} +, +{"photo_id": 2082221, "photo_title": "\"Bekötött szemmel\"", "photo_url": "http://www.panoramio.com/photo/2082221", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2082221.jpg", "longitude": 17.660522, "latitude": 47.604543, "width": 500, "height": 334, "upload_date": "05 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 5836484, "photo_title": "An Autumn's golden dawn on the Lake of Varese", "photo_url": "http://www.panoramio.com/photo/5836484", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5836484.jpg", "longitude": 8.718081, "latitude": 45.838966, "width": 500, "height": 312, "upload_date": "11 November 2007", "owner_id": 933456, "owner_name": "© Marco De Candido", "owner_url": "http://www.panoramio.com/user/933456"} +, +{"photo_id": 5204696, "photo_title": "Scotland", "photo_url": "http://www.panoramio.com/photo/5204696", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5204696.jpg", "longitude": -5.078773, "latitude": 56.558726, "width": 500, "height": 254, "upload_date": "09 October 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 1343454, "photo_title": "Вулкан КарымÑкий", "photo_url": "http://www.panoramio.com/photo/1343454", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1343454.jpg", "longitude": 159.480286, "latitude": 54.025470, "width": 364, "height": 500, "upload_date": "16 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 507424, "photo_title": "Lankák, ívek, felhőárnyak", "photo_url": "http://www.panoramio.com/photo/507424", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507424.jpg", "longitude": 17.967281, "latitude": 47.318112, "width": 500, "height": 291, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 5893176, "photo_title": "07-06-11_Camino de Santiago, Castrojeriz_PIXELECTA", "photo_url": "http://www.panoramio.com/photo/5893176", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5893176.jpg", "longitude": -4.182916, "latitude": 42.285723, "width": 500, "height": 333, "upload_date": "13 November 2007", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 186685, "photo_title": "People of Petra, the boy and his job", "photo_url": "http://www.panoramio.com/photo/186685", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/186685.jpg", "longitude": 35.437002, "latitude": 30.322285, "width": 500, "height": 375, "upload_date": "19 December 2006", "owner_id": 24068, "owner_name": "Daniele Nasi", "owner_url": "http://www.panoramio.com/user/24068"} +, +{"photo_id": 355648, "photo_title": "puerto-rico el-yunque", "photo_url": "http://www.panoramio.com/photo/355648", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/355648.jpg", "longitude": -65.788536, "latitude": 18.298795, "width": 500, "height": 334, "upload_date": "09 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 46913, "photo_title": "beachy head", "photo_url": "http://www.panoramio.com/photo/46913", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/46913.jpg", "longitude": 0.216272, "latitude": 50.737969, "width": 500, "height": 291, "upload_date": "11 September 2006", "owner_id": 2575, "owner_name": "mikel ortega", "owner_url": "http://www.panoramio.com/user/2575"} +, +{"photo_id": 6012999, "photo_title": "Wetterumschwung in Murano", "photo_url": "http://www.panoramio.com/photo/6012999", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6012999.jpg", "longitude": 12.357838, "latitude": 45.457557, "width": 500, "height": 336, "upload_date": "19 November 2007", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 590422, "photo_title": "Gyilkos-tó (Killer Lake) - Remains of the forest, which grew here until 1837, conserved by the water", "photo_url": "http://www.panoramio.com/photo/590422", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/590422.jpg", "longitude": 25.785170, "latitude": 46.792597, "width": 500, "height": 352, "upload_date": "27 January 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 5119067, "photo_title": "Fog In The Forest", "photo_url": "http://www.panoramio.com/photo/5119067", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5119067.jpg", "longitude": 7.667191, "latitude": 49.174283, "width": 500, "height": 375, "upload_date": "05 October 2007", "owner_id": 528834, "owner_name": "©junebug", "owner_url": "http://www.panoramio.com/user/528834"} +, +{"photo_id": 4702558, "photo_title": "Sunset ( Isla de Antigua-Caribe)", "photo_url": "http://www.panoramio.com/photo/4702558", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4702558.jpg", "longitude": -61.833801, "latitude": 17.171627, "width": 500, "height": 375, "upload_date": "16 September 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 717413, "photo_title": "Singapore Skyline with Esplanade at night", "photo_url": "http://www.panoramio.com/photo/717413", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/717413.jpg", "longitude": 103.856664, "latitude": 1.291589, "width": 391, "height": 500, "upload_date": "06 February 2007", "owner_id": 20398, "owner_name": "boerx", "owner_url": "http://www.panoramio.com/user/20398"} +, +{"photo_id": 6281064, "photo_title": "Latemar Carezza", "photo_url": "http://www.panoramio.com/photo/6281064", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6281064.jpg", "longitude": 11.595447, "latitude": 46.412476, "width": 500, "height": 332, "upload_date": "03 December 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 327016, "photo_title": "bryce canyon", "photo_url": "http://www.panoramio.com/photo/327016", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/327016.jpg", "longitude": -112.210836, "latitude": 37.586146, "width": 500, "height": 375, "upload_date": "07 January 2007", "owner_id": 63705, "owner_name": "Karl Wiktorin", "owner_url": "http://www.panoramio.com/user/63705"} +, +{"photo_id": 301678, "photo_title": "Akashi Kaikyo Bridge (Pearl Bridge)", "photo_url": "http://www.panoramio.com/photo/301678", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/301678.jpg", "longitude": 135.028882, "latitude": 34.623002, "width": 443, "height": 500, "upload_date": "04 January 2007", "owner_id": 30202, "owner_name": "S_Mori", "owner_url": "http://www.panoramio.com/user/30202"} +, +{"photo_id": 6055804, "photo_title": "2007 Balsa de SALBURUA_VITORIA (Alava) PIXELECTA", "photo_url": "http://www.panoramio.com/photo/6055804", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6055804.jpg", "longitude": -2.650537, "latitude": 42.859907, "width": 500, "height": 333, "upload_date": "21 November 2007", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 5946759, "photo_title": "Snow Pond", "photo_url": "http://www.panoramio.com/photo/5946759", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5946759.jpg", "longitude": 10.899510, "latitude": 49.694507, "width": 500, "height": 375, "upload_date": "16 November 2007", "owner_id": 884621, "owner_name": "Florian Eichhorn", "owner_url": "http://www.panoramio.com/user/884621"} +, +{"photo_id": 231305, "photo_title": "Cathedral Rock in Sedona, AZ at Sunset", "photo_url": "http://www.panoramio.com/photo/231305", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/231305.jpg", "longitude": -111.792294, "latitude": 34.818657, "width": 500, "height": 327, "upload_date": "25 December 2006", "owner_id": 45308, "owner_name": "Mike Cavaroc", "owner_url": "http://www.panoramio.com/user/45308"} +, +{"photo_id": 582047, "photo_title": "Old Vineyard with the sun trying to break through the fog: Oakley, CA", "photo_url": "http://www.panoramio.com/photo/582047", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/582047.jpg", "longitude": -121.753750, "latitude": 38.001658, "width": 500, "height": 316, "upload_date": "26 January 2007", "owner_id": 99249, "owner_name": "shaunika", "owner_url": "http://www.panoramio.com/user/99249"} +, +{"photo_id": 679332, "photo_title": "forbidden city", "photo_url": "http://www.panoramio.com/photo/679332", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/679332.jpg", "longitude": 116.396177, "latitude": 39.921734, "width": 500, "height": 248, "upload_date": "04 February 2007", "owner_id": 146092, "owner_name": "sid1662", "owner_url": "http://www.panoramio.com/user/146092"} +, +{"photo_id": 3904189, "photo_title": "Hajnal", "photo_url": "http://www.panoramio.com/photo/3904189", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3904189.jpg", "longitude": 17.361488, "latitude": 47.875138, "width": 500, "height": 333, "upload_date": "13 August 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 11059137, "photo_title": "Sunset at Kythira Greece by Nikos Demiris", "photo_url": "http://www.panoramio.com/photo/11059137", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11059137.jpg", "longitude": 23.003998, "latitude": 36.142034, "width": 500, "height": 346, "upload_date": "09 June 2008", "owner_id": 1629713, "owner_name": "demirisn", "owner_url": "http://www.panoramio.com/user/1629713"} +, +{"photo_id": 2334150, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/2334150", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2334150.jpg", "longitude": 0.491531, "latitude": 40.903993, "width": 500, "height": 373, "upload_date": "21 May 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 5709301, "photo_title": "Ködvarázs II", "photo_url": "http://www.panoramio.com/photo/5709301", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5709301.jpg", "longitude": 17.998352, "latitude": 47.252903, "width": 333, "height": 500, "upload_date": "05 November 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 55029, "photo_title": "Solar Eclipce, Mt.Elbrus, Refuge of 11", "photo_url": "http://www.panoramio.com/photo/55029", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/55029.jpg", "longitude": 42.451859, "latitude": 43.316186, "width": 448, "height": 500, "upload_date": "30 September 2006", "owner_id": 7707, "owner_name": "Yorix", "owner_url": "http://www.panoramio.com/user/7707"} +, +{"photo_id": 702974, "photo_title": "Hundertwasserhaus", "photo_url": "http://www.panoramio.com/photo/702974", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/702974.jpg", "longitude": 16.393780, "latitude": 48.207594, "width": 375, "height": 500, "upload_date": "05 February 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 8811826, "photo_title": "Der Baum im Wasser", "photo_url": "http://www.panoramio.com/photo/8811826", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8811826.jpg", "longitude": 9.293532, "latitude": 52.869078, "width": 375, "height": 500, "upload_date": "24 March 2008", "owner_id": 1431077, "owner_name": "Heiner F.", "owner_url": "http://www.panoramio.com/user/1431077"} +, +{"photo_id": 67843, "photo_title": "Torre Eiffel", "photo_url": "http://www.panoramio.com/photo/67843", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/67843.jpg", "longitude": 2.294587, "latitude": 48.858468, "width": 500, "height": 375, "upload_date": "21 October 2006", "owner_id": 9163, "owner_name": "marathoniano", "owner_url": "http://www.panoramio.com/user/9163"} +, +{"photo_id": 1183509, "photo_title": "Viharpart", "photo_url": "http://www.panoramio.com/photo/1183509", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1183509.jpg", "longitude": 15.917473, "latitude": 43.590587, "width": 500, "height": 334, "upload_date": "05 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 449049, "photo_title": "Encantos de Santos", "photo_url": "http://www.panoramio.com/photo/449049", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/449049.jpg", "longitude": -46.307716, "latitude": -23.988605, "width": 500, "height": 342, "upload_date": "16 January 2007", "owner_id": 81574, "owner_name": "Criss RB", "owner_url": "http://www.panoramio.com/user/81574"} +, +{"photo_id": 4669228, "photo_title": "Reif an der naab", "photo_url": "http://www.panoramio.com/photo/4669228", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4669228.jpg", "longitude": 12.113457, "latitude": 49.339105, "width": 500, "height": 333, "upload_date": "15 September 2007", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 516653, "photo_title": "Alkonyvarázs", "photo_url": "http://www.panoramio.com/photo/516653", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/516653.jpg", "longitude": 17.451611, "latitude": 47.782424, "width": 404, "height": 500, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4214320, "photo_title": "暮色", "photo_url": "http://www.panoramio.com/photo/4214320", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4214320.jpg", "longitude": 110.364532, "latitude": 25.201524, "width": 500, "height": 313, "upload_date": "26 August 2007", "owner_id": 161470, "owner_name": "John Su", "owner_url": "http://www.panoramio.com/user/161470"} +, +{"photo_id": 9419312, "photo_title": "Skeleton", "photo_url": "http://www.panoramio.com/photo/9419312", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9419312.jpg", "longitude": -147.929063, "latitude": -15.091723, "width": 500, "height": 326, "upload_date": "16 April 2008", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 642609, "photo_title": "Oia, Santorini, Cyclades, Hellas, Greece", "photo_url": "http://www.panoramio.com/photo/642609", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/642609.jpg", "longitude": 25.377388, "latitude": 36.460778, "width": 500, "height": 333, "upload_date": "01 February 2007", "owner_id": 131038, "owner_name": "wolffystyle", "owner_url": "http://www.panoramio.com/user/131038"} +, +{"photo_id": 354614, "photo_title": "Dresden_Centrum_01", "photo_url": "http://www.panoramio.com/photo/354614", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/354614.jpg", "longitude": 13.740206, "latitude": 51.056934, "width": 500, "height": 332, "upload_date": "09 January 2007", "owner_id": 71628, "owner_name": "Ulrich Hässler, Dresden", "owner_url": "http://www.panoramio.com/user/71628"} +, +{"photo_id": 678200, "photo_title": "Geometria de terrazas", "photo_url": "http://www.panoramio.com/photo/678200", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/678200.jpg", "longitude": -16.841269, "latitude": 28.235525, "width": 500, "height": 333, "upload_date": "03 February 2007", "owner_id": 92750, "owner_name": "Pablo López Ramos", "owner_url": "http://www.panoramio.com/user/92750"} +, +{"photo_id": 436284, "photo_title": "bandaibasi2", "photo_url": "http://www.panoramio.com/photo/436284", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436284.jpg", "longitude": 139.051423, "latitude": 37.920063, "width": 500, "height": 393, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 2235454, "photo_title": "La bonde et la brume", "photo_url": "http://www.panoramio.com/photo/2235454", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2235454.jpg", "longitude": 1.595249, "latitude": 47.313181, "width": 500, "height": 500, "upload_date": "15 May 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 5983, "photo_title": "Waiting", "photo_url": "http://www.panoramio.com/photo/5983", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5983.jpg", "longitude": 7.796173, "latitude": 33.954752, "width": 344, "height": 500, "upload_date": "17 December 2005", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 97402, "photo_title": "Mostar", "photo_url": "http://www.panoramio.com/photo/97402", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/97402.jpg", "longitude": 17.814803, "latitude": 43.337102, "width": 500, "height": 375, "upload_date": "09 December 2006", "owner_id": 12954, "owner_name": "ZiÄ™bol", "owner_url": "http://www.panoramio.com/user/12954"} +, +{"photo_id": 5159548, "photo_title": "Autumn - Herbstfarben - Fall", "photo_url": "http://www.panoramio.com/photo/5159548", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5159548.jpg", "longitude": 7.541599, "latitude": 46.834772, "width": 500, "height": 374, "upload_date": "08 October 2007", "owner_id": 635422, "owner_name": "♫ Swissmay", "owner_url": "http://www.panoramio.com/user/635422"} +, +{"photo_id": 1779072, "photo_title": "Égi érintés", "photo_url": "http://www.panoramio.com/photo/1779072", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1779072.jpg", "longitude": 17.747383, "latitude": 47.556835, "width": 462, "height": 500, "upload_date": "14 April 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 5795973, "photo_title": "Emmental mit 7 Hengsten Hohgant und Berneralpen - Emmental, 7 Stallions and Bernese Alpine Snow Mountains", "photo_url": "http://www.panoramio.com/photo/5795973", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5795973.jpg", "longitude": 7.730427, "latitude": 47.033280, "width": 500, "height": 374, "upload_date": "08 November 2007", "owner_id": 635422, "owner_name": "♫ Swissmay", "owner_url": "http://www.panoramio.com/user/635422"} +, +{"photo_id": 6850694, "photo_title": "2007-VITORIA Alava PIXELECTA", "photo_url": "http://www.panoramio.com/photo/6850694", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6850694.jpg", "longitude": -2.649336, "latitude": 42.861260, "width": 500, "height": 116, "upload_date": "02 January 2008", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 11738506, "photo_title": "Galeria de Itálica", "photo_url": "http://www.panoramio.com/photo/11738506", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11738506.jpg", "longitude": -6.046858, "latitude": 37.444199, "width": 378, "height": 500, "upload_date": "03 July 2008", "owner_id": 1038666, "owner_name": "Doenjo", "owner_url": "http://www.panoramio.com/user/1038666"} +, +{"photo_id": 4013965, "photo_title": "Pedaleando en la costanera", "photo_url": "http://www.panoramio.com/photo/4013965", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4013965.jpg", "longitude": -73.231012, "latitude": -39.817655, "width": 500, "height": 366, "upload_date": "18 August 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 611985, "photo_title": "Toda Temple", "photo_url": "http://www.panoramio.com/photo/611985", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/611985.jpg", "longitude": 76.715459, "latitude": 11.420014, "width": 500, "height": 375, "upload_date": "29 January 2007", "owner_id": 130990, "owner_name": "Eye for India. blogspot .com", "owner_url": "http://www.panoramio.com/user/130990"} +, +{"photo_id": 2689441, "photo_title": "Terepszemle", "photo_url": "http://www.panoramio.com/photo/2689441", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2689441.jpg", "longitude": 17.674255, "latitude": 47.601533, "width": 500, "height": 347, "upload_date": "11 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6599853, "photo_title": "FlowerSun", "photo_url": "http://www.panoramio.com/photo/6599853", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6599853.jpg", "longitude": 21.042938, "latitude": 41.988333, "width": 480, "height": 500, "upload_date": "21 December 2007", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 71855, "photo_title": "British Museum", "photo_url": "http://www.panoramio.com/photo/71855", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/71855.jpg", "longitude": -0.127373, "latitude": 51.519265, "width": 500, "height": 333, "upload_date": "28 October 2006", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 58291, "photo_title": "Gollinger Wasserfall", "photo_url": "http://www.panoramio.com/photo/58291", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58291.jpg", "longitude": 13.138103, "latitude": 47.601244, "width": 330, "height": 500, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 3903941, "photo_title": "Viharos Pipacsos", "photo_url": "http://www.panoramio.com/photo/3903941", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3903941.jpg", "longitude": 16.638451, "latitude": 47.732396, "width": 500, "height": 331, "upload_date": "13 August 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 5363928, "photo_title": "Antelope Slot Canyon", "photo_url": "http://www.panoramio.com/photo/5363928", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5363928.jpg", "longitude": -111.370811, "latitude": 36.856755, "width": 500, "height": 326, "upload_date": "17 October 2007", "owner_id": 358485, "owner_name": "Francesco Villa", "owner_url": "http://www.panoramio.com/user/358485"} +, +{"photo_id": 2688750, "photo_title": "Playa de Strenc,Mallorca", "photo_url": "http://www.panoramio.com/photo/2688750", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2688750.jpg", "longitude": 2.980042, "latitude": 39.348702, "width": 500, "height": 427, "upload_date": "11 June 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 3148025, "photo_title": "Zuidlede", "photo_url": "http://www.panoramio.com/photo/3148025", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3148025.jpg", "longitude": 3.906112, "latitude": 51.147667, "width": 496, "height": 500, "upload_date": "06 July 2007", "owner_id": 635244, "owner_name": "A.Lebacq", "owner_url": "http://www.panoramio.com/user/635244"} +, +{"photo_id": 809727, "photo_title": "Túl az óperencián", "photo_url": "http://www.panoramio.com/photo/809727", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/809727.jpg", "longitude": 17.062283, "latitude": 43.277580, "width": 500, "height": 334, "upload_date": "13 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 11560716, "photo_title": "China's Great Wall, 09 may 2008", "photo_url": "http://www.panoramio.com/photo/11560716", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11560716.jpg", "longitude": 116.064860, "latitude": 40.287162, "width": 500, "height": 331, "upload_date": "27 June 2008", "owner_id": 1931067, "owner_name": "EugeneTrambo", "owner_url": "http://www.panoramio.com/user/1931067"} +, +{"photo_id": 10484028, "photo_title": "Tuscanny in lower bavaria? Toskana in Niederbayern? near Pfeffenhausen", "photo_url": "http://www.panoramio.com/photo/10484028", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10484028.jpg", "longitude": 11.982479, "latitude": 48.628768, "width": 500, "height": 411, "upload_date": "22 May 2008", "owner_id": 1077251, "owner_name": "picsonthemove", "owner_url": "http://www.panoramio.com/user/1077251"} +, +{"photo_id": 10321724, "photo_title": "Kingston Lacy beech avenue from the middle of the road (don't try this at home...)", "photo_url": "http://www.panoramio.com/photo/10321724", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10321724.jpg", "longitude": -2.051697, "latitude": 50.820469, "width": 500, "height": 473, "upload_date": "17 May 2008", "owner_id": 450216, "owner_name": "Graham Hobbs", "owner_url": "http://www.panoramio.com/user/450216"} +, +{"photo_id": 11847917, "photo_title": "Neda.... The end of an unusual trip! First Prize \"Travel\" Panoramio JULY 2008, a shot by kostas andreopoulos", "photo_url": "http://www.panoramio.com/photo/11847917", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11847917.jpg", "longitude": 21.776275, "latitude": 37.394711, "width": 500, "height": 484, "upload_date": "06 July 2008", "owner_id": 1690483, "owner_name": "k.andre", "owner_url": "http://www.panoramio.com/user/1690483"} +, +{"photo_id": 723285, "photo_title": "Stonehenge Fisheye View June 2000", "photo_url": "http://www.panoramio.com/photo/723285", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723285.jpg", "longitude": -1.826195, "latitude": 51.178849, "width": 500, "height": 500, "upload_date": "07 February 2007", "owner_id": 154364, "owner_name": "Edgy01", "owner_url": "http://www.panoramio.com/user/154364"} +, +{"photo_id": 9831198, "photo_title": "VerÅ‘fényes hangulat", "photo_url": "http://www.panoramio.com/photo/9831198", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9831198.jpg", "longitude": 18.331053, "latitude": 47.650689, "width": 333, "height": 500, "upload_date": "01 May 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4670496, "photo_title": "Vuelo rasante entre la niebla", "photo_url": "http://www.panoramio.com/photo/4670496", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4670496.jpg", "longitude": -73.243092, "latitude": -39.809134, "width": 500, "height": 371, "upload_date": "15 September 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 2414624, "photo_title": "Triumvirátus", "photo_url": "http://www.panoramio.com/photo/2414624", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2414624.jpg", "longitude": 17.768154, "latitude": 47.510940, "width": 500, "height": 309, "upload_date": "27 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 196129, "photo_title": "usgo", "photo_url": "http://www.panoramio.com/photo/196129", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196129.jpg", "longitude": -3.999882, "latitude": 43.439397, "width": 500, "height": 316, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 304677, "photo_title": "Allee bei Wilhelmsthal", "photo_url": "http://www.panoramio.com/photo/304677", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/304677.jpg", "longitude": 9.409919, "latitude": 51.392686, "width": 500, "height": 409, "upload_date": "05 January 2007", "owner_id": 63703, "owner_name": "Rainer Kaufhold", "owner_url": "http://www.panoramio.com/user/63703"} +, +{"photo_id": 4924213, "photo_title": "Egy varázslatos estén", "photo_url": "http://www.panoramio.com/photo/4924213", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4924213.jpg", "longitude": 2.151239, "latitude": 41.371278, "width": 500, "height": 335, "upload_date": "26 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 189243, "photo_title": "coming in for a landing", "photo_url": "http://www.panoramio.com/photo/189243", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/189243.jpg", "longitude": -123.147984, "latitude": 49.198812, "width": 500, "height": 333, "upload_date": "19 December 2006", "owner_id": 29932, "owner_name": "Rom@nce", "owner_url": "http://www.panoramio.com/user/29932"} +, +{"photo_id": 3121730, "photo_title": "Mers-les-Bains dark clouds looming", "photo_url": "http://www.panoramio.com/photo/3121730", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3121730.jpg", "longitude": 1.383655, "latitude": 50.066878, "width": 500, "height": 375, "upload_date": "04 July 2007", "owner_id": 633531, "owner_name": "ianwstokes", "owner_url": "http://www.panoramio.com/user/633531"} +, +{"photo_id": 5358146, "photo_title": "Lone Rock Rainbows", "photo_url": "http://www.panoramio.com/photo/5358146", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5358146.jpg", "longitude": -111.537795, "latitude": 37.020475, "width": 500, "height": 335, "upload_date": "16 October 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 9633346, "photo_title": "Altstadt von Spello--Winner Contest of April 2008 First Prize of Travel Category", "photo_url": "http://www.panoramio.com/photo/9633346", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9633346.jpg", "longitude": 12.672386, "latitude": 42.989236, "width": 347, "height": 500, "upload_date": "23 April 2008", "owner_id": 1400529, "owner_name": "marita1004", "owner_url": "http://www.panoramio.com/user/1400529"} +, +{"photo_id": 611425, "photo_title": "The Dome of Cologne", "photo_url": "http://www.panoramio.com/photo/611425", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/611425.jpg", "longitude": 6.968604, "latitude": 50.941157, "width": 500, "height": 357, "upload_date": "29 January 2007", "owner_id": 8058, "owner_name": "Ermanec", "owner_url": "http://www.panoramio.com/user/8058"} +, +{"photo_id": 6850661, "photo_title": "Në Fush të Pallaticës", "photo_url": "http://www.panoramio.com/photo/6850661", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6850661.jpg", "longitude": 21.075768, "latitude": 42.007915, "width": 488, "height": 500, "upload_date": "02 January 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 5617509, "photo_title": "Cölöp kiadó", "photo_url": "http://www.panoramio.com/photo/5617509", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5617509.jpg", "longitude": 12.333934, "latitude": 45.425368, "width": 500, "height": 334, "upload_date": "29 October 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2083687, "photo_title": "Sunrise at Abu Simbel", "photo_url": "http://www.panoramio.com/photo/2083687", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2083687.jpg", "longitude": 31.630840, "latitude": 22.363729, "width": 500, "height": 335, "upload_date": "05 May 2007", "owner_id": 3316, "owner_name": "kristine hannon (www.traveltheglobe.be)", "owner_url": "http://www.panoramio.com/user/3316"} +, +{"photo_id": 7284083, "photo_title": "Japanese garden", "photo_url": "http://www.panoramio.com/photo/7284083", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7284083.jpg", "longitude": -13.673172, "latitude": 21.259301, "width": 335, "height": 500, "upload_date": "22 January 2008", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 5750152, "photo_title": "Earth, Moon and Sky", "photo_url": "http://www.panoramio.com/photo/5750152", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5750152.jpg", "longitude": -117.560234, "latitude": 36.678057, "width": 333, "height": 500, "upload_date": "06 November 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 5633673, "photo_title": "Ridgely Farm Lane", "photo_url": "http://www.panoramio.com/photo/5633673", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5633673.jpg", "longitude": -78.775320, "latitude": 38.031867, "width": 500, "height": 378, "upload_date": "30 October 2007", "owner_id": 523038, "owner_name": "Yank in Dixie", "owner_url": "http://www.panoramio.com/user/523038"} +, +{"photo_id": 723090, "photo_title": "Grand Canyon (Havasupai)", "photo_url": "http://www.panoramio.com/photo/723090", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723090.jpg", "longitude": -112.716293, "latitude": 36.270989, "width": 500, "height": 332, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1226915, "photo_title": "Flamants roses sur l'Etang de Vaccarès", "photo_url": "http://www.panoramio.com/photo/1226915", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1226915.jpg", "longitude": 4.627304, "latitude": 43.551285, "width": 500, "height": 333, "upload_date": "08 March 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 2738883, "photo_title": "Tormenta", "photo_url": "http://www.panoramio.com/photo/2738883", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2738883.jpg", "longitude": -71.616096, "latitude": -33.042558, "width": 333, "height": 500, "upload_date": "14 June 2007", "owner_id": 477365, "owner_name": "✔chilefoto", "owner_url": "http://www.panoramio.com/user/477365"} +, +{"photo_id": 2875846, "photo_title": "Rannoch Moor, Scotland", "photo_url": "http://www.panoramio.com/photo/2875846", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2875846.jpg", "longitude": -4.745750, "latitude": 56.594467, "width": 500, "height": 462, "upload_date": "22 June 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 533456, "photo_title": "Zöld symphonia", "photo_url": "http://www.panoramio.com/photo/533456", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/533456.jpg", "longitude": 17.500362, "latitude": 47.843579, "width": 500, "height": 333, "upload_date": "22 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3078609, "photo_title": "Pagan - Sunset Vista", "photo_url": "http://www.panoramio.com/photo/3078609", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3078609.jpg", "longitude": 94.884624, "latitude": 21.166644, "width": 500, "height": 329, "upload_date": "02 July 2007", "owner_id": 73104, "owner_name": "zerega", "owner_url": "http://www.panoramio.com/user/73104"} +, +{"photo_id": 1599459, "photo_title": "Rosina Lamberti - Templestowe Sunset", "photo_url": "http://www.panoramio.com/photo/1599459", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1599459.jpg", "longitude": 145.145187, "latitude": -37.773700, "width": 500, "height": 332, "upload_date": "02 April 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 37097, "photo_title": "Burj Al Arab at Night", "photo_url": "http://www.panoramio.com/photo/37097", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/37097.jpg", "longitude": 55.190012, "latitude": 25.144411, "width": 333, "height": 500, "upload_date": "05 August 2006", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 42988, "photo_title": "Mekhong at Nakhon Phanom, Thailand", "photo_url": "http://www.panoramio.com/photo/42988", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/42988.jpg", "longitude": 104.780045, "latitude": 17.415348, "width": 500, "height": 375, "upload_date": "29 August 2006", "owner_id": 6386, "owner_name": "Uwe Werner", "owner_url": "http://www.panoramio.com/user/6386"} +, +{"photo_id": 4738551, "photo_title": "Aquakatedral", "photo_url": "http://www.panoramio.com/photo/4738551", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4738551.jpg", "longitude": 18.026505, "latitude": 47.279462, "width": 500, "height": 334, "upload_date": "18 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6126327, "photo_title": "Autumnal Morning", "photo_url": "http://www.panoramio.com/photo/6126327", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126327.jpg", "longitude": 0.209620, "latitude": 51.658827, "width": 500, "height": 500, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 1390072, "photo_title": "Winter Wonder Woods", "photo_url": "http://www.panoramio.com/photo/1390072", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1390072.jpg", "longitude": -123.184891, "latitude": 49.400027, "width": 500, "height": 343, "upload_date": "19 March 2007", "owner_id": 164125, "owner_name": "DannyXu", "owner_url": "http://www.panoramio.com/user/164125"} +, +{"photo_id": 8600061, "photo_title": "Templio", "photo_url": "http://www.panoramio.com/photo/8600061", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8600061.jpg", "longitude": 13.600258, "latitude": 37.288703, "width": 500, "height": 375, "upload_date": "17 March 2008", "owner_id": 325031, "owner_name": "Gibrail", "owner_url": "http://www.panoramio.com/user/325031"} +, +{"photo_id": 1232144, "photo_title": "the Wave", "photo_url": "http://www.panoramio.com/photo/1232144", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1232144.jpg", "longitude": -112.006313, "latitude": 36.995921, "width": 497, "height": 500, "upload_date": "08 March 2007", "owner_id": 256348, "owner_name": "DIEZ Jean-Paul", "owner_url": "http://www.panoramio.com/user/256348"} +, +{"photo_id": 12825028, "photo_title": "American Star shipwreck", "photo_url": "http://www.panoramio.com/photo/12825028", "photo_file_url": "http://static1.bareka.com/photos/medium/12825028.jpg", "longitude": -14.178050, "latitude": 28.345596, "width": 500, "height": 375, "upload_date": "05 August 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 9705164, "photo_title": "Die blaue Stunde-Dresden", "photo_url": "http://www.panoramio.com/photo/9705164", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9705164.jpg", "longitude": 13.732374, "latitude": 51.061020, "width": 500, "height": 333, "upload_date": "26 April 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 9701147, "photo_title": "After the thunderstorm II (Calella de Palafrugell)", "photo_url": "http://www.panoramio.com/photo/9701147", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9701147.jpg", "longitude": 3.185166, "latitude": 41.888413, "width": 500, "height": 347, "upload_date": "26 April 2008", "owner_id": 629243, "owner_name": "Olivier Faugeras", "owner_url": "http://www.panoramio.com/user/629243"} +, +{"photo_id": 3414277, "photo_title": "Morning at Vlixos_Lefkada", "photo_url": "http://www.panoramio.com/photo/3414277", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3414277.jpg", "longitude": 20.698693, "latitude": 38.689111, "width": 500, "height": 333, "upload_date": "20 July 2007", "owner_id": 242446, "owner_name": "Ntinos Lagos", "owner_url": "http://www.panoramio.com/user/242446"} +, +{"photo_id": 1205806, "photo_title": "A tavasz aranya", "photo_url": "http://www.panoramio.com/photo/1205806", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1205806.jpg", "longitude": 17.634773, "latitude": 47.557299, "width": 500, "height": 302, "upload_date": "07 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6430261, "photo_title": "The wet side of winter", "photo_url": "http://www.panoramio.com/photo/6430261", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6430261.jpg", "longitude": 9.531434, "latitude": 48.559611, "width": 500, "height": 375, "upload_date": "11 December 2007", "owner_id": 424589, "owner_name": "PeSchn", "owner_url": "http://www.panoramio.com/user/424589"} +, +{"photo_id": 8116025, "photo_title": "Sale el Sol, Cae la Luna", "photo_url": "http://www.panoramio.com/photo/8116025", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8116025.jpg", "longitude": -71.875992, "latitude": -41.170126, "width": 500, "height": 333, "upload_date": "26 February 2008", "owner_id": 4483, "owner_name": "Miguel Coranti", "owner_url": "http://www.panoramio.com/user/4483"} +, +{"photo_id": 1235514, "photo_title": "Pulau Menjangan", "photo_url": "http://www.panoramio.com/photo/1235514", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1235514.jpg", "longitude": 114.502687, "latitude": -8.095941, "width": 500, "height": 341, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 32827, "photo_title": "Xi'an Bell Tower", "photo_url": "http://www.panoramio.com/photo/32827", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/32827.jpg", "longitude": 108.943026, "latitude": 34.260759, "width": 500, "height": 375, "upload_date": "17 July 2006", "owner_id": 5168, "owner_name": "Markus Källander", "owner_url": "http://www.panoramio.com/user/5168"} +, +{"photo_id": 798014, "photo_title": "Porto Canale", "photo_url": "http://www.panoramio.com/photo/798014", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/798014.jpg", "longitude": 12.399648, "latitude": 44.203343, "width": 500, "height": 332, "upload_date": "12 February 2007", "owner_id": 159455, "owner_name": "©Franco Truscello", "owner_url": "http://www.panoramio.com/user/159455"} +, +{"photo_id": 10517317, "photo_title": "Route 66", "photo_url": "http://www.panoramio.com/photo/10517317", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10517317.jpg", "longitude": 18.027492, "latitude": 46.268071, "width": 500, "height": 375, "upload_date": "23 May 2008", "owner_id": 328249, "owner_name": "v.zsoloo", "owner_url": "http://www.panoramio.com/user/328249"} +, +{"photo_id": 416838, "photo_title": "Old Faithful on New Year's Morning", "photo_url": "http://www.panoramio.com/photo/416838", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/416838.jpg", "longitude": -110.827900, "latitude": 44.459354, "width": 500, "height": 375, "upload_date": "13 January 2007", "owner_id": 71099, "owner_name": "Eve in Montana", "owner_url": "http://www.panoramio.com/user/71099"} +, +{"photo_id": 5964, "photo_title": "Skradin bridge", "photo_url": "http://www.panoramio.com/photo/5964", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5964.jpg", "longitude": 15.908031, "latitude": 43.806040, "width": 500, "height": 333, "upload_date": "17 December 2005", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 419923, "photo_title": "bandaibashi2", "photo_url": "http://www.panoramio.com/photo/419923", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/419923.jpg", "longitude": 139.055500, "latitude": 37.920029, "width": 334, "height": 500, "upload_date": "14 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 26985, "photo_title": "Cementerio General", "photo_url": "http://www.panoramio.com/photo/26985", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/26985.jpg", "longitude": -84.091458, "latitude": 9.930174, "width": 393, "height": 500, "upload_date": "23 June 2006", "owner_id": 4112, "owner_name": "Roberto Garcia", "owner_url": "http://www.panoramio.com/user/4112"} +, +{"photo_id": 405866, "photo_title": "awasima", "photo_url": "http://www.panoramio.com/photo/405866", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405866.jpg", "longitude": 139.229908, "latitude": 38.463267, "width": 396, "height": 500, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1319538, "photo_title": "What a place !", "photo_url": "http://www.panoramio.com/photo/1319538", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1319538.jpg", "longitude": -62.542677, "latitude": 6.022092, "width": 329, "height": 500, "upload_date": "14 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 444280, "photo_title": "Cigars are for ladies", "photo_url": "http://www.panoramio.com/photo/444280", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/444280.jpg", "longitude": -82.351027, "latitude": 23.139117, "width": 500, "height": 375, "upload_date": "15 January 2007", "owner_id": 57893, "owner_name": "ThoiryK", "owner_url": "http://www.panoramio.com/user/57893"} +, +{"photo_id": 6016, "photo_title": "Å ibenik - tiramol", "photo_url": "http://www.panoramio.com/photo/6016", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6016.jpg", "longitude": 15.890865, "latitude": 43.735693, "width": 473, "height": 500, "upload_date": "18 December 2005", "owner_id": 991, "owner_name": "Mario Marotti", "owner_url": "http://www.panoramio.com/user/991"} +, +{"photo_id": 3531661, "photo_title": "Zúzmara", "photo_url": "http://www.panoramio.com/photo/3531661", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3531661.jpg", "longitude": 17.498131, "latitude": 47.847727, "width": 500, "height": 346, "upload_date": "25 July 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 723088, "photo_title": "Friendly Evening Haze", "photo_url": "http://www.panoramio.com/photo/723088", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723088.jpg", "longitude": 25.428715, "latitude": 36.421282, "width": 333, "height": 500, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 422813, "photo_title": "tanokami", "photo_url": "http://www.panoramio.com/photo/422813", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/422813.jpg", "longitude": 138.777237, "latitude": 37.581453, "width": 500, "height": 379, "upload_date": "14 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 516256, "photo_title": "A hitehagyott", "photo_url": "http://www.panoramio.com/photo/516256", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/516256.jpg", "longitude": 17.533493, "latitude": 47.842139, "width": 500, "height": 291, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 706978, "photo_title": "Snow at full moon", "photo_url": "http://www.panoramio.com/photo/706978", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/706978.jpg", "longitude": 23.878784, "latitude": 69.829207, "width": 500, "height": 334, "upload_date": "05 February 2007", "owner_id": 56091, "owner_name": "Kjetil Vaage Øie", "owner_url": "http://www.panoramio.com/user/56091"} +, +{"photo_id": 4994983, "photo_title": "Camogli - Castello della \"Dragonara\" (north-west looking photograph)", "photo_url": "http://www.panoramio.com/photo/4994983", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4994983.jpg", "longitude": 9.151220, "latitude": 44.350207, "width": 325, "height": 500, "upload_date": "30 September 2007", "owner_id": 180947, "owner_name": "gilberto silvestri", "owner_url": "http://www.panoramio.com/user/180947"} +, +{"photo_id": 1315255, "photo_title": "Tulpen in Holland", "photo_url": "http://www.panoramio.com/photo/1315255", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1315255.jpg", "longitude": 4.556494, "latitude": 52.278451, "width": 500, "height": 321, "upload_date": "14 March 2007", "owner_id": 193467, "owner_name": "Jörg Behmann", "owner_url": "http://www.panoramio.com/user/193467"} +, +{"photo_id": 5204412, "photo_title": "Alaska Range", "photo_url": "http://www.panoramio.com/photo/5204412", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5204412.jpg", "longitude": -150.150146, "latitude": 62.734601, "width": 500, "height": 375, "upload_date": "09 October 2007", "owner_id": 71099, "owner_name": "Eve in Montana", "owner_url": "http://www.panoramio.com/user/71099"} +, +{"photo_id": 5204668, "photo_title": "Scotland", "photo_url": "http://www.panoramio.com/photo/5204668", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5204668.jpg", "longitude": -4.821882, "latitude": 56.634188, "width": 500, "height": 500, "upload_date": "09 October 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 1706188, "photo_title": "Night", "photo_url": "http://www.panoramio.com/photo/1706188", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1706188.jpg", "longitude": 21.440957, "latitude": 48.427236, "width": 390, "height": 500, "upload_date": "09 April 2007", "owner_id": 346103, "owner_name": "lacitot", "owner_url": "http://www.panoramio.com/user/346103"} +, +{"photo_id": 6366165, "photo_title": "Il Latemar", "photo_url": "http://www.panoramio.com/photo/6366165", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6366165.jpg", "longitude": 11.575856, "latitude": 46.410138, "width": 500, "height": 375, "upload_date": "08 December 2007", "owner_id": 933456, "owner_name": "© Marco De Candido", "owner_url": "http://www.panoramio.com/user/933456"} +, +{"photo_id": 5433048, "photo_title": "moon photoshop", "photo_url": "http://www.panoramio.com/photo/5433048", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5433048.jpg", "longitude": 11.337848, "latitude": 46.460602, "width": 500, "height": 335, "upload_date": "20 October 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 611035, "photo_title": "Ice berg", "photo_url": "http://www.panoramio.com/photo/611035", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/611035.jpg", "longitude": -58.886719, "latitude": -63.470145, "width": 333, "height": 500, "upload_date": "29 January 2007", "owner_id": 14940, "owner_name": "elmtree", "owner_url": "http://www.panoramio.com/user/14940"} +, +{"photo_id": 4258269, "photo_title": "Új nap kelte", "photo_url": "http://www.panoramio.com/photo/4258269", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4258269.jpg", "longitude": 17.474785, "latitude": 47.832057, "width": 500, "height": 327, "upload_date": "28 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 37088, "photo_title": "Komandoo From The Air", "photo_url": "http://www.panoramio.com/photo/37088", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/37088.jpg", "longitude": 73.422661, "latitude": 5.496900, "width": 500, "height": 278, "upload_date": "05 August 2006", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 71667, "photo_title": "2006ë…„06ì›”11ì¼(ì¼) 장전계곡 ë° ë‹¨ìž„ê³¨ 046_resize", "photo_url": "http://www.panoramio.com/photo/71667", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/71667.jpg", "longitude": 128.533516, "latitude": 37.435340, "width": 500, "height": 333, "upload_date": "28 October 2006", "owner_id": 9424, "owner_name": "박범호", "owner_url": "http://www.panoramio.com/user/9424"} +, +{"photo_id": 5300468, "photo_title": "Lac du Vieux Emosson", "photo_url": "http://www.panoramio.com/photo/5300468", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5300468.jpg", "longitude": 6.883256, "latitude": 46.055744, "width": 500, "height": 500, "upload_date": "14 October 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 591351, "photo_title": "smokestack_8739", "photo_url": "http://www.panoramio.com/photo/591351", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/591351.jpg", "longitude": -79.386027, "latitude": 43.648168, "width": 500, "height": 392, "upload_date": "27 January 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 11224316, "photo_title": "Remindful winter season-Vardar river", "photo_url": "http://www.panoramio.com/photo/11224316", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11224316.jpg", "longitude": 21.084051, "latitude": 42.013782, "width": 214, "height": 500, "upload_date": "15 June 2008", "owner_id": 695042, "owner_name": "Neim Sejfuli ♦", "owner_url": "http://www.panoramio.com/user/695042"} +, +{"photo_id": 5968187, "photo_title": "2007 VITORIA Alava PIXELECTA", "photo_url": "http://www.panoramio.com/photo/5968187", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5968187.jpg", "longitude": -2.650087, "latitude": 42.860206, "width": 500, "height": 333, "upload_date": "17 November 2007", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 1781517, "photo_title": "Yosemite Falls in Winter", "photo_url": "http://www.panoramio.com/photo/1781517", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781517.jpg", "longitude": -119.590130, "latitude": 37.744318, "width": 500, "height": 400, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 5796376, "photo_title": "Shuto Expressway Loop Line in Nihombashi", "photo_url": "http://www.panoramio.com/photo/5796376", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5796376.jpg", "longitude": 139.776344, "latitude": 35.684536, "width": 327, "height": 500, "upload_date": "08 November 2007", "owner_id": 558055, "owner_name": "www.tokyoform.com", "owner_url": "http://www.panoramio.com/user/558055"} +, +{"photo_id": 5523741, "photo_title": "Saskatchewan Sunset October 24/07 (and there is the flat land of the prairies at the bottom of this pic ;)", "photo_url": "http://www.panoramio.com/photo/5523741", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5523741.jpg", "longitude": -105.535011, "latitude": 50.502073, "width": 375, "height": 500, "upload_date": "24 October 2007", "owner_id": 133037, "owner_name": "Lilypon", "owner_url": "http://www.panoramio.com/user/133037"} +, +{"photo_id": 196125, "photo_title": "arnía y covachos", "photo_url": "http://www.panoramio.com/photo/196125", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/196125.jpg", "longitude": -3.914223, "latitude": 43.474349, "width": 500, "height": 337, "upload_date": "20 December 2006", "owner_id": 38804, "owner_name": "www.oscarsanchez.net", "owner_url": "http://www.panoramio.com/user/38804"} +, +{"photo_id": 349726, "photo_title": "thailand ko-samui sunset", "photo_url": "http://www.panoramio.com/photo/349726", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/349726.jpg", "longitude": 99.930954, "latitude": 9.472344, "width": 500, "height": 334, "upload_date": "08 January 2007", "owner_id": 69671, "owner_name": "illusandpics.com", "owner_url": "http://www.panoramio.com/user/69671"} +, +{"photo_id": 280106, "photo_title": "dune01", "photo_url": "http://www.panoramio.com/photo/280106", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/280106.jpg", "longitude": -5.089073, "latitude": 30.229408, "width": 500, "height": 345, "upload_date": "01 January 2007", "owner_id": 58867, "owner_name": "Lachaud Franck", "owner_url": "http://www.panoramio.com/user/58867"} +, +{"photo_id": 4446015, "photo_title": "Mennyei fényjáték", "photo_url": "http://www.panoramio.com/photo/4446015", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4446015.jpg", "longitude": 17.818108, "latitude": 47.525084, "width": 500, "height": 333, "upload_date": "06 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4644180, "photo_title": "Bridalveil Falls from Valley View", "photo_url": "http://www.panoramio.com/photo/4644180", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4644180.jpg", "longitude": -119.661723, "latitude": 37.717419, "width": 500, "height": 357, "upload_date": "14 September 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 457302, "photo_title": "Matterhorn Zermatt", "photo_url": "http://www.panoramio.com/photo/457302", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/457302.jpg", "longitude": 7.746391, "latitude": 46.016992, "width": 500, "height": 375, "upload_date": "16 January 2007", "owner_id": 47930, "owner_name": "werni", "owner_url": "http://www.panoramio.com/user/47930"} +, +{"photo_id": 4258138, "photo_title": "Szentkút", "photo_url": "http://www.panoramio.com/photo/4258138", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4258138.jpg", "longitude": 17.731848, "latitude": 47.243755, "width": 500, "height": 334, "upload_date": "28 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 26986, "photo_title": "Cementerio General", "photo_url": "http://www.panoramio.com/photo/26986", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/26986.jpg", "longitude": -84.091158, "latitude": 9.930047, "width": 500, "height": 373, "upload_date": "23 June 2006", "owner_id": 4112, "owner_name": "Roberto Garcia", "owner_url": "http://www.panoramio.com/user/4112"} +, +{"photo_id": 1269869, "photo_title": "Barents Sea at night, Finnmark, Norway", "photo_url": "http://www.panoramio.com/photo/1269869", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1269869.jpg", "longitude": 30.868149, "latitude": 70.438638, "width": 500, "height": 324, "upload_date": "11 March 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 515971, "photo_title": "A hosszútávfutó magányossága", "photo_url": "http://www.panoramio.com/photo/515971", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/515971.jpg", "longitude": 17.870121, "latitude": 47.373012, "width": 500, "height": 276, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 36486, "photo_title": "Sunrise on Trondheimsfjord", "photo_url": "http://www.panoramio.com/photo/36486", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36486.jpg", "longitude": 10.333843, "latitude": 63.456186, "width": 500, "height": 332, "upload_date": "02 August 2006", "owner_id": 5703, "owner_name": "dancer", "owner_url": "http://www.panoramio.com/user/5703"} +, +{"photo_id": 4950702, "photo_title": "Abandoned Gas Stand, Hachimantai, Iwate, Japan", "photo_url": "http://www.panoramio.com/photo/4950702", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4950702.jpg", "longitude": 141.062308, "latitude": 39.955547, "width": 500, "height": 335, "upload_date": "28 September 2007", "owner_id": 699984, "owner_name": "Fried Toast", "owner_url": "http://www.panoramio.com/user/699984"} +, +{"photo_id": 2345653, "photo_title": "planet mars", "photo_url": "http://www.panoramio.com/photo/2345653", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2345653.jpg", "longitude": 33.631908, "latitude": 27.380118, "width": 500, "height": 322, "upload_date": "22 May 2007", "owner_id": 223374, "owner_name": "voutsen", "owner_url": "http://www.panoramio.com/user/223374"} +, +{"photo_id": 4612307, "photo_title": "Sitges - Spinaker", "photo_url": "http://www.panoramio.com/photo/4612307", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4612307.jpg", "longitude": 1.859436, "latitude": 41.211722, "width": 500, "height": 371, "upload_date": "13 September 2007", "owner_id": 138691, "owner_name": "Josep Maria Alegre", "owner_url": "http://www.panoramio.com/user/138691"} +, +{"photo_id": 4644311, "photo_title": "Through the Looking Glass", "photo_url": "http://www.panoramio.com/photo/4644311", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4644311.jpg", "longitude": -119.649745, "latitude": 37.722019, "width": 333, "height": 500, "upload_date": "14 September 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 1480664, "photo_title": "Királyi szurkolótábor", "photo_url": "http://www.panoramio.com/photo/1480664", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1480664.jpg", "longitude": 17.300034, "latitude": 47.190646, "width": 500, "height": 269, "upload_date": "24 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8492774, "photo_title": "Lago Fedaia in estate Panoramio and ATP first CONTEST, March 2008, category Scenery : awarded \" Honorable Mention\". Many thanks to all voters", "photo_url": "http://www.panoramio.com/photo/8492774", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8492774.jpg", "longitude": 11.867519, "latitude": 46.463128, "width": 500, "height": 375, "upload_date": "12 March 2008", "owner_id": 6033, "owner_name": "â–º Marco Vanzo", "owner_url": "http://www.panoramio.com/user/6033"} +, +{"photo_id": 57835, "photo_title": "Seewaldsee 2 - St.Koloman", "photo_url": "http://www.panoramio.com/photo/57835", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57835.jpg", "longitude": 13.274918, "latitude": 47.630115, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 57837, "photo_title": "Der Hraunfossar an einem kalten Wintertag .....(MS)", "photo_url": "http://www.panoramio.com/photo/57837", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57837.jpg", "longitude": -20.939941, "latitude": 64.698078, "width": 500, "height": 264, "upload_date": "05 October 2006", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 70641, "photo_title": "Lake Nakuru (Kenya)", "photo_url": "http://www.panoramio.com/photo/70641", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/70641.jpg", "longitude": 36.114979, "latitude": -0.324782, "width": 500, "height": 333, "upload_date": "25 October 2006", "owner_id": 8975, "owner_name": "Laura Sayalero", "owner_url": "http://www.panoramio.com/user/8975"} +, +{"photo_id": 766205, "photo_title": "posta sol porto colom", "photo_url": "http://www.panoramio.com/photo/766205", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/766205.jpg", "longitude": 3.264495, "latitude": 39.425093, "width": 500, "height": 335, "upload_date": "10 February 2007", "owner_id": 134682, "owner_name": "------ Cafate ------", "owner_url": "http://www.panoramio.com/user/134682"} +, +{"photo_id": 10662910, "photo_title": "Megvilágosodván", "photo_url": "http://www.panoramio.com/photo/10662910", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10662910.jpg", "longitude": 17.718544, "latitude": 47.460130, "width": 500, "height": 334, "upload_date": "27 May 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8703547, "photo_title": "Lonely bike-rider", "photo_url": "http://www.panoramio.com/photo/8703547", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8703547.jpg", "longitude": 6.039004, "latitude": 52.208974, "width": 500, "height": 467, "upload_date": "21 March 2008", "owner_id": 523564, "owner_name": "Luud Riphagen", "owner_url": "http://www.panoramio.com/user/523564"} +, +{"photo_id": 11669907, "photo_title": "Alba sulle pale di San Martino", "photo_url": "http://www.panoramio.com/photo/11669907", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11669907.jpg", "longitude": 11.568518, "latitude": 46.345269, "width": 500, "height": 361, "upload_date": "30 June 2008", "owner_id": 6033, "owner_name": "â–º Marco Vanzo", "owner_url": "http://www.panoramio.com/user/6033"} +, +{"photo_id": 11403916, "photo_title": "Lonely", "photo_url": "http://www.panoramio.com/photo/11403916", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11403916.jpg", "longitude": 18.164520, "latitude": 46.345269, "width": 500, "height": 375, "upload_date": "21 June 2008", "owner_id": 328249, "owner_name": "v.zsoloo", "owner_url": "http://www.panoramio.com/user/328249"} +, +{"photo_id": 289803, "photo_title": "Rain Clouds", "photo_url": "http://www.panoramio.com/photo/289803", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/289803.jpg", "longitude": -57.733154, "latitude": -51.661908, "width": 500, "height": 335, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 123413, "photo_title": "Paisaje cromático de Landmanalaugar", "photo_url": "http://www.panoramio.com/photo/123413", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/123413.jpg", "longitude": -19.085140, "latitude": 63.918285, "width": 500, "height": 332, "upload_date": "12 December 2006", "owner_id": 20549, "owner_name": "oscarvg", "owner_url": "http://www.panoramio.com/user/20549"} +, +{"photo_id": 595734, "photo_title": "Sphinx profile", "photo_url": "http://www.panoramio.com/photo/595734", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/595734.jpg", "longitude": 31.137791, "latitude": 29.975034, "width": 500, "height": 330, "upload_date": "27 January 2007", "owner_id": 124418, "owner_name": "Pierre-Jean Durieu", "owner_url": "http://www.panoramio.com/user/124418"} +, +{"photo_id": 3282726, "photo_title": "Shanghai - Inside the Jinmao Tower", "photo_url": "http://www.panoramio.com/photo/3282726", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3282726.jpg", "longitude": 121.501153, "latitude": 31.237519, "width": 500, "height": 335, "upload_date": "13 July 2007", "owner_id": 578163, "owner_name": "Margherita-Italy", "owner_url": "http://www.panoramio.com/user/578163"} +, +{"photo_id": 1346342, "photo_title": "nemrut", "photo_url": "http://www.panoramio.com/photo/1346342", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1346342.jpg", "longitude": 38.761826, "latitude": 38.042413, "width": 340, "height": 500, "upload_date": "16 March 2007", "owner_id": 2659, "owner_name": "ozalph", "owner_url": "http://www.panoramio.com/user/2659"} +, +{"photo_id": 151849, "photo_title": "panoramas photo @ the cross at Xin-Yi and Kee-Lung road ( my 2nd try )", "photo_url": "http://www.panoramio.com/photo/151849", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/151849.jpg", "longitude": 121.559209, "latitude": 25.033073, "width": 500, "height": 348, "upload_date": "15 December 2006", "owner_id": 27791, "owner_name": "Jerome Chen", "owner_url": "http://www.panoramio.com/user/27791"} +, +{"photo_id": 1212973, "photo_title": "Perhaps Neruda's View", "photo_url": "http://www.panoramio.com/photo/1212973", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1212973.jpg", "longitude": 14.398935, "latitude": 50.084752, "width": 500, "height": 333, "upload_date": "07 March 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 809789, "photo_title": "Pihike", "photo_url": "http://www.panoramio.com/photo/809789", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/809789.jpg", "longitude": 17.457018, "latitude": 47.881010, "width": 500, "height": 387, "upload_date": "13 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 88150, "photo_title": "Marmore Falls - Umbria - Italy", "photo_url": "http://www.panoramio.com/photo/88150", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/88150.jpg", "longitude": 12.716667, "latitude": 42.550000, "width": 375, "height": 500, "upload_date": "28 November 2006", "owner_id": 11098, "owner_name": "Michele Masnata", "owner_url": "http://www.panoramio.com/user/11098"} +, +{"photo_id": 624990, "photo_title": "Mélyrepülés", "photo_url": "http://www.panoramio.com/photo/624990", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/624990.jpg", "longitude": 17.455988, "latitude": 47.881931, "width": 500, "height": 288, "upload_date": "30 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 612449, "photo_title": "Rio de Janeiro - Vista do Corcovado ©G.Schüür", "photo_url": "http://www.panoramio.com/photo/612449", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/612449.jpg", "longitude": -43.210323, "latitude": -22.951463, "width": 500, "height": 400, "upload_date": "29 January 2007", "owner_id": 120756, "owner_name": "Germano Schüür", "owner_url": "http://www.panoramio.com/user/120756"} +, +{"photo_id": 1545313, "photo_title": "Tempestade", "photo_url": "http://www.panoramio.com/photo/1545313", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1545313.jpg", "longitude": -48.678703, "latitude": -26.643470, "width": 500, "height": 341, "upload_date": "29 March 2007", "owner_id": 160342, "owner_name": "Jakson Santos", "owner_url": "http://www.panoramio.com/user/160342"} +, +{"photo_id": 1595492, "photo_title": "Explosión Rosa", "photo_url": "http://www.panoramio.com/photo/1595492", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1595492.jpg", "longitude": -73.250393, "latitude": -39.813481, "width": 500, "height": 375, "upload_date": "02 April 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 5501284, "photo_title": "Da qui passano i sogni...", "photo_url": "http://www.panoramio.com/photo/5501284", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5501284.jpg", "longitude": 12.335930, "latitude": 45.435563, "width": 375, "height": 500, "upload_date": "23 October 2007", "owner_id": 325031, "owner_name": "Gibrail", "owner_url": "http://www.panoramio.com/user/325031"} +, +{"photo_id": 444265, "photo_title": "Cafe, Calle and Capitol of Cuba", "photo_url": "http://www.panoramio.com/photo/444265", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/444265.jpg", "longitude": -82.350453, "latitude": 23.136354, "width": 500, "height": 375, "upload_date": "15 January 2007", "owner_id": 57893, "owner_name": "ThoiryK", "owner_url": "http://www.panoramio.com/user/57893"} +, +{"photo_id": 9590, "photo_title": "South Street Seaport and Financial Center Skyline [007783]", "photo_url": "http://www.panoramio.com/photo/9590", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9590.jpg", "longitude": -74.001760, "latitude": 40.704937, "width": 500, "height": 375, "upload_date": "04 February 2006", "owner_id": 1489, "owner_name": "Thorsten", "owner_url": "http://www.panoramio.com/user/1489"} +, +{"photo_id": 204153, "photo_title": "Stormheimfjell and Hamperokken mountains near Brevikeidet ", "photo_url": "http://www.panoramio.com/photo/204153", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/204153.jpg", "longitude": 19.650421, "latitude": 69.668899, "width": 500, "height": 375, "upload_date": "21 December 2006", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 916095, "photo_title": "Before daybreak on Mount Etna (as seen from Piano Provenzana)", "photo_url": "http://www.panoramio.com/photo/916095", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/916095.jpg", "longitude": 15.038610, "latitude": 37.793881, "width": 500, "height": 375, "upload_date": "20 February 2007", "owner_id": 67714, "owner_name": "Robert Gulyas", "owner_url": "http://www.panoramio.com/user/67714"} +, +{"photo_id": 680320, "photo_title": "A severe storm approaches Nyngan, NSW www.ozthunder.com", "photo_url": "http://www.panoramio.com/photo/680320", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/680320.jpg", "longitude": 147.154312, "latitude": -31.563910, "width": 500, "height": 378, "upload_date": "04 February 2007", "owner_id": 67208, "owner_name": "Michael Thompson", "owner_url": "http://www.panoramio.com/user/67208"} +, +{"photo_id": 6018, "photo_title": "Jadrija - barke", "photo_url": "http://www.panoramio.com/photo/6018", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6018.jpg", "longitude": 15.841599, "latitude": 43.725026, "width": 500, "height": 176, "upload_date": "18 December 2005", "owner_id": 991, "owner_name": "Mario Marotti", "owner_url": "http://www.panoramio.com/user/991"} +, +{"photo_id": 36485, "photo_title": "Great Belt Bridge", "photo_url": "http://www.panoramio.com/photo/36485", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36485.jpg", "longitude": 11.029501, "latitude": 55.342130, "width": 500, "height": 332, "upload_date": "02 August 2006", "owner_id": 5703, "owner_name": "dancer", "owner_url": "http://www.panoramio.com/user/5703"} +, +{"photo_id": 19098, "photo_title": "Jökulsárlón", "photo_url": "http://www.panoramio.com/photo/19098", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/19098.jpg", "longitude": -16.355896, "latitude": 64.037351, "width": 500, "height": 333, "upload_date": "02 May 2006", "owner_id": 2885, "owner_name": "Luis Rodríguez Baena", "owner_url": "http://www.panoramio.com/user/2885"} +, +{"photo_id": 55458, "photo_title": "034 Troianisches Pferd", "photo_url": "http://www.panoramio.com/photo/55458", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/55458.jpg", "longitude": 26.240464, "latitude": 39.957188, "width": 375, "height": 500, "upload_date": "01 October 2006", "owner_id": 7633, "owner_name": "Daniel Meyer", "owner_url": "http://www.panoramio.com/user/7633"} +, +{"photo_id": 1800357, "photo_title": "Beach & Evening Light - Garrapata State Park Big Sur, CA", "photo_url": "http://www.panoramio.com/photo/1800357", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1800357.jpg", "longitude": -121.925915, "latitude": 36.455437, "width": 500, "height": 345, "upload_date": "16 April 2007", "owner_id": 107613, "owner_name": "Tom Grubbe", "owner_url": "http://www.panoramio.com/user/107613"} +, +{"photo_id": 1447086, "photo_title": "Odyssey", "photo_url": "http://www.panoramio.com/photo/1447086", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1447086.jpg", "longitude": 15.923395, "latitude": 43.589530, "width": 500, "height": 323, "upload_date": "22 March 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 10378421, "photo_title": "Red Bus", "photo_url": "http://www.panoramio.com/photo/10378421", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10378421.jpg", "longitude": -0.124497, "latitude": 51.500809, "width": 414, "height": 500, "upload_date": "19 May 2008", "owner_id": 325031, "owner_name": "Gibrail", "owner_url": "http://www.panoramio.com/user/325031"} +, +{"photo_id": 1087672, "photo_title": "És azután menydörgést hallottunk...", "photo_url": "http://www.panoramio.com/photo/1087672", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1087672.jpg", "longitude": 15.917473, "latitude": 43.590836, "width": 500, "height": 299, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 74950, "photo_title": "高åƒç©‚", "photo_url": "http://www.panoramio.com/photo/74950", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/74950.jpg", "longitude": 131.019516, "latitude": 32.320504, "width": 500, "height": 375, "upload_date": "03 November 2006", "owner_id": 9556, "owner_name": "shigesato", "owner_url": "http://www.panoramio.com/user/9556"} +, +{"photo_id": 1749978, "photo_title": "Campos de Criptana", "photo_url": "http://www.panoramio.com/photo/1749978", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1749978.jpg", "longitude": -3.123207, "latitude": 39.409805, "width": 500, "height": 334, "upload_date": "12 April 2007", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 94171, "photo_title": "Matsumoto Castle", "photo_url": "http://www.panoramio.com/photo/94171", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/94171.jpg", "longitude": 137.967778, "latitude": 36.239194, "width": 408, "height": 500, "upload_date": "09 December 2006", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 2053084, "photo_title": "Blue lagoon, Melchior islands", "photo_url": "http://www.panoramio.com/photo/2053084", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2053084.jpg", "longitude": -62.830811, "latitude": -64.415921, "width": 500, "height": 336, "upload_date": "03 May 2007", "owner_id": 3316, "owner_name": "kristine hannon (www.traveltheglobe.be)", "owner_url": "http://www.panoramio.com/user/3316"} +, +{"photo_id": 86244, "photo_title": "Palmeras", "photo_url": "http://www.panoramio.com/photo/86244", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/86244.jpg", "longitude": -1.116829, "latitude": 37.930930, "width": 333, "height": 500, "upload_date": "25 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 629489, "photo_title": "Hare in winter fur...beast of the Cave of Caerbannog.", "photo_url": "http://www.panoramio.com/photo/629489", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/629489.jpg", "longitude": -105.645390, "latitude": 40.296593, "width": 500, "height": 376, "upload_date": "31 January 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 8459506, "photo_title": "Baltic sunrise in Kiel", "photo_url": "http://www.panoramio.com/photo/8459506", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8459506.jpg", "longitude": 10.169671, "latitude": 54.430970, "width": 500, "height": 375, "upload_date": "11 March 2008", "owner_id": 73946, "owner_name": "pembo", "owner_url": "http://www.panoramio.com/user/73946"} +, +{"photo_id": 36599, "photo_title": "ц Ð—Ð°Ñ‡Ð°Ñ‚Ð¸Ñ Ðнны на Углу", "photo_url": "http://www.panoramio.com/photo/36599", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36599.jpg", "longitude": 37.630963, "latitude": 55.750159, "width": 500, "height": 375, "upload_date": "03 August 2006", "owner_id": 5641, "owner_name": "sergey duhanin", "owner_url": "http://www.panoramio.com/user/5641"} +, +{"photo_id": 62716, "photo_title": "Amanecer en la Sauceda", "photo_url": "http://www.panoramio.com/photo/62716", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/62716.jpg", "longitude": -5.591730, "latitude": 36.521630, "width": 500, "height": 330, "upload_date": "15 October 2006", "owner_id": 473, "owner_name": "Juanlu", "owner_url": "http://www.panoramio.com/user/473"} +, +{"photo_id": 4709631, "photo_title": "The sun sets in the East....", "photo_url": "http://www.panoramio.com/photo/4709631", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4709631.jpg", "longitude": -112.624583, "latitude": 45.211038, "width": 500, "height": 375, "upload_date": "17 September 2007", "owner_id": 71099, "owner_name": "Eve in Montana", "owner_url": "http://www.panoramio.com/user/71099"} +, +{"photo_id": 11408203, "photo_title": "05-08-31_Paramo de MASA_PIXELECTA", "photo_url": "http://www.panoramio.com/photo/11408203", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11408203.jpg", "longitude": -3.536568, "latitude": 42.669357, "width": 500, "height": 375, "upload_date": "21 June 2008", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 416263, "photo_title": "Mt. Meeker at Dawn", "photo_url": "http://www.panoramio.com/photo/416263", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/416263.jpg", "longitude": -105.579643, "latitude": 40.270472, "width": 500, "height": 374, "upload_date": "13 January 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 1289233, "photo_title": " High Dades", "photo_url": "http://www.panoramio.com/photo/1289233", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1289233.jpg", "longitude": -5.838375, "latitude": 31.652066, "width": 500, "height": 329, "upload_date": "12 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 1567767, "photo_title": "Rosina Lamberti - Sunset Templestowe, 31 March 2007", "photo_url": "http://www.panoramio.com/photo/1567767", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1567767.jpg", "longitude": 145.133858, "latitude": -37.765015, "width": 500, "height": 237, "upload_date": "31 March 2007", "owner_id": 140796, "owner_name": "rosina lamberti", "owner_url": "http://www.panoramio.com/user/140796"} +, +{"photo_id": 4130842, "photo_title": "Ãrvore Solar", "photo_url": "http://www.panoramio.com/photo/4130842", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4130842.jpg", "longitude": -51.830320, "latitude": -22.939424, "width": 427, "height": 500, "upload_date": "23 August 2007", "owner_id": 465654, "owner_name": "Carlos Sica", "owner_url": "http://www.panoramio.com/user/465654"} +, +{"photo_id": 340508, "photo_title": "Sunset from Camelback Mountain Echo Trail", "photo_url": "http://www.panoramio.com/photo/340508", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/340508.jpg", "longitude": -111.969969, "latitude": 33.520820, "width": 333, "height": 500, "upload_date": "08 January 2007", "owner_id": 45308, "owner_name": "Mike Cavaroc", "owner_url": "http://www.panoramio.com/user/45308"} +, +{"photo_id": 74792, "photo_title": "annapurna south", "photo_url": "http://www.panoramio.com/photo/74792", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/74792.jpg", "longitude": 83.804398, "latitude": 28.524813, "width": 500, "height": 334, "upload_date": "03 November 2006", "owner_id": 9812, "owner_name": "wsm earp", "owner_url": "http://www.panoramio.com/user/9812"} +, +{"photo_id": 4445995, "photo_title": "Ködvarázs", "photo_url": "http://www.panoramio.com/photo/4445995", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4445995.jpg", "longitude": 18.053970, "latitude": 47.276783, "width": 500, "height": 334, "upload_date": "06 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3032620, "photo_title": "Mira sin bueyes", "photo_url": "http://www.panoramio.com/photo/3032620", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3032620.jpg", "longitude": -8.802710, "latitude": 40.459324, "width": 500, "height": 327, "upload_date": "30 June 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 415533, "photo_title": "Manila Sunset", "photo_url": "http://www.panoramio.com/photo/415533", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/415533.jpg", "longitude": 120.984208, "latitude": 14.572339, "width": 333, "height": 500, "upload_date": "13 January 2007", "owner_id": 20398, "owner_name": "boerx", "owner_url": "http://www.panoramio.com/user/20398"} +, +{"photo_id": 723004, "photo_title": "Bouncing Light", "photo_url": "http://www.panoramio.com/photo/723004", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723004.jpg", "longitude": 25.379276, "latitude": 36.461468, "width": 500, "height": 332, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 2514494, "photo_title": "klatschmohn bis zum Horizont", "photo_url": "http://www.panoramio.com/photo/2514494", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2514494.jpg", "longitude": 12.025051, "latitude": 54.145244, "width": 500, "height": 334, "upload_date": "01 June 2007", "owner_id": 82603, "owner_name": "HelgeNug", "owner_url": "http://www.panoramio.com/user/82603"} +, +{"photo_id": 436289, "photo_title": "koaganogawa", "photo_url": "http://www.panoramio.com/photo/436289", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436289.jpg", "longitude": 139.065456, "latitude": 37.831548, "width": 500, "height": 341, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 73027, "photo_title": "Concourse, British Museum", "photo_url": "http://www.panoramio.com/photo/73027", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/73027.jpg", "longitude": -0.127201, "latitude": 51.519532, "width": 500, "height": 326, "upload_date": "29 October 2006", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 9766996, "photo_title": "Racetrack Playa", "photo_url": "http://www.panoramio.com/photo/9766996", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9766996.jpg", "longitude": -117.558091, "latitude": 36.664815, "width": 388, "height": 500, "upload_date": "29 April 2008", "owner_id": 308300, "owner_name": "Tony R Immoos", "owner_url": "http://www.panoramio.com/user/308300"} +, +{"photo_id": 1455193, "photo_title": "Вулкан КарымÑкий, Ñо Ñклона вулкана Малый СемÑчик", "photo_url": "http://www.panoramio.com/photo/1455193", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1455193.jpg", "longitude": 159.626970, "latitude": 54.133227, "width": 500, "height": 345, "upload_date": "23 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 1234797, "photo_title": "Sahalie Falls, Mckenzie River", "photo_url": "http://www.panoramio.com/photo/1234797", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1234797.jpg", "longitude": -121.997187, "latitude": 44.348769, "width": 500, "height": 420, "upload_date": "09 March 2007", "owner_id": 128746, "owner_name": "© Michael Hatten", "owner_url": "http://www.panoramio.com/user/128746"} +, +{"photo_id": 3989102, "photo_title": "El Gran Miércoles", "photo_url": "http://www.panoramio.com/photo/3989102", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3989102.jpg", "longitude": -17.991056, "latitude": 27.797638, "width": 500, "height": 375, "upload_date": "17 August 2007", "owner_id": 787217, "owner_name": "♣ Víctor S de Lara ♣", "owner_url": "http://www.panoramio.com/user/787217"} +, +{"photo_id": 85625, "photo_title": "Cañón de Valdeinfiernos", "photo_url": "http://www.panoramio.com/photo/85625", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/85625.jpg", "longitude": -1.961060, "latitude": 37.801511, "width": 333, "height": 500, "upload_date": "24 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 4558716, "photo_title": "Corsica - West Coast", "photo_url": "http://www.panoramio.com/photo/4558716", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4558716.jpg", "longitude": 8.655338, "latitude": 42.253108, "width": 500, "height": 341, "upload_date": "10 September 2007", "owner_id": 49870, "owner_name": "Jean-Michel Raggioli", "owner_url": "http://www.panoramio.com/user/49870"} +, +{"photo_id": 3201916, "photo_title": "Mönch", "photo_url": "http://www.panoramio.com/photo/3201916", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3201916.jpg", "longitude": 7.640026, "latitude": 46.745537, "width": 500, "height": 374, "upload_date": "09 July 2007", "owner_id": 635422, "owner_name": "♫ Swissmay", "owner_url": "http://www.panoramio.com/user/635422"} +, +{"photo_id": 4365440, "photo_title": "a piece of wood", "photo_url": "http://www.panoramio.com/photo/4365440", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4365440.jpg", "longitude": -1.254158, "latitude": 44.480463, "width": 221, "height": 500, "upload_date": "03 September 2007", "owner_id": 521836, "owner_name": "KLEFER", "owner_url": "http://www.panoramio.com/user/521836"} +, +{"photo_id": 124545, "photo_title": "66_St-Cyp_vagues_01", "photo_url": "http://www.panoramio.com/photo/124545", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/124545.jpg", "longitude": 3.037736, "latitude": 42.623436, "width": 500, "height": 333, "upload_date": "12 December 2006", "owner_id": 18696, "owner_name": "Besnard", "owner_url": "http://www.panoramio.com/user/18696"} +, +{"photo_id": 65666, "photo_title": "Barco fantasma", "photo_url": "http://www.panoramio.com/photo/65666", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/65666.jpg", "longitude": -14.179380, "latitude": 28.344878, "width": 500, "height": 375, "upload_date": "18 October 2006", "owner_id": 8658, "owner_name": "Canarina", "owner_url": "http://www.panoramio.com/user/8658"} +, +{"photo_id": 573064, "photo_title": "Looking west across Isfjorden", "photo_url": "http://www.panoramio.com/photo/573064", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/573064.jpg", "longitude": 7.681332, "latitude": 62.558395, "width": 500, "height": 332, "upload_date": "26 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 859786, "photo_title": "Aurora Borealis, Andøya, VesterÃ¥len, Norway", "photo_url": "http://www.panoramio.com/photo/859786", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/859786.jpg", "longitude": 15.605392, "latitude": 69.118548, "width": 500, "height": 377, "upload_date": "17 February 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 507024, "photo_title": "Agrárcolorgeometria", "photo_url": "http://www.panoramio.com/photo/507024", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507024.jpg", "longitude": 18.014488, "latitude": 47.316017, "width": 500, "height": 300, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6665111, "photo_title": "Coucher du soleil depuis les Crêts", "photo_url": "http://www.panoramio.com/photo/6665111", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6665111.jpg", "longitude": 6.172214, "latitude": 46.129129, "width": 500, "height": 375, "upload_date": "24 December 2007", "owner_id": 359127, "owner_name": "wx", "owner_url": "http://www.panoramio.com/user/359127"} +, +{"photo_id": 679331, "photo_title": "wentworth falls", "photo_url": "http://www.panoramio.com/photo/679331", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/679331.jpg", "longitude": 150.371124, "latitude": -33.727111, "width": 498, "height": 500, "upload_date": "04 February 2007", "owner_id": 146092, "owner_name": "sid1662", "owner_url": "http://www.panoramio.com/user/146092"} +, +{"photo_id": 459436, "photo_title": "aikawa", "photo_url": "http://www.panoramio.com/photo/459436", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459436.jpg", "longitude": 138.234701, "latitude": 37.998936, "width": 500, "height": 341, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 31662, "photo_title": "NY_7_GE", "photo_url": "http://www.panoramio.com/photo/31662", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/31662.jpg", "longitude": -73.977041, "latitude": 40.761528, "width": 452, "height": 500, "upload_date": "11 July 2006", "owner_id": 4657, "owner_name": "Giuseppe Grande", "owner_url": "http://www.panoramio.com/user/4657"} +, +{"photo_id": 1488304, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/1488304", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1488304.jpg", "longitude": 138.135223, "latitude": 36.848719, "width": 383, "height": 500, "upload_date": "25 March 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 181939, "photo_title": "The Eiffel Tower, Paris", "photo_url": "http://www.panoramio.com/photo/181939", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/181939.jpg", "longitude": 2.288718, "latitude": 48.861920, "width": 384, "height": 500, "upload_date": "18 December 2006", "owner_id": 12954, "owner_name": "ZiÄ™bol", "owner_url": "http://www.panoramio.com/user/12954"} +, +{"photo_id": 2422198, "photo_title": "In the Pine's Shade", "photo_url": "http://www.panoramio.com/photo/2422198", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2422198.jpg", "longitude": -112.393484, "latitude": 44.580075, "width": 500, "height": 333, "upload_date": "27 May 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 2363576, "photo_title": "Cienfuegos Yacht Club", "photo_url": "http://www.panoramio.com/photo/2363576", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2363576.jpg", "longitude": -80.450901, "latitude": 22.126499, "width": 500, "height": 306, "upload_date": "23 May 2007", "owner_id": 2575, "owner_name": "mikel ortega", "owner_url": "http://www.panoramio.com/user/2575"} +, +{"photo_id": 58296, "photo_title": "Liechtensteinklamm 2", "photo_url": "http://www.panoramio.com/photo/58296", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58296.jpg", "longitude": 13.190546, "latitude": 47.310140, "width": 333, "height": 500, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 507328, "photo_title": "Pillantás a hídról", "photo_url": "http://www.panoramio.com/photo/507328", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/507328.jpg", "longitude": 17.629859, "latitude": 47.687102, "width": 500, "height": 334, "upload_date": "20 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 468161, "photo_title": "Honfleur", "photo_url": "http://www.panoramio.com/photo/468161", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/468161.jpg", "longitude": 0.234833, "latitude": 49.421806, "width": 500, "height": 350, "upload_date": "17 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 2521031, "photo_title": "Derűs délután", "photo_url": "http://www.panoramio.com/photo/2521031", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2521031.jpg", "longitude": 17.523537, "latitude": 47.751790, "width": 380, "height": 500, "upload_date": "02 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 934105, "photo_title": "Times Square", "photo_url": "http://www.panoramio.com/photo/934105", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/934105.jpg", "longitude": -73.986762, "latitude": 40.756652, "width": 375, "height": 500, "upload_date": "21 February 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 57824, "photo_title": "Hallstatt 3", "photo_url": "http://www.panoramio.com/photo/57824", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57824.jpg", "longitude": 13.642616, "latitude": 47.556372, "width": 500, "height": 333, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 1370861, "photo_title": "Wanganui Sunrise", "photo_url": "http://www.panoramio.com/photo/1370861", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1370861.jpg", "longitude": 175.053218, "latitude": -39.927193, "width": 500, "height": 400, "upload_date": "17 March 2007", "owner_id": 286729, "owner_name": "jimwitkowski", "owner_url": "http://www.panoramio.com/user/286729"} +, +{"photo_id": 4823023, "photo_title": "Cielo en llamas ( Sky on fire )", "photo_url": "http://www.panoramio.com/photo/4823023", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4823023.jpg", "longitude": -0.471725, "latitude": 39.601588, "width": 500, "height": 375, "upload_date": "22 September 2007", "owner_id": 787217, "owner_name": "♣ Víctor S de Lara ♣", "owner_url": "http://www.panoramio.com/user/787217"} +, +{"photo_id": 520945, "photo_title": "Estvarázs", "photo_url": "http://www.panoramio.com/photo/520945", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/520945.jpg", "longitude": 17.627692, "latitude": 47.665156, "width": 500, "height": 334, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 818423, "photo_title": "Karst Countryside in Guangxi, China", "photo_url": "http://www.panoramio.com/photo/818423", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/818423.jpg", "longitude": 106.953964, "latitude": 22.716023, "width": 500, "height": 206, "upload_date": "14 February 2007", "owner_id": 164125, "owner_name": "DannyXu", "owner_url": "http://www.panoramio.com/user/164125"} +, +{"photo_id": 532730, "photo_title": "Nightfall and fog at lake Helgeren", "photo_url": "http://www.panoramio.com/photo/532730", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532730.jpg", "longitude": 10.708923, "latitude": 60.074348, "width": 419, "height": 500, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 650237, "photo_title": "Aruba, Eagle Beach, Divi Divi Tree", "photo_url": "http://www.panoramio.com/photo/650237", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/650237.jpg", "longitude": -70.055099, "latitude": 12.555003, "width": 500, "height": 375, "upload_date": "01 February 2007", "owner_id": 136446, "owner_name": "© Wim", "owner_url": "http://www.panoramio.com/user/136446"} +, +{"photo_id": 2414590, "photo_title": "Egy csendes estén", "photo_url": "http://www.panoramio.com/photo/2414590", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2414590.jpg", "longitude": 17.626448, "latitude": 47.662613, "width": 500, "height": 334, "upload_date": "27 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 10544520, "photo_title": "Plansee", "photo_url": "http://www.panoramio.com/photo/10544520", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10544520.jpg", "longitude": 10.799389, "latitude": 47.473011, "width": 500, "height": 242, "upload_date": "24 May 2008", "owner_id": 634000, "owner_name": "© Massimo De Candido", "owner_url": "http://www.panoramio.com/user/634000"} +, +{"photo_id": 11341211, "photo_title": "AMAPOLAS AL SOL", "photo_url": "http://www.panoramio.com/photo/11341211", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11341211.jpg", "longitude": -1.995735, "latitude": 42.471844, "width": 500, "height": 374, "upload_date": "19 June 2008", "owner_id": 1487989, "owner_name": "mesias", "owner_url": "http://www.panoramio.com/user/1487989"} +, +{"photo_id": 134748, "photo_title": "20060813_9795_raw", "photo_url": "http://www.panoramio.com/photo/134748", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/134748.jpg", "longitude": 30.452921, "latitude": 50.358700, "width": 500, "height": 333, "upload_date": "13 December 2006", "owner_id": 17090, "owner_name": "Pavel Danko", "owner_url": "http://www.panoramio.com/user/17090"} +, +{"photo_id": 66816, "photo_title": "desierto cerca de Tolar Grande", "photo_url": "http://www.panoramio.com/photo/66816", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/66816.jpg", "longitude": -67.394257, "latitude": -24.584593, "width": 374, "height": 500, "upload_date": "19 October 2006", "owner_id": 9080, "owner_name": "Marco Teodonio", "owner_url": "http://www.panoramio.com/user/9080"} +, +{"photo_id": 70148, "photo_title": "Grotto Azure, Capris: The cave is lit by light refracting through the water.", "photo_url": "http://www.panoramio.com/photo/70148", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/70148.jpg", "longitude": 14.203262, "latitude": 40.560895, "width": 500, "height": 375, "upload_date": "25 October 2006", "owner_id": 1634, "owner_name": "Rick Guthrie", "owner_url": "http://www.panoramio.com/user/1634"} +, +{"photo_id": 1409801, "photo_title": "Hedges, Aerial", "photo_url": "http://www.panoramio.com/photo/1409801", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1409801.jpg", "longitude": 9.027843, "latitude": 56.130772, "width": 332, "height": 500, "upload_date": "20 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 840971, "photo_title": "Upper Thracian Lowlands", "photo_url": "http://www.panoramio.com/photo/840971", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/840971.jpg", "longitude": 26.364269, "latitude": 42.717759, "width": 500, "height": 400, "upload_date": "16 February 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 9557772, "photo_title": "Le Shan Giant Buddha Statue - Geotagged April 08 Photo Contest Heritage Category Honorable Mentions", "photo_url": "http://www.panoramio.com/photo/9557772", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9557772.jpg", "longitude": 103.769115, "latitude": 29.547084, "width": 375, "height": 500, "upload_date": "20 April 2008", "owner_id": 964751, "owner_name": "jymsn123", "owner_url": "http://www.panoramio.com/user/964751"} +, +{"photo_id": 4716049, "photo_title": "Sol-edad", "photo_url": "http://www.panoramio.com/photo/4716049", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4716049.jpg", "longitude": -73.228008, "latitude": -39.820720, "width": 366, "height": 500, "upload_date": "17 September 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 1419283, "photo_title": "Sunset in Boka", "photo_url": "http://www.panoramio.com/photo/1419283", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1419283.jpg", "longitude": 18.703022, "latitude": 42.479883, "width": 500, "height": 375, "upload_date": "20 March 2007", "owner_id": 239453, "owner_name": "Å ovran NikÅ¡a", "owner_url": "http://www.panoramio.com/user/239453"} +, +{"photo_id": 3507222, "photo_title": "The sheperd of the Glen", "photo_url": "http://www.panoramio.com/photo/3507222", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3507222.jpg", "longitude": -4.840164, "latitude": 56.641504, "width": 500, "height": 334, "upload_date": "24 July 2007", "owner_id": 599676, "owner_name": "mossip", "owner_url": "http://www.panoramio.com/user/599676"} +, +{"photo_id": 3521820, "photo_title": "Utolsó pillantás", "photo_url": "http://www.panoramio.com/photo/3521820", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3521820.jpg", "longitude": 17.809353, "latitude": 47.528097, "width": 500, "height": 334, "upload_date": "25 July 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 521264, "photo_title": "Felhőátvonulás", "photo_url": "http://www.panoramio.com/photo/521264", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/521264.jpg", "longitude": 17.760429, "latitude": 47.555329, "width": 500, "height": 280, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 636723, "photo_title": "ASZFALTOZÓK", "photo_url": "http://www.panoramio.com/photo/636723", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/636723.jpg", "longitude": 19.038105, "latitude": 47.520041, "width": 500, "height": 318, "upload_date": "31 January 2007", "owner_id": 137538, "owner_name": "BALÃS ISTVÃN", "owner_url": "http://www.panoramio.com/user/137538"} +, +{"photo_id": 153144, "photo_title": "cierny_vah01", "photo_url": "http://www.panoramio.com/photo/153144", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/153144.jpg", "longitude": 19.907227, "latitude": 49.020084, "width": 500, "height": 332, "upload_date": "15 December 2006", "owner_id": 28092, "owner_name": "Design d15", "owner_url": "http://www.panoramio.com/user/28092"} +, +{"photo_id": 7485246, "photo_title": "Túl mindenen", "photo_url": "http://www.panoramio.com/photo/7485246", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7485246.jpg", "longitude": 17.624259, "latitude": 47.662092, "width": 500, "height": 334, "upload_date": "31 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4884030, "photo_title": "A Cloud is Born", "photo_url": "http://www.panoramio.com/photo/4884030", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4884030.jpg", "longitude": -119.631693, "latitude": 37.724208, "width": 333, "height": 500, "upload_date": "24 September 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 6126146, "photo_title": "North Weald Park", "photo_url": "http://www.panoramio.com/photo/6126146", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126146.jpg", "longitude": 0.264530, "latitude": 51.624631, "width": 500, "height": 333, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 438342, "photo_title": "Sunrise in Sierra Nevada", "photo_url": "http://www.panoramio.com/photo/438342", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/438342.jpg", "longitude": -119.225607, "latitude": 37.945213, "width": 500, "height": 318, "upload_date": "15 January 2007", "owner_id": 93560, "owner_name": "Alex Petrov", "owner_url": "http://www.panoramio.com/user/93560"} +, +{"photo_id": 91978, "photo_title": "Dubrovnik (Croatia)", "photo_url": "http://www.panoramio.com/photo/91978", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/91978.jpg", "longitude": 18.108457, "latitude": 42.642909, "width": 500, "height": 375, "upload_date": "04 December 2006", "owner_id": 11403, "owner_name": "Arnáiz", "owner_url": "http://www.panoramio.com/user/11403"} +, +{"photo_id": 10816587, "photo_title": "Cementiri de Carcassonne", "photo_url": "http://www.panoramio.com/photo/10816587", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10816587.jpg", "longitude": 2.365751, "latitude": 43.205551, "width": 500, "height": 333, "upload_date": "01 June 2008", "owner_id": 599233, "owner_name": "SílviaPrats", "owner_url": "http://www.panoramio.com/user/599233"} +, +{"photo_id": 292943, "photo_title": "Aekingerzand", "photo_url": "http://www.panoramio.com/photo/292943", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/292943.jpg", "longitude": 6.296024, "latitude": 52.935293, "width": 500, "height": 333, "upload_date": "03 January 2007", "owner_id": 62613, "owner_name": "erik van den Ham", "owner_url": "http://www.panoramio.com/user/62613"} +, +{"photo_id": 4696655, "photo_title": "Old boat", "photo_url": "http://www.panoramio.com/photo/4696655", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4696655.jpg", "longitude": 27.399902, "latitude": 42.414079, "width": 500, "height": 357, "upload_date": "16 September 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 348752, "photo_title": "_Cariniana legalis_ (Lecythidaceae), Santa Rita do Passa Quatro, SP,Brasil", "photo_url": "http://www.panoramio.com/photo/348752", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/348752.jpg", "longitude": -47.618523, "latitude": -21.691885, "width": 500, "height": 375, "upload_date": "08 January 2007", "owner_id": 56214, "owner_name": "Vinícius Antonio de Oliveira Dittrich", "owner_url": "http://www.panoramio.com/user/56214"} +, +{"photo_id": 3724631, "photo_title": "Abbazia di Chiaravalle in un'alba nebbiosa", "photo_url": "http://www.panoramio.com/photo/3724631", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3724631.jpg", "longitude": 9.201404, "latitude": 45.424284, "width": 500, "height": 375, "upload_date": "04 August 2007", "owner_id": 732643, "owner_name": "La Mugna", "owner_url": "http://www.panoramio.com/user/732643"} +, +{"photo_id": 405853, "photo_title": "oyasirazu", "photo_url": "http://www.panoramio.com/photo/405853", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405853.jpg", "longitude": 137.747955, "latitude": 37.009133, "width": 500, "height": 384, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1192286, "photo_title": "Ojos del mar - 1", "photo_url": "http://www.panoramio.com/photo/1192286", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1192286.jpg", "longitude": -67.369022, "latitude": -24.630634, "width": 500, "height": 337, "upload_date": "06 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 589411, "photo_title": "Sunset, London, UK.", "photo_url": "http://www.panoramio.com/photo/589411", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/589411.jpg", "longitude": -0.123596, "latitude": 51.500942, "width": 500, "height": 346, "upload_date": "27 January 2007", "owner_id": 44319, "owner_name": "André Bonacin", "owner_url": "http://www.panoramio.com/user/44319"} +, +{"photo_id": 7586406, "photo_title": "Sol naciente en Villarrica", "photo_url": "http://www.panoramio.com/photo/7586406", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7586406.jpg", "longitude": -72.219400, "latitude": -39.289273, "width": 500, "height": 375, "upload_date": "04 February 2008", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 621, "photo_title": "Cape Drastis / Corfu", "photo_url": "http://www.panoramio.com/photo/621", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/621.jpg", "longitude": 19.701061, "latitude": 39.795744, "width": 500, "height": 375, "upload_date": "27 September 2005", "owner_id": 30, "owner_name": "eSHa", "owner_url": "http://www.panoramio.com/user/30"} +, +{"photo_id": 2379636, "photo_title": "Detail from the valley below Holmbukttind", "photo_url": "http://www.panoramio.com/photo/2379636", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2379636.jpg", "longitude": 19.781570, "latitude": 69.476339, "width": 500, "height": 375, "upload_date": "24 May 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 5725557, "photo_title": "Kardzhali lake - Panorama", "photo_url": "http://www.panoramio.com/photo/5725557", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5725557.jpg", "longitude": 25.242250, "latitude": 41.668667, "width": 500, "height": 187, "upload_date": "05 November 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 22393, "photo_title": "View from Bosphorus Bridge", "photo_url": "http://www.panoramio.com/photo/22393", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/22393.jpg", "longitude": 28.999443, "latitude": 41.027053, "width": 500, "height": 355, "upload_date": "04 June 2006", "owner_id": 3504, "owner_name": "zeytinbass", "owner_url": "http://www.panoramio.com/user/3504"} +, +{"photo_id": 5611129, "photo_title": "Torrent de Pareis - Sa Calobra (Mallorca)", "photo_url": "http://www.panoramio.com/photo/5611129", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5611129.jpg", "longitude": 2.807093, "latitude": 39.851709, "width": 500, "height": 373, "upload_date": "29 October 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 3457918, "photo_title": "Walk of Venus", "photo_url": "http://www.panoramio.com/photo/3457918", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3457918.jpg", "longitude": 14.721851, "latitude": 44.838891, "width": 500, "height": 367, "upload_date": "22 July 2007", "owner_id": 346103, "owner_name": "lacitot", "owner_url": "http://www.panoramio.com/user/346103"} +, +{"photo_id": 21135, "photo_title": "icebergs in the Channel", "photo_url": "http://www.panoramio.com/photo/21135", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/21135.jpg", "longitude": -63.017578, "latitude": -64.774125, "width": 500, "height": 338, "upload_date": "24 May 2006", "owner_id": 3316, "owner_name": "kristine hannon (www.traveltheglobe.be)", "owner_url": "http://www.panoramio.com/user/3316"} +, +{"photo_id": 1288597, "photo_title": "Gift", "photo_url": "http://www.panoramio.com/photo/1288597", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1288597.jpg", "longitude": 72.920036, "latitude": 4.038077, "width": 337, "height": 500, "upload_date": "12 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 708502, "photo_title": "A single skier from Gogsøyra tw Litjskjorta mountain", "photo_url": "http://www.panoramio.com/photo/708502", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/708502.jpg", "longitude": 8.160782, "latitude": 62.645604, "width": 424, "height": 500, "upload_date": "05 February 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 4386456, "photo_title": "good bye", "photo_url": "http://www.panoramio.com/photo/4386456", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4386456.jpg", "longitude": -1.254845, "latitude": 44.463191, "width": 500, "height": 405, "upload_date": "04 September 2007", "owner_id": 521836, "owner_name": "KLEFER", "owner_url": "http://www.panoramio.com/user/521836"} +, +{"photo_id": 902303, "photo_title": "Kék", "photo_url": "http://www.panoramio.com/photo/902303", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/902303.jpg", "longitude": 17.941017, "latitude": 47.650703, "width": 334, "height": 500, "upload_date": "19 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3660960, "photo_title": "Angkor - Ta Prohm IV", "photo_url": "http://www.panoramio.com/photo/3660960", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3660960.jpg", "longitude": 103.890334, "latitude": 13.435028, "width": 338, "height": 500, "upload_date": "01 August 2007", "owner_id": 73104, "owner_name": "zerega", "owner_url": "http://www.panoramio.com/user/73104"} +, +{"photo_id": 902570, "photo_title": "Tavitündér", "photo_url": "http://www.panoramio.com/photo/902570", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/902570.jpg", "longitude": 17.468948, "latitude": 47.871914, "width": 500, "height": 345, "upload_date": "19 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 2521005, "photo_title": "Megvilágosodás elött", "photo_url": "http://www.panoramio.com/photo/2521005", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2521005.jpg", "longitude": 17.515984, "latitude": 47.743825, "width": 500, "height": 286, "upload_date": "02 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 586159, "photo_title": "Central Park", "photo_url": "http://www.panoramio.com/photo/586159", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/586159.jpg", "longitude": -73.971816, "latitude": 40.775789, "width": 500, "height": 375, "upload_date": "27 January 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 23475, "photo_title": "Good Morning", "photo_url": "http://www.panoramio.com/photo/23475", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/23475.jpg", "longitude": -28.210895, "latitude": 38.680351, "width": 500, "height": 375, "upload_date": "11 June 2006", "owner_id": 3760, "owner_name": "Frank Pustlauck", "owner_url": "http://www.panoramio.com/user/3760"} +, +{"photo_id": 1006005, "photo_title": "04-09-07_\"La Nube Sangrante\"_017_PIXELECTA", "photo_url": "http://www.panoramio.com/photo/1006005", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1006005.jpg", "longitude": -0.896330, "latitude": 41.738016, "width": 500, "height": 375, "upload_date": "24 February 2007", "owner_id": 163655, "owner_name": "[[[ PIXELECTA ]]]", "owner_url": "http://www.panoramio.com/user/163655"} +, +{"photo_id": 3473597, "photo_title": "Sails in the sunset", "photo_url": "http://www.panoramio.com/photo/3473597", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3473597.jpg", "longitude": -87.173424, "latitude": 45.158317, "width": 500, "height": 375, "upload_date": "22 July 2007", "owner_id": 555551, "owner_name": "Marilyn Whiteley", "owner_url": "http://www.panoramio.com/user/555551"} +, +{"photo_id": 3809992, "photo_title": "DÅ‚ugie Pobrzeże latem/ Las casas narcisistas que se pasan el día mirándose en el espejo del agua - gracias Arturo García!", "photo_url": "http://www.panoramio.com/photo/3809992", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3809992.jpg", "longitude": 18.658776, "latitude": 54.350679, "width": 500, "height": 375, "upload_date": "08 August 2007", "owner_id": 277750, "owner_name": "Karolina P.", "owner_url": "http://www.panoramio.com/user/277750"} +, +{"photo_id": 2280401, "photo_title": "Hetyke-egyke", "photo_url": "http://www.panoramio.com/photo/2280401", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2280401.jpg", "longitude": 17.829094, "latitude": 47.206508, "width": 500, "height": 308, "upload_date": "18 May 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 290772, "photo_title": "Tormenta Bahía de Pollensa", "photo_url": "http://www.panoramio.com/photo/290772", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/290772.jpg", "longitude": 3.116437, "latitude": 39.928440, "width": 500, "height": 335, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 57822, "photo_title": "Maria Alm - Pfarrkirche", "photo_url": "http://www.panoramio.com/photo/57822", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/57822.jpg", "longitude": 12.903442, "latitude": 47.407877, "width": 346, "height": 500, "upload_date": "05 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 516322, "photo_title": "A völgy", "photo_url": "http://www.panoramio.com/photo/516322", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/516322.jpg", "longitude": 17.774162, "latitude": 47.292504, "width": 338, "height": 500, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 12271085, "photo_title": "Ein Bild für meine Freunde", "photo_url": "http://www.panoramio.com/photo/12271085", "photo_file_url": "http://static2.bareka.com/photos/medium/12271085.jpg", "longitude": 9.284134, "latitude": 51.510933, "width": 500, "height": 333, "upload_date": "19 July 2008", "owner_id": 497213, "owner_name": "UlrichSchnuerer", "owner_url": "http://www.panoramio.com/user/497213"} +, +{"photo_id": 5050864, "photo_title": "Ãlmok útján", "photo_url": "http://www.panoramio.com/photo/5050864", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5050864.jpg", "longitude": 12.333773, "latitude": 45.436466, "width": 500, "height": 354, "upload_date": "02 October 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 617461, "photo_title": "Miravet", "photo_url": "http://www.panoramio.com/photo/617461", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/617461.jpg", "longitude": 0.593348, "latitude": 41.035568, "width": 500, "height": 334, "upload_date": "29 January 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 2689526, "photo_title": "Égszakadás", "photo_url": "http://www.panoramio.com/photo/2689526", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2689526.jpg", "longitude": 17.503624, "latitude": 47.749481, "width": 500, "height": 325, "upload_date": "11 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 38135, "photo_title": "Amanecer en el sur", "photo_url": "http://www.panoramio.com/photo/38135", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/38135.jpg", "longitude": -64.983333, "latitude": -31.900000, "width": 500, "height": 375, "upload_date": "11 August 2006", "owner_id": 4483, "owner_name": "Miguel Coranti", "owner_url": "http://www.panoramio.com/user/4483"} +, +{"photo_id": 1087737, "photo_title": "Szeles nyárelÅ‘", "photo_url": "http://www.panoramio.com/photo/1087737", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1087737.jpg", "longitude": 17.605934, "latitude": 47.603154, "width": 500, "height": 333, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 8411394, "photo_title": "Dead Vlei", "photo_url": "http://www.panoramio.com/photo/8411394", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8411394.jpg", "longitude": 15.295715, "latitude": -24.764914, "width": 500, "height": 341, "upload_date": "09 March 2008", "owner_id": 1204358, "owner_name": "aldenc", "owner_url": "http://www.panoramio.com/user/1204358"} +, +{"photo_id": 8491464, "photo_title": "Horsetail Falls on El Capitan", "photo_url": "http://www.panoramio.com/photo/8491464", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8491464.jpg", "longitude": -119.623947, "latitude": 37.723512, "width": 357, "height": 500, "upload_date": "12 March 2008", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 58134, "photo_title": "Chateaux Lake Louise from the head of the lake", "photo_url": "http://www.panoramio.com/photo/58134", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58134.jpg", "longitude": -116.239901, "latitude": 51.407291, "width": 500, "height": 375, "upload_date": "06 October 2006", "owner_id": 8118, "owner_name": "Michael Gerstmann", "owner_url": "http://www.panoramio.com/user/8118"} +, +{"photo_id": 11237087, "photo_title": " Ein Strand zum träumen", "photo_url": "http://www.panoramio.com/photo/11237087", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11237087.jpg", "longitude": 15.914984, "latitude": 38.683366, "width": 500, "height": 294, "upload_date": "15 June 2008", "owner_id": 1400529, "owner_name": "marita1004", "owner_url": "http://www.panoramio.com/user/1400529"} +, +{"photo_id": 8384850, "photo_title": "Winter has gone", "photo_url": "http://www.panoramio.com/photo/8384850", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8384850.jpg", "longitude": 12.428112, "latitude": 49.084351, "width": 500, "height": 333, "upload_date": "08 March 2008", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 3947779, "photo_title": "Mont-Saint-Michel floating in water", "photo_url": "http://www.panoramio.com/photo/3947779", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3947779.jpg", "longitude": -1.508625, "latitude": 48.634561, "width": 500, "height": 335, "upload_date": "15 August 2007", "owner_id": 57893, "owner_name": "ThoiryK", "owner_url": "http://www.panoramio.com/user/57893"} +, +{"photo_id": 1069321, "photo_title": "The old Temple N2", "photo_url": "http://www.panoramio.com/photo/1069321", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1069321.jpg", "longitude": 37.426300, "latitude": 56.370622, "width": 500, "height": 333, "upload_date": "27 February 2007", "owner_id": 212477, "owner_name": "Cherepanov Timofey", "owner_url": "http://www.panoramio.com/user/212477"} +, +{"photo_id": 5756689, "photo_title": "Tokyo Metropolitan Government", "photo_url": "http://www.panoramio.com/photo/5756689", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5756689.jpg", "longitude": 139.690722, "latitude": 35.689906, "width": 500, "height": 339, "upload_date": "06 November 2007", "owner_id": 558055, "owner_name": "www.tokyoform.com", "owner_url": "http://www.panoramio.com/user/558055"} +, +{"photo_id": 1599763, "photo_title": "Atomium", "photo_url": "http://www.panoramio.com/photo/1599763", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1599763.jpg", "longitude": 4.341531, "latitude": 50.894805, "width": 500, "height": 375, "upload_date": "02 April 2007", "owner_id": 18137, "owner_name": "digitaler lumpensammler", "owner_url": "http://www.panoramio.com/user/18137"} +, +{"photo_id": 516375, "photo_title": "A zöld folyó", "photo_url": "http://www.panoramio.com/photo/516375", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/516375.jpg", "longitude": 17.724895, "latitude": 46.297137, "width": 369, "height": 500, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1538329, "photo_title": "View east from Empire State Building by night", "photo_url": "http://www.panoramio.com/photo/1538329", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1538329.jpg", "longitude": -73.986332, "latitude": 40.748346, "width": 500, "height": 332, "upload_date": "28 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 1838875, "photo_title": "Modern art in Mainz", "photo_url": "http://www.panoramio.com/photo/1838875", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1838875.jpg", "longitude": 8.276659, "latitude": 50.001071, "width": 500, "height": 393, "upload_date": "19 April 2007", "owner_id": 12954, "owner_name": "ZiÄ™bol", "owner_url": "http://www.panoramio.com/user/12954"} +, +{"photo_id": 4740891, "photo_title": "The golden path - Az aranyozott ösvény", "photo_url": "http://www.panoramio.com/photo/4740891", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4740891.jpg", "longitude": 17.599239, "latitude": 47.639948, "width": 500, "height": 334, "upload_date": "18 September 2007", "owner_id": 217370, "owner_name": "Borbély Márk", "owner_url": "http://www.panoramio.com/user/217370"} +, +{"photo_id": 441376, "photo_title": "Bolungarvik", "photo_url": "http://www.panoramio.com/photo/441376", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/441376.jpg", "longitude": -23.197975, "latitude": 66.151698, "width": 500, "height": 333, "upload_date": "15 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 3354401, "photo_title": "Alkonyi színjáték", "photo_url": "http://www.panoramio.com/photo/3354401", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3354401.jpg", "longitude": 17.504225, "latitude": 47.745730, "width": 500, "height": 334, "upload_date": "16 July 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 809506, "photo_title": "Szivárványhorizont", "photo_url": "http://www.panoramio.com/photo/809506", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/809506.jpg", "longitude": 15.969830, "latitude": 43.626632, "width": 500, "height": 334, "upload_date": "13 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 36387, "photo_title": "Adobe Headquarters - Looking Up", "photo_url": "http://www.panoramio.com/photo/36387", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/36387.jpg", "longitude": -121.893804, "latitude": 37.330959, "width": 351, "height": 500, "upload_date": "02 August 2006", "owner_id": 5684, "owner_name": "Brent Townshend", "owner_url": "http://www.panoramio.com/user/5684"} +, +{"photo_id": 722982, "photo_title": "Antelope-Light", "photo_url": "http://www.panoramio.com/photo/722982", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/722982.jpg", "longitude": -111.371326, "latitude": 36.857236, "width": 333, "height": 500, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 138030, "photo_title": "Kinderdijk", "photo_url": "http://www.panoramio.com/photo/138030", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/138030.jpg", "longitude": 4.645500, "latitude": 51.879458, "width": 500, "height": 335, "upload_date": "13 December 2006", "owner_id": 18131, "owner_name": "ron zoeteweij", "owner_url": "http://www.panoramio.com/user/18131"} +, +{"photo_id": 9725235, "photo_title": "railway / MaÅ‚opolska / województwo maÅ‚opolskie", "photo_url": "http://www.panoramio.com/photo/9725235", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9725235.jpg", "longitude": 20.363159, "latitude": 49.748443, "width": 321, "height": 500, "upload_date": "28 April 2008", "owner_id": 454219, "owner_name": "Rafal Ociepka", "owner_url": "http://www.panoramio.com/user/454219"} +, +{"photo_id": 945984, "photo_title": "El canal", "photo_url": "http://www.panoramio.com/photo/945984", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/945984.jpg", "longitude": 0.484858, "latitude": 40.901901, "width": 378, "height": 500, "upload_date": "21 February 2007", "owner_id": 3022, "owner_name": "Arcadi", "owner_url": "http://www.panoramio.com/user/3022"} +, +{"photo_id": 677953, "photo_title": "Shuto Expressway over the Sumida River", "photo_url": "http://www.panoramio.com/photo/677953", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/677953.jpg", "longitude": 139.788644, "latitude": 35.690411, "width": 500, "height": 364, "upload_date": "03 February 2007", "owner_id": 78856, "owner_name": "chrisjongkind • archive", "owner_url": "http://www.panoramio.com/user/78856"} +, +{"photo_id": 2723655, "photo_title": "Orciano Pisano", "photo_url": "http://www.panoramio.com/photo/2723655", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2723655.jpg", "longitude": 10.505505, "latitude": 43.491911, "width": 366, "height": 500, "upload_date": "13 June 2007", "owner_id": 65478, "owner_name": "Gabriele Marabotti", "owner_url": "http://www.panoramio.com/user/65478"} +, +{"photo_id": 444745, "photo_title": "Pres de Nefta", "photo_url": "http://www.panoramio.com/photo/444745", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/444745.jpg", "longitude": 7.904320, "latitude": 33.766590, "width": 500, "height": 333, "upload_date": "15 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 1388623, "photo_title": "El Aviario (Parque Ecológico, Puebla, México)", "photo_url": "http://www.panoramio.com/photo/1388623", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1388623.jpg", "longitude": -98.187540, "latitude": 19.025552, "width": 500, "height": 488, "upload_date": "18 March 2007", "owner_id": 274633, "owner_name": "D4v17 ]7. G.", "owner_url": "http://www.panoramio.com/user/274633"} +, +{"photo_id": 792658, "photo_title": "Reichtag in the dome, Berlin HDR", "photo_url": "http://www.panoramio.com/photo/792658", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/792658.jpg", "longitude": 13.376133, "latitude": 52.518610, "width": 376, "height": 500, "upload_date": "12 February 2007", "owner_id": 161254, "owner_name": "fotoartistry", "owner_url": "http://www.panoramio.com/user/161254"} +, +{"photo_id": 324694, "photo_title": "Thachted houses", "photo_url": "http://www.panoramio.com/photo/324694", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/324694.jpg", "longitude": 137.235117, "latitude": 36.132095, "width": 500, "height": 265, "upload_date": "06 January 2007", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 2353496, "photo_title": "раÑÑвет над вулканом ЖупановÑкий", "photo_url": "http://www.panoramio.com/photo/2353496", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2353496.jpg", "longitude": 158.591080, "latitude": 53.497850, "width": 500, "height": 337, "upload_date": "23 May 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 7251801, "photo_title": "Fellegek közt", "photo_url": "http://www.panoramio.com/photo/7251801", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7251801.jpg", "longitude": 18.314981, "latitude": 47.638820, "width": 500, "height": 329, "upload_date": "20 January 2008", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 35422, "photo_title": "caracas", "photo_url": "http://www.panoramio.com/photo/35422", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/35422.jpg", "longitude": -66.904507, "latitude": 10.498193, "width": 500, "height": 375, "upload_date": "29 July 2006", "owner_id": 3360, "owner_name": "ozzy", "owner_url": "http://www.panoramio.com/user/3360"} +, +{"photo_id": 405861, "photo_title": "myoukou", "photo_url": "http://www.panoramio.com/photo/405861", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/405861.jpg", "longitude": 138.295898, "latitude": 37.099003, "width": 500, "height": 383, "upload_date": "13 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 2719848, "photo_title": "Idaho relic", "photo_url": "http://www.panoramio.com/photo/2719848", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2719848.jpg", "longitude": -111.398749, "latitude": 42.286707, "width": 500, "height": 375, "upload_date": "13 June 2007", "owner_id": 555551, "owner_name": "Marilyn Whiteley", "owner_url": "http://www.panoramio.com/user/555551"} +, +{"photo_id": 599401, "photo_title": "Hozenji", "photo_url": "http://www.panoramio.com/photo/599401", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/599401.jpg", "longitude": 135.502450, "latitude": 34.668002, "width": 500, "height": 500, "upload_date": "28 January 2007", "owner_id": 128403, "owner_name": "mechanics", "owner_url": "http://www.panoramio.com/user/128403"} +, +{"photo_id": 53101, "photo_title": "Night Auadkhara", "photo_url": "http://www.panoramio.com/photo/53101", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/53101.jpg", "longitude": 40.631331, "latitude": 43.525806, "width": 500, "height": 323, "upload_date": "27 September 2006", "owner_id": 7707, "owner_name": "Yorix", "owner_url": "http://www.panoramio.com/user/7707"} +, +{"photo_id": 112752, "photo_title": "V-35-003b", "photo_url": "http://www.panoramio.com/photo/112752", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/112752.jpg", "longitude": 12.339267, "latitude": 45.433696, "width": 500, "height": 338, "upload_date": "11 December 2006", "owner_id": 17599, "owner_name": "Dmitry Andreev", "owner_url": "http://www.panoramio.com/user/17599"} +, +{"photo_id": 1946749, "photo_title": "Mt Hood and a John Deer Tractor over the Wooden Shoe Tulip Fields Monitor Oregon", "photo_url": "http://www.panoramio.com/photo/1946749", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1946749.jpg", "longitude": -122.740974, "latitude": 45.119326, "width": 500, "height": 351, "upload_date": "27 April 2007", "owner_id": 128746, "owner_name": "© Michael Hatten", "owner_url": "http://www.panoramio.com/user/128746"} +, +{"photo_id": 723074, "photo_title": "September Twilight in Thira", "photo_url": "http://www.panoramio.com/photo/723074", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723074.jpg", "longitude": 25.430603, "latitude": 36.416862, "width": 500, "height": 223, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1658251, "photo_title": "Behold the moon", "photo_url": "http://www.panoramio.com/photo/1658251", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1658251.jpg", "longitude": 15.589085, "latitude": 78.170125, "width": 333, "height": 500, "upload_date": "06 April 2007", "owner_id": 3574, "owner_name": "blackone", "owner_url": "http://www.panoramio.com/user/3574"} +, +{"photo_id": 2225571, "photo_title": "Landscape (Via Di Porta Castello Street) ~ Tarquinia, Italy", "photo_url": "http://www.panoramio.com/photo/2225571", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2225571.jpg", "longitude": 11.751836, "latitude": 42.255808, "width": 500, "height": 335, "upload_date": "15 May 2007", "owner_id": 395380, "owner_name": "Rafael (Retrocool)", "owner_url": "http://www.panoramio.com/user/395380"} +, +{"photo_id": 348071, "photo_title": "Perfect ice for skating, Svartlögafjärden", "photo_url": "http://www.panoramio.com/photo/348071", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/348071.jpg", "longitude": 19.021196, "latitude": 59.558766, "width": 500, "height": 375, "upload_date": "08 January 2007", "owner_id": 70471, "owner_name": "David Thyberg", "owner_url": "http://www.panoramio.com/user/70471"} +, +{"photo_id": 1408683, "photo_title": "Dragon", "photo_url": "http://www.panoramio.com/photo/1408683", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1408683.jpg", "longitude": 11.099625, "latitude": 24.203758, "width": 334, "height": 500, "upload_date": "20 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 58293, "photo_title": "Hundeschlittenrennen in Werfenweng", "photo_url": "http://www.panoramio.com/photo/58293", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58293.jpg", "longitude": 13.263245, "latitude": 47.465062, "width": 500, "height": 377, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 1488328, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/1488328", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1488328.jpg", "longitude": 139.290161, "latitude": 37.860218, "width": 500, "height": 383, "upload_date": "25 March 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 5439200, "photo_title": "shinjuku", "photo_url": "http://www.panoramio.com/photo/5439200", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5439200.jpg", "longitude": 139.693281, "latitude": 35.690921, "width": 500, "height": 500, "upload_date": "20 October 2007", "owner_id": 128403, "owner_name": "mechanics", "owner_url": "http://www.panoramio.com/user/128403"} +, +{"photo_id": 86241, "photo_title": "camino", "photo_url": "http://www.panoramio.com/photo/86241", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/86241.jpg", "longitude": -1.145668, "latitude": 38.170464, "width": 333, "height": 500, "upload_date": "25 November 2006", "owner_id": 10969, "owner_name": "Juanra", "owner_url": "http://www.panoramio.com/user/10969"} +, +{"photo_id": 4757733, "photo_title": "MASSIVE WAVE", "photo_url": "http://www.panoramio.com/photo/4757733", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4757733.jpg", "longitude": -1.262569, "latitude": 44.426793, "width": 259, "height": 500, "upload_date": "19 September 2007", "owner_id": 521836, "owner_name": "KLEFER", "owner_url": "http://www.panoramio.com/user/521836"} +, +{"photo_id": 941286, "photo_title": "Mesa Arch (3x1 pano)", "photo_url": "http://www.panoramio.com/photo/941286", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/941286.jpg", "longitude": -109.863667, "latitude": 38.388159, "width": 500, "height": 181, "upload_date": "21 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1284843, "photo_title": "Озеро Хангар в кратере вулкана", "photo_url": "http://www.panoramio.com/photo/1284843", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1284843.jpg", "longitude": 157.393055, "latitude": 54.764255, "width": 500, "height": 197, "upload_date": "12 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 2602988, "photo_title": "The best beach of Manihi", "photo_url": "http://www.panoramio.com/photo/2602988", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2602988.jpg", "longitude": -145.847282, "latitude": -14.348134, "width": 500, "height": 333, "upload_date": "06 June 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 2273013, "photo_title": "Another View of Vedra Island", "photo_url": "http://www.panoramio.com/photo/2273013", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2273013.jpg", "longitude": 1.247164, "latitude": 38.859406, "width": 500, "height": 465, "upload_date": "18 May 2007", "owner_id": 213866, "owner_name": "Nicolas Mertens", "owner_url": "http://www.panoramio.com/user/213866"} +, +{"photo_id": 8857011, "photo_title": "The Subway,Zion NP", "photo_url": "http://www.panoramio.com/photo/8857011", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8857011.jpg", "longitude": -113.055840, "latitude": 37.308741, "width": 500, "height": 375, "upload_date": "26 March 2008", "owner_id": 1465912, "owner_name": "funtor", "owner_url": "http://www.panoramio.com/user/1465912"} +, +{"photo_id": 167606, "photo_title": "Rainy Causeway Bay", "photo_url": "http://www.panoramio.com/photo/167606", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/167606.jpg", "longitude": 114.169595, "latitude": 22.293028, "width": 500, "height": 238, "upload_date": "16 December 2006", "owner_id": 31693, "owner_name": "Huw Thomas", "owner_url": "http://www.panoramio.com/user/31693"} +, +{"photo_id": 11077834, "photo_title": "In sunset", "photo_url": "http://www.panoramio.com/photo/11077834", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11077834.jpg", "longitude": 174.865694, "latitude": -41.330162, "width": 500, "height": 357, "upload_date": "10 June 2008", "owner_id": 1248894, "owner_name": "Eva Kaprinay", "owner_url": "http://www.panoramio.com/user/1248894"} +, +{"photo_id": 10919439, "photo_title": "Majestic Møøse", "photo_url": "http://www.panoramio.com/photo/10919439", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10919439.jpg", "longitude": -110.549712, "latitude": 43.866322, "width": 500, "height": 400, "upload_date": "04 June 2008", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 4892928, "photo_title": "tsukudajima", "photo_url": "http://www.panoramio.com/photo/4892928", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4892928.jpg", "longitude": 139.788172, "latitude": 35.672141, "width": 430, "height": 500, "upload_date": "25 September 2007", "owner_id": 128403, "owner_name": "mechanics", "owner_url": "http://www.panoramio.com/user/128403"} +, +{"photo_id": 5798660, "photo_title": "Guiding Light", "photo_url": "http://www.panoramio.com/photo/5798660", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5798660.jpg", "longitude": -111.374674, "latitude": 36.861974, "width": 333, "height": 500, "upload_date": "08 November 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 94219, "photo_title": "Bridge of Manganji", "photo_url": "http://www.panoramio.com/photo/94219", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/94219.jpg", "longitude": 137.821137, "latitude": 36.329284, "width": 500, "height": 375, "upload_date": "09 December 2006", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 3772695, "photo_title": "Fotomontaggio di Arquata & Andromeda", "photo_url": "http://www.panoramio.com/photo/3772695", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3772695.jpg", "longitude": 13.304100, "latitude": 42.773731, "width": 500, "height": 375, "upload_date": "07 August 2007", "owner_id": 646873, "owner_name": "Fabio Roman", "owner_url": "http://www.panoramio.com/user/646873"} +, +{"photo_id": 1314842, "photo_title": "Река Сим Ñ Ð¼Ð¾Ñта (1729 км)", "photo_url": "http://www.panoramio.com/photo/1314842", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1314842.jpg", "longitude": 57.309623, "latitude": 55.013544, "width": 500, "height": 335, "upload_date": "14 March 2007", "owner_id": 268724, "owner_name": "Korotnev AV", "owner_url": "http://www.panoramio.com/user/268724"} +, +{"photo_id": 5333278, "photo_title": "hong kong, early evening", "photo_url": "http://www.panoramio.com/photo/5333278", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5333278.jpg", "longitude": 114.151651, "latitude": 22.280112, "width": 375, "height": 500, "upload_date": "15 October 2007", "owner_id": 90373, "owner_name": "michael habla", "owner_url": "http://www.panoramio.com/user/90373"} +, +{"photo_id": 2574624, "photo_title": "Mount Everest", "photo_url": "http://www.panoramio.com/photo/2574624", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2574624.jpg", "longitude": 86.933270, "latitude": 27.979546, "width": 500, "height": 375, "upload_date": "04 June 2007", "owner_id": 534045, "owner_name": "Lucjon", "owner_url": "http://www.panoramio.com/user/534045"} +, +{"photo_id": 160808, "photo_title": "Luquillo Beach", "photo_url": "http://www.panoramio.com/photo/160808", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/160808.jpg", "longitude": -65.677128, "latitude": 18.364871, "width": 500, "height": 375, "upload_date": "16 December 2006", "owner_id": 28766, "owner_name": "Tim Jansa", "owner_url": "http://www.panoramio.com/user/28766"} +, +{"photo_id": 2883625, "photo_title": "Sokorói impresszió", "photo_url": "http://www.panoramio.com/photo/2883625", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2883625.jpg", "longitude": 17.678204, "latitude": 47.533661, "width": 500, "height": 332, "upload_date": "22 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 287785, "photo_title": "Cascada Fuente del Algar © (Foto_Seb)", "photo_url": "http://www.panoramio.com/photo/287785", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/287785.jpg", "longitude": -0.095959, "latitude": 38.659359, "width": 500, "height": 332, "upload_date": "03 January 2007", "owner_id": 55833, "owner_name": "Sebastien Pigneur Jans (Outdoor Photographer) seolta@terra.es", "owner_url": "http://www.panoramio.com/user/55833"} +, +{"photo_id": 354350, "photo_title": "Bondhus icefall up close", "photo_url": "http://www.panoramio.com/photo/354350", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/354350.jpg", "longitude": 6.296539, "latitude": 60.071436, "width": 500, "height": 332, "upload_date": "09 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 3625784, "photo_title": "P.N.P.J.(Croacia)", "photo_url": "http://www.panoramio.com/photo/3625784", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3625784.jpg", "longitude": 15.612602, "latitude": 44.883911, "width": 500, "height": 375, "upload_date": "30 July 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 4866107, "photo_title": "Milkdrop sunset", "photo_url": "http://www.panoramio.com/photo/4866107", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4866107.jpg", "longitude": 16.693897, "latitude": 43.183338, "width": 334, "height": 500, "upload_date": "24 September 2007", "owner_id": 989, "owner_name": "Mrgud", "owner_url": "http://www.panoramio.com/user/989"} +, +{"photo_id": 5217595, "photo_title": "kolory...", "photo_url": "http://www.panoramio.com/photo/5217595", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5217595.jpg", "longitude": 17.990541, "latitude": 54.253292, "width": 375, "height": 500, "upload_date": "10 October 2007", "owner_id": 277750, "owner_name": "Karolina P.", "owner_url": "http://www.panoramio.com/user/277750"} +, +{"photo_id": 1235515, "photo_title": "Gangga sunset", "photo_url": "http://www.panoramio.com/photo/1235515", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1235515.jpg", "longitude": 115.063634, "latitude": -8.586962, "width": 332, "height": 500, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 88143, "photo_title": "Anse Cocos - La Digue - Seychelles", "photo_url": "http://www.panoramio.com/photo/88143", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/88143.jpg", "longitude": 55.850029, "latitude": -4.365924, "width": 500, "height": 375, "upload_date": "28 November 2006", "owner_id": 11098, "owner_name": "Michele Masnata", "owner_url": "http://www.panoramio.com/user/11098"} +, +{"photo_id": 993105, "photo_title": "Dinos", "photo_url": "http://www.panoramio.com/photo/993105", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/993105.jpg", "longitude": 47.267990, "latitude": 34.392321, "width": 432, "height": 500, "upload_date": "24 February 2007", "owner_id": 83972, "owner_name": "Maxim Popov (http://www.popovm.ru)", "owner_url": "http://www.panoramio.com/user/83972"} +, +{"photo_id": 3382098, "photo_title": "Golden sunset", "photo_url": "http://www.panoramio.com/photo/3382098", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3382098.jpg", "longitude": -9.231960, "latitude": 38.652899, "width": 500, "height": 375, "upload_date": "18 July 2007", "owner_id": 465080, "owner_name": "Vasco Pires", "owner_url": "http://www.panoramio.com/user/465080"} +, +{"photo_id": 4689747, "photo_title": "La disipación de un ensueño", "photo_url": "http://www.panoramio.com/photo/4689747", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4689747.jpg", "longitude": -73.231199, "latitude": -39.817288, "width": 500, "height": 375, "upload_date": "16 September 2007", "owner_id": 327310, "owner_name": "Erwin Woenckhaus", "owner_url": "http://www.panoramio.com/user/327310"} +, +{"photo_id": 2520917, "photo_title": "Két vihar közt alkonyatkor", "photo_url": "http://www.panoramio.com/photo/2520917", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2520917.jpg", "longitude": 17.514782, "latitude": 47.747057, "width": 500, "height": 334, "upload_date": "02 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 419927, "photo_title": "echigoheiya", "photo_url": "http://www.panoramio.com/photo/419927", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/419927.jpg", "longitude": 138.885427, "latitude": 37.568562, "width": 500, "height": 334, "upload_date": "14 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1977433, "photo_title": "Victoria Falls, devils cauldron natural hot tub at lip of falls", "photo_url": "http://www.panoramio.com/photo/1977433", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1977433.jpg", "longitude": 25.853426, "latitude": -17.923924, "width": 500, "height": 375, "upload_date": "29 April 2007", "owner_id": 165455, "owner_name": "snorth", "owner_url": "http://www.panoramio.com/user/165455"} +, +{"photo_id": 3417691, "photo_title": "Völgy-Zugoly", "photo_url": "http://www.panoramio.com/photo/3417691", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3417691.jpg", "longitude": 17.826734, "latitude": 47.359293, "width": 500, "height": 346, "upload_date": "20 July 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 4166241, "photo_title": "Egy másik világ", "photo_url": "http://www.panoramio.com/photo/4166241", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4166241.jpg", "longitude": 18.056545, "latitude": 47.276667, "width": 333, "height": 500, "upload_date": "25 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3976033, "photo_title": "Sunrise Blüemlisalp Switzerland", "photo_url": "http://www.panoramio.com/photo/3976033", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3976033.jpg", "longitude": 7.779844, "latitude": 46.528974, "width": 500, "height": 333, "upload_date": "16 August 2007", "owner_id": 47930, "owner_name": "werni", "owner_url": "http://www.panoramio.com/user/47930"} +, +{"photo_id": 1449570, "photo_title": "Akabat", "photo_url": "http://www.panoramio.com/photo/1449570", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1449570.jpg", "longitude": 28.286717, "latitude": 27.484675, "width": 500, "height": 304, "upload_date": "22 March 2007", "owner_id": 304324, "owner_name": "OxyPhoto.ru - O x y", "owner_url": "http://www.panoramio.com/user/304324"} +, +{"photo_id": 8802, "photo_title": "Statue of Liberty [003393]", "photo_url": "http://www.panoramio.com/photo/8802", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8802.jpg", "longitude": -74.044375, "latitude": 40.688871, "width": 500, "height": 375, "upload_date": "27 January 2006", "owner_id": 1489, "owner_name": "Thorsten", "owner_url": "http://www.panoramio.com/user/1489"} +, +{"photo_id": 6015859, "photo_title": "Amazing place to drink ouzo", "photo_url": "http://www.panoramio.com/photo/6015859", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6015859.jpg", "longitude": 23.057030, "latitude": 36.687990, "width": 500, "height": 333, "upload_date": "19 November 2007", "owner_id": 242446, "owner_name": "Ntinos Lagos", "owner_url": "http://www.panoramio.com/user/242446"} +, +{"photo_id": 653941, "photo_title": "Mt. Moran across Jackson Lake", "photo_url": "http://www.panoramio.com/photo/653941", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/653941.jpg", "longitude": -110.656099, "latitude": 43.897336, "width": 500, "height": 374, "upload_date": "02 February 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 354695, "photo_title": "Dresden_Zwinger_01", "photo_url": "http://www.panoramio.com/photo/354695", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/354695.jpg", "longitude": 13.734369, "latitude": 51.053481, "width": 399, "height": 500, "upload_date": "09 January 2007", "owner_id": 71628, "owner_name": "Ulrich Hässler, Dresden", "owner_url": "http://www.panoramio.com/user/71628"} +, +{"photo_id": 8327051, "photo_title": "Anelito di .... luce", "photo_url": "http://www.panoramio.com/photo/8327051", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8327051.jpg", "longitude": 13.717203, "latitude": 45.699706, "width": 500, "height": 375, "upload_date": "06 March 2008", "owner_id": 1121720, "owner_name": "â–¬ Mauro Antonini â–¬", "owner_url": "http://www.panoramio.com/user/1121720"} +, +{"photo_id": 522126, "photo_title": "Ãme a ludas hogy Márton lemaradt", "photo_url": "http://www.panoramio.com/photo/522126", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/522126.jpg", "longitude": 16.855431, "latitude": 47.653594, "width": 500, "height": 319, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 3948179, "photo_title": " petit matin en Vendée, sur la rive droite du Jaunay, 11 août 2007. #921, 933", "photo_url": "http://www.panoramio.com/photo/3948179", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3948179.jpg", "longitude": -1.901278, "latitude": 46.663487, "width": 500, "height": 343, "upload_date": "15 August 2007", "owner_id": 666755, "owner_name": "Armagnac", "owner_url": "http://www.panoramio.com/user/666755"} +, +{"photo_id": 1781399, "photo_title": "Dawn in Yosemite Valley", "photo_url": "http://www.panoramio.com/photo/1781399", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1781399.jpg", "longitude": -119.590645, "latitude": 37.743775, "width": 333, "height": 500, "upload_date": "15 April 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 905112, "photo_title": "Searea buildings in Odaiba", "photo_url": "http://www.panoramio.com/photo/905112", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/905112.jpg", "longitude": 139.773039, "latitude": 35.635670, "width": 500, "height": 372, "upload_date": "19 February 2007", "owner_id": 78856, "owner_name": "chrisjongkind • archive", "owner_url": "http://www.panoramio.com/user/78856"} +, +{"photo_id": 6935706, "photo_title": "poranek w ogniu - morning on fire", "photo_url": "http://www.panoramio.com/photo/6935706", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6935706.jpg", "longitude": 20.319901, "latitude": 49.730028, "width": 500, "height": 332, "upload_date": "06 January 2008", "owner_id": 454219, "owner_name": "Rafal Ociepka", "owner_url": "http://www.panoramio.com/user/454219"} +, +{"photo_id": 29606, "photo_title": "Romance entre el Agua y la Roca", "photo_url": "http://www.panoramio.com/photo/29606", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/29606.jpg", "longitude": -64.859161, "latitude": -31.991480, "width": 500, "height": 375, "upload_date": "01 July 2006", "owner_id": 4483, "owner_name": "Miguel Coranti", "owner_url": "http://www.panoramio.com/user/4483"} +, +{"photo_id": 58290, "photo_title": "Taurachbahn", "photo_url": "http://www.panoramio.com/photo/58290", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58290.jpg", "longitude": 13.688021, "latitude": 47.130418, "width": 500, "height": 369, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 44982, "photo_title": "Paris200412PJDSC_9304l", "photo_url": "http://www.panoramio.com/photo/44982", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/44982.jpg", "longitude": 2.301636, "latitude": 48.853760, "width": 500, "height": 332, "upload_date": "02 September 2006", "owner_id": 6703, "owner_name": "Peter Jansen", "owner_url": "http://www.panoramio.com/user/6703"} +, +{"photo_id": 532669, "photo_title": "Closeup of wheatfield in november", "photo_url": "http://www.panoramio.com/photo/532669", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532669.jpg", "longitude": 11.276093, "latitude": 59.644239, "width": 375, "height": 500, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 723648, "photo_title": "Elk near Jasper", "photo_url": "http://www.panoramio.com/photo/723648", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/723648.jpg", "longitude": -118.046207, "latitude": 52.923290, "width": 500, "height": 332, "upload_date": "07 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 535234, "photo_title": "Cathedral Cove near Hahei, New Zealand", "photo_url": "http://www.panoramio.com/photo/535234", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/535234.jpg", "longitude": 175.790222, "latitude": -36.828611, "width": 500, "height": 375, "upload_date": "22 January 2007", "owner_id": 101257, "owner_name": "Denis Campbell", "owner_url": "http://www.panoramio.com/user/101257"} +, +{"photo_id": 15299, "photo_title": "Bodrum Sunset", "photo_url": "http://www.panoramio.com/photo/15299", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/15299.jpg", "longitude": 27.425308, "latitude": 37.028595, "width": 500, "height": 375, "upload_date": "19 March 2006", "owner_id": 2351, "owner_name": "Serdar Bilecen", "owner_url": "http://www.panoramio.com/user/2351"} +, +{"photo_id": 1932227, "photo_title": "Mono Lake 3", "photo_url": "http://www.panoramio.com/photo/1932227", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1932227.jpg", "longitude": -119.023819, "latitude": 37.940068, "width": 333, "height": 500, "upload_date": "26 April 2007", "owner_id": 40260, "owner_name": "Don Albonico", "owner_url": "http://www.panoramio.com/user/40260"} +, +{"photo_id": 744906, "photo_title": "Tsukahara Highland", "photo_url": "http://www.panoramio.com/photo/744906", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/744906.jpg", "longitude": 131.403952, "latitude": 33.320201, "width": 500, "height": 375, "upload_date": "08 February 2007", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 490198, "photo_title": "Jal Mahal, Jaipur", "photo_url": "http://www.panoramio.com/photo/490198", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/490198.jpg", "longitude": 75.842797, "latitude": 26.954571, "width": 500, "height": 403, "upload_date": "19 January 2007", "owner_id": 10456, "owner_name": "eulogio", "owner_url": "http://www.panoramio.com/user/10456"} +, +{"photo_id": 451032, "photo_title": "Mono Lake", "photo_url": "http://www.panoramio.com/photo/451032", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/451032.jpg", "longitude": -119.017537, "latitude": 37.941803, "width": 363, "height": 500, "upload_date": "16 January 2007", "owner_id": 93560, "owner_name": "Alex Petrov", "owner_url": "http://www.panoramio.com/user/93560"} +, +{"photo_id": 5808345, "photo_title": "Majesty in the snow", "photo_url": "http://www.panoramio.com/photo/5808345", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5808345.jpg", "longitude": 9.944987, "latitude": 48.684866, "width": 367, "height": 500, "upload_date": "09 November 2007", "owner_id": 424589, "owner_name": "PeSchn", "owner_url": "http://www.panoramio.com/user/424589"} +, +{"photo_id": 2718436, "photo_title": "BKCC view northwest", "photo_url": "http://www.panoramio.com/photo/2718436", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2718436.jpg", "longitude": 139.752048, "latitude": 35.708102, "width": 500, "height": 365, "upload_date": "12 June 2007", "owner_id": 558055, "owner_name": "www.tokyoform.com", "owner_url": "http://www.panoramio.com/user/558055"} +, +{"photo_id": 5446639, "photo_title": "ОÑень", "photo_url": "http://www.panoramio.com/photo/5446639", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5446639.jpg", "longitude": 23.824694, "latitude": 53.680547, "width": 500, "height": 375, "upload_date": "21 October 2007", "owner_id": 937915, "owner_name": "HiV", "owner_url": "http://www.panoramio.com/user/937915"} +, +{"photo_id": 3393267, "photo_title": "Barco hundido (pecio) /Shipwreck /épave ", "photo_url": "http://www.panoramio.com/photo/3393267", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3393267.jpg", "longitude": -81.680587, "latitude": 45.255181, "width": 329, "height": 500, "upload_date": "18 July 2007", "owner_id": 401966, "owner_name": "Syl de Canada", "owner_url": "http://www.panoramio.com/user/401966"} +, +{"photo_id": 4369140, "photo_title": "Beach on HÃ¥ja", "photo_url": "http://www.panoramio.com/photo/4369140", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4369140.jpg", "longitude": 18.096886, "latitude": 69.740825, "width": 500, "height": 375, "upload_date": "03 September 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 3711738, "photo_title": "Safe", "photo_url": "http://www.panoramio.com/photo/3711738", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3711738.jpg", "longitude": 1.787220, "latitude": 41.224610, "width": 500, "height": 375, "upload_date": "04 August 2007", "owner_id": 138691, "owner_name": "Josep Maria Alegre", "owner_url": "http://www.panoramio.com/user/138691"} +, +{"photo_id": 7415554, "photo_title": "Sunrise at Hae-keum-gang, Korea", "photo_url": "http://www.panoramio.com/photo/7415554", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7415554.jpg", "longitude": 128.605957, "latitude": 34.698719, "width": 500, "height": 500, "upload_date": "28 January 2008", "owner_id": 1221287, "owner_name": "TS Jeung", "owner_url": "http://www.panoramio.com/user/1221287"} +, +{"photo_id": 10129080, "photo_title": "Polish Silesia sunset.", "photo_url": "http://www.panoramio.com/photo/10129080", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10129080.jpg", "longitude": 18.819752, "latitude": 49.789798, "width": 500, "height": 335, "upload_date": "11 May 2008", "owner_id": 548131, "owner_name": "murart", "owner_url": "http://www.panoramio.com/user/548131"} +, +{"photo_id": 11827263, "photo_title": ": Casa Rustica", "photo_url": "http://www.panoramio.com/photo/11827263", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11827263.jpg", "longitude": -8.644395, "latitude": 42.795039, "width": 500, "height": 375, "upload_date": "05 July 2008", "owner_id": 546858, "owner_name": "Lazariparcero", "owner_url": "http://www.panoramio.com/user/546858"} +, +{"photo_id": 9185096, "photo_title": "E per cambiare... oggi è nevicato ! 07.04.2008", "photo_url": "http://www.panoramio.com/photo/9185096", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9185096.jpg", "longitude": 11.469633, "latitude": 46.304547, "width": 500, "height": 375, "upload_date": "07 April 2008", "owner_id": 6033, "owner_name": "â–º Marco Vanzo", "owner_url": "http://www.panoramio.com/user/6033"} +, +{"photo_id": 691, "photo_title": "Monasterio de Santa Catalina. Arequipa, Perú", "photo_url": "http://www.panoramio.com/photo/691", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/691.jpg", "longitude": -71.536671, "latitude": -16.395835, "width": 500, "height": 375, "upload_date": "05 October 2005", "owner_id": 7, "owner_name": "Eduardo Manchón", "owner_url": "http://www.panoramio.com/user/7"} +, +{"photo_id": 672525, "photo_title": "Pyramid", "photo_url": "http://www.panoramio.com/photo/672525", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/672525.jpg", "longitude": 31.132421, "latitude": 29.978283, "width": 500, "height": 474, "upload_date": "03 February 2007", "owner_id": 123698, "owner_name": "© Kojak", "owner_url": "http://www.panoramio.com/user/123698"} +, +{"photo_id": 275730, "photo_title": "Oberalp - 2033 m", "photo_url": "http://www.panoramio.com/photo/275730", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/275730.jpg", "longitude": 8.668191, "latitude": 46.661528, "width": 500, "height": 333, "upload_date": "01 January 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 3661332, "photo_title": "Angkor - Temple vs Trees", "photo_url": "http://www.panoramio.com/photo/3661332", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3661332.jpg", "longitude": 103.855079, "latitude": 13.449099, "width": 500, "height": 461, "upload_date": "01 August 2007", "owner_id": 73104, "owner_name": "zerega", "owner_url": "http://www.panoramio.com/user/73104"} +, +{"photo_id": 336151, "photo_title": "Lake north of Tupaassat", "photo_url": "http://www.panoramio.com/photo/336151", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/336151.jpg", "longitude": -44.307861, "latitude": 60.376030, "width": 500, "height": 333, "upload_date": "07 January 2007", "owner_id": 62557, "owner_name": "Dirk Jenrich", "owner_url": "http://www.panoramio.com/user/62557"} +, +{"photo_id": 423705, "photo_title": "Bouche du Pu`u `ÅŒ`Å", "photo_url": "http://www.panoramio.com/photo/423705", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/423705.jpg", "longitude": -155.106182, "latitude": 19.390101, "width": 500, "height": 349, "upload_date": "14 January 2007", "owner_id": 75602, "owner_name": "Lloulhy", "owner_url": "http://www.panoramio.com/user/75602"} +, +{"photo_id": 1344795, "photo_title": "Tree in a field, Aerial", "photo_url": "http://www.panoramio.com/photo/1344795", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1344795.jpg", "longitude": 12.058611, "latitude": 55.471581, "width": 500, "height": 332, "upload_date": "16 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 5591839, "photo_title": "Can I touch the clouds?", "photo_url": "http://www.panoramio.com/photo/5591839", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5591839.jpg", "longitude": 130.689411, "latitude": 33.305569, "width": 333, "height": 500, "upload_date": "28 October 2007", "owner_id": 775356, "owner_name": "ascesis.image", "owner_url": "http://www.panoramio.com/user/775356"} +, +{"photo_id": 5476386, "photo_title": "Nuages crépusculaires sur le Lauterbrunnental", "photo_url": "http://www.panoramio.com/photo/5476386", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5476386.jpg", "longitude": 7.908010, "latitude": 46.592490, "width": 500, "height": 375, "upload_date": "22 October 2007", "owner_id": 359127, "owner_name": "wx", "owner_url": "http://www.panoramio.com/user/359127"} +, +{"photo_id": 459556, "photo_title": "minatopia", "photo_url": "http://www.panoramio.com/photo/459556", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459556.jpg", "longitude": 139.058182, "latitude": 37.930041, "width": 381, "height": 500, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1407525, "photo_title": "Mackinac Bridge, Michigan", "photo_url": "http://www.panoramio.com/photo/1407525", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1407525.jpg", "longitude": -84.729652, "latitude": 45.788250, "width": 500, "height": 313, "upload_date": "20 March 2007", "owner_id": 60173, "owner_name": "Lars Jensen", "owner_url": "http://www.panoramio.com/user/60173"} +, +{"photo_id": 74790, "photo_title": "kang taiga with moon in sunset", "photo_url": "http://www.panoramio.com/photo/74790", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/74790.jpg", "longitude": 86.830101, "latitude": 27.811750, "width": 500, "height": 334, "upload_date": "03 November 2006", "owner_id": 9812, "owner_name": "wsm earp", "owner_url": "http://www.panoramio.com/user/9812"} +, +{"photo_id": 4025902, "photo_title": "Coloured PoznaÅ„ ", "photo_url": "http://www.panoramio.com/photo/4025902", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4025902.jpg", "longitude": 16.934255, "latitude": 52.407878, "width": 500, "height": 316, "upload_date": "19 August 2007", "owner_id": 369127, "owner_name": "♥ Caterpillar", "owner_url": "http://www.panoramio.com/user/369127"} +, +{"photo_id": 88121, "photo_title": "View from Punta Martin - Liguria - Italy", "photo_url": "http://www.panoramio.com/photo/88121", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/88121.jpg", "longitude": 8.795028, "latitude": 44.468489, "width": 500, "height": 375, "upload_date": "28 November 2006", "owner_id": 11098, "owner_name": "Michele Masnata", "owner_url": "http://www.panoramio.com/user/11098"} +, +{"photo_id": 8214845, "photo_title": "Molino Albolafia,cauce del Guadalquivir(Córdoba)", "photo_url": "http://www.panoramio.com/photo/8214845", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8214845.jpg", "longitude": -4.780898, "latitude": 37.876242, "width": 500, "height": 375, "upload_date": "01 March 2008", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 23364, "photo_title": "Alanya, Taurus-Mountains of Kemer", "photo_url": "http://www.panoramio.com/photo/23364", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/23364.jpg", "longitude": 31.979656, "latitude": 36.548466, "width": 500, "height": 375, "upload_date": "10 June 2006", "owner_id": 3760, "owner_name": "Frank Pustlauck", "owner_url": "http://www.panoramio.com/user/3760"} +, +{"photo_id": 6128452, "photo_title": "Ð’ оÑеннем парке - In autumn park", "photo_url": "http://www.panoramio.com/photo/6128452", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6128452.jpg", "longitude": 37.458926, "latitude": 55.737422, "width": 500, "height": 500, "upload_date": "25 November 2007", "owner_id": 244932, "owner_name": "Andrey Jitkov", "owner_url": "http://www.panoramio.com/user/244932"} +, +{"photo_id": 4356679, "photo_title": "Old Santa Fe Caboose", "photo_url": "http://www.panoramio.com/photo/4356679", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4356679.jpg", "longitude": -119.699687, "latitude": 36.707083, "width": 500, "height": 335, "upload_date": "03 September 2007", "owner_id": 339677, "owner_name": "Chip Stephan", "owner_url": "http://www.panoramio.com/user/339677"} +, +{"photo_id": 436312, "photo_title": "tokimesse", "photo_url": "http://www.panoramio.com/photo/436312", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/436312.jpg", "longitude": 139.059105, "latitude": 37.932013, "width": 396, "height": 500, "upload_date": "15 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 1089381, "photo_title": "Szabadon szélben", "photo_url": "http://www.panoramio.com/photo/1089381", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1089381.jpg", "longitude": 17.604561, "latitude": 47.588799, "width": 332, "height": 500, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 5667175, "photo_title": "Northen Lights", "photo_url": "http://www.panoramio.com/photo/5667175", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5667175.jpg", "longitude": 28.482399, "latitude": 66.227860, "width": 500, "height": 333, "upload_date": "01 November 2007", "owner_id": 897591, "owner_name": "markku pirttimaa www.karhukuusamo.com", "owner_url": "http://www.panoramio.com/user/897591"} +, +{"photo_id": 1317737, "photo_title": "Bora Bora", "photo_url": "http://www.panoramio.com/photo/1317737", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1317737.jpg", "longitude": -151.739988, "latitude": -16.538715, "width": 500, "height": 351, "upload_date": "14 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 993129, "photo_title": "Würzburg", "photo_url": "http://www.panoramio.com/photo/993129", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/993129.jpg", "longitude": 9.931523, "latitude": 49.793310, "width": 500, "height": 395, "upload_date": "24 February 2007", "owner_id": 83972, "owner_name": "Maxim Popov (http://www.popovm.ru)", "owner_url": "http://www.panoramio.com/user/83972"} +, +{"photo_id": 1836922, "photo_title": "Fountain Place / Dallas / Texas", "photo_url": "http://www.panoramio.com/photo/1836922", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1836922.jpg", "longitude": -96.802940, "latitude": 32.785236, "width": 500, "height": 405, "upload_date": "19 April 2007", "owner_id": 57778, "owner_name": "William Lile", "owner_url": "http://www.panoramio.com/user/57778"} +, +{"photo_id": 3409786, "photo_title": "Molinos de Elguea con Gorbea al fondo", "photo_url": "http://www.panoramio.com/photo/3409786", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3409786.jpg", "longitude": -2.325025, "latitude": 42.951271, "width": 500, "height": 303, "upload_date": "19 July 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 476284, "photo_title": "Place \"Poda\"", "photo_url": "http://www.panoramio.com/photo/476284", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/476284.jpg", "longitude": 27.471657, "latitude": 42.447655, "width": 500, "height": 357, "upload_date": "18 January 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 3499645, "photo_title": "Tükör-kép", "photo_url": "http://www.panoramio.com/photo/3499645", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3499645.jpg", "longitude": 17.503667, "latitude": 47.843522, "width": 500, "height": 333, "upload_date": "24 July 2007", "owner_id": 689769, "owner_name": "Ponty István", "owner_url": "http://www.panoramio.com/user/689769"} +, +{"photo_id": 1419901, "photo_title": "Øresundsbroen seen from Sweden (The Dragon Tail), Aerial", "photo_url": "http://www.panoramio.com/photo/1419901", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1419901.jpg", "longitude": 12.885418, "latitude": 55.566213, "width": 332, "height": 500, "upload_date": "20 March 2007", "owner_id": 278074, "owner_name": "H. C. Steensen", "owner_url": "http://www.panoramio.com/user/278074"} +, +{"photo_id": 441727, "photo_title": "Ð¤Ð¾Ñ€Ñ‚ÐµÑ†Ñ Ñƒ Кам'Ñнці-ПодільÑькому", "photo_url": "http://www.panoramio.com/photo/441727", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/441727.jpg", "longitude": 26.563311, "latitude": 48.672486, "width": 375, "height": 500, "upload_date": "15 January 2007", "owner_id": 13058, "owner_name": "Kyryl", "owner_url": "http://www.panoramio.com/user/13058"} +, +{"photo_id": 309122, "photo_title": "Standing Stone, Spittal of Glenshee", "photo_url": "http://www.panoramio.com/photo/309122", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/309122.jpg", "longitude": -3.461593, "latitude": 56.814745, "width": 500, "height": 332, "upload_date": "05 January 2007", "owner_id": 64815, "owner_name": "PigleT", "owner_url": "http://www.panoramio.com/user/64815"} +, +{"photo_id": 2599560, "photo_title": "Isigaki Island Hirakubosaki lighthouse 石垣島 平久ä¿å´Žç¯å°", "photo_url": "http://www.panoramio.com/photo/2599560", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2599560.jpg", "longitude": 124.315994, "latitude": 24.610064, "width": 500, "height": 328, "upload_date": "06 June 2007", "owner_id": 446937, "owner_name": "y_komatsu", "owner_url": "http://www.panoramio.com/user/446937"} +, +{"photo_id": 6545801, "photo_title": "Front Range of the Canadian Rocky Mountains", "photo_url": "http://www.panoramio.com/photo/6545801", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6545801.jpg", "longitude": -115.248213, "latitude": 51.026389, "width": 500, "height": 338, "upload_date": "18 December 2007", "owner_id": 85489, "owner_name": "Bruce MacIver", "owner_url": "http://www.panoramio.com/user/85489"} +, +{"photo_id": 1254026, "photo_title": "Hagia Sophia (inside)", "photo_url": "http://www.panoramio.com/photo/1254026", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1254026.jpg", "longitude": 28.979831, "latitude": 41.008548, "width": 500, "height": 408, "upload_date": "10 March 2007", "owner_id": 258322, "owner_name": "www.tatjana.ingold.ch", "owner_url": "http://www.panoramio.com/user/258322"} +, +{"photo_id": 911501, "photo_title": "View from Nordenskiöldtoppen, Svalbard", "photo_url": "http://www.panoramio.com/photo/911501", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/911501.jpg", "longitude": 15.402832, "latitude": 78.184088, "width": 500, "height": 308, "upload_date": "20 February 2007", "owner_id": 66734, "owner_name": "Svein Solhaug", "owner_url": "http://www.panoramio.com/user/66734"} +, +{"photo_id": 3797140, "photo_title": "Mas Francesc", "photo_url": "http://www.panoramio.com/photo/3797140", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3797140.jpg", "longitude": 2.408388, "latitude": 41.962346, "width": 500, "height": 332, "upload_date": "08 August 2007", "owner_id": 756267, "owner_name": "Albert Codina", "owner_url": "http://www.panoramio.com/user/756267"} +, +{"photo_id": 150165, "photo_title": "Aso crater from the air", "photo_url": "http://www.panoramio.com/photo/150165", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/150165.jpg", "longitude": 131.083159, "latitude": 32.885390, "width": 500, "height": 375, "upload_date": "14 December 2006", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 532631, "photo_title": "Last bath in Oslofjorden - self portrait", "photo_url": "http://www.panoramio.com/photo/532631", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532631.jpg", "longitude": 10.782223, "latitude": 59.854773, "width": 500, "height": 205, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 3978149, "photo_title": "Les Mines 3", "photo_url": "http://www.panoramio.com/photo/3978149", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3978149.jpg", "longitude": 1.315312, "latitude": 45.921961, "width": 500, "height": 500, "upload_date": "16 August 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 848807, "photo_title": "mystic morning", "photo_url": "http://www.panoramio.com/photo/848807", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/848807.jpg", "longitude": 10.144372, "latitude": 54.323031, "width": 375, "height": 500, "upload_date": "17 February 2007", "owner_id": 73946, "owner_name": "pembo", "owner_url": "http://www.panoramio.com/user/73946"} +, +{"photo_id": 4097972, "photo_title": "Dry Land", "photo_url": "http://www.panoramio.com/photo/4097972", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4097972.jpg", "longitude": 25.936694, "latitude": 41.660906, "width": 500, "height": 333, "upload_date": "22 August 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 479927, "photo_title": "Monterosso at night", "photo_url": "http://www.panoramio.com/photo/479927", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/479927.jpg", "longitude": 9.655094, "latitude": 44.144461, "width": 500, "height": 357, "upload_date": "18 January 2007", "owner_id": 100907, "owner_name": "Julia Wahl", "owner_url": "http://www.panoramio.com/user/100907"} +, +{"photo_id": 50872, "photo_title": "Düne 40 auf dem Weg nach Sossusvlei ...", "photo_url": "http://www.panoramio.com/photo/50872", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/50872.jpg", "longitude": 15.593033, "latitude": -24.720950, "width": 500, "height": 192, "upload_date": "22 September 2006", "owner_id": 7434, "owner_name": "baldinger reisen ag, waedenswil/switzerland", "owner_url": "http://www.panoramio.com/user/7434"} +, +{"photo_id": 2903483, "photo_title": "Reggeli", "photo_url": "http://www.panoramio.com/photo/2903483", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2903483.jpg", "longitude": 17.469549, "latitude": 47.868977, "width": 410, "height": 500, "upload_date": "23 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4226249, "photo_title": "Rainbow", "photo_url": "http://www.panoramio.com/photo/4226249", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4226249.jpg", "longitude": 9.615569, "latitude": 62.529150, "width": 500, "height": 230, "upload_date": "27 August 2007", "owner_id": 223406, "owner_name": "Sigmund Rise", "owner_url": "http://www.panoramio.com/user/223406"} +, +{"photo_id": 2267849, "photo_title": "Rayos vistos desde mi ventana", "photo_url": "http://www.panoramio.com/photo/2267849", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2267849.jpg", "longitude": -89.203963, "latitude": 13.728734, "width": 500, "height": 375, "upload_date": "17 May 2007", "owner_id": 170919, "owner_name": "Wilber Calderón - El Salvador", "owner_url": "http://www.panoramio.com/user/170919"} +, +{"photo_id": 459470, "photo_title": "bandaibashi4", "photo_url": "http://www.panoramio.com/photo/459470", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459470.jpg", "longitude": 139.051123, "latitude": 37.919081, "width": 500, "height": 399, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 5279707, "photo_title": "Jægervasstindane", "photo_url": "http://www.panoramio.com/photo/5279707", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5279707.jpg", "longitude": 19.651279, "latitude": 69.771296, "width": 500, "height": 375, "upload_date": "13 October 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 1057758, "photo_title": "Giant dragonfly in rice field", "photo_url": "http://www.panoramio.com/photo/1057758", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1057758.jpg", "longitude": 137.115641, "latitude": 34.862834, "width": 500, "height": 375, "upload_date": "27 February 2007", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 479454, "photo_title": "Morning sun over lake Øymarksjøen", "photo_url": "http://www.panoramio.com/photo/479454", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/479454.jpg", "longitude": 11.637611, "latitude": 59.338617, "width": 333, "height": 500, "upload_date": "18 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 87263, "photo_title": "Payun - Mendoza - Argentina", "photo_url": "http://www.panoramio.com/photo/87263", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/87263.jpg", "longitude": -69.280128, "latitude": -36.643080, "width": 500, "height": 333, "upload_date": "27 November 2006", "owner_id": 8409, "owner_name": "Hector Fabian Garrido", "owner_url": "http://www.panoramio.com/user/8409"} +, +{"photo_id": 11430112, "photo_title": "Tramonto dalla Pietra Parcellara", "photo_url": "http://www.panoramio.com/photo/11430112", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11430112.jpg", "longitude": 9.476480, "latitude": 44.843334, "width": 500, "height": 375, "upload_date": "22 June 2008", "owner_id": 22921, "owner_name": "Francesco Favalesi - VAL LURETTA", "owner_url": "http://www.panoramio.com/user/22921"} +, +{"photo_id": 33760, "photo_title": "Yu Yuan Gardens", "photo_url": "http://www.panoramio.com/photo/33760", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/33760.jpg", "longitude": 121.487803, "latitude": 31.228821, "width": 500, "height": 375, "upload_date": "21 July 2006", "owner_id": 5168, "owner_name": "Markus Källander", "owner_url": "http://www.panoramio.com/user/5168"} +, +{"photo_id": 1935332, "photo_title": "Lafayette", "photo_url": "http://www.panoramio.com/photo/1935332", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1935332.jpg", "longitude": 2.311839, "latitude": 48.864475, "width": 384, "height": 500, "upload_date": "26 April 2007", "owner_id": 372189, "owner_name": "Phil©", "owner_url": "http://www.panoramio.com/user/372189"} +, +{"photo_id": 2558954, "photo_title": "Two Thumbs Morning", "photo_url": "http://www.panoramio.com/photo/2558954", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2558954.jpg", "longitude": 170.463352, "latitude": -43.999792, "width": 500, "height": 400, "upload_date": "04 June 2007", "owner_id": 286729, "owner_name": "jimwitkowski", "owner_url": "http://www.panoramio.com/user/286729"} +, +{"photo_id": 94190, "photo_title": "morning light", "photo_url": "http://www.panoramio.com/photo/94190", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/94190.jpg", "longitude": 138.362846, "latitude": 35.981896, "width": 500, "height": 375, "upload_date": "09 December 2006", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 1283054, "photo_title": "Panorama - Bahia desde la playa", "photo_url": "http://www.panoramio.com/photo/1283054", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1283054.jpg", "longitude": -1.990094, "latitude": 43.316053, "width": 500, "height": 167, "upload_date": "12 March 2007", "owner_id": 218075, "owner_name": "fotoramas", "owner_url": "http://www.panoramio.com/user/218075"} +, +{"photo_id": 2541040, "photo_title": "Színförgeteg", "photo_url": "http://www.panoramio.com/photo/2541040", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2541040.jpg", "longitude": 17.506886, "latitude": 47.744403, "width": 500, "height": 334, "upload_date": "03 June 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 837872, "photo_title": "Midnight Sunset", "photo_url": "http://www.panoramio.com/photo/837872", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/837872.jpg", "longitude": -14.670181, "latitude": 65.142363, "width": 500, "height": 333, "upload_date": "16 February 2007", "owner_id": 175423, "owner_name": "Fabien Barrau", "owner_url": "http://www.panoramio.com/user/175423"} +, +{"photo_id": 1706995, "photo_title": "Cantera de Manresa", "photo_url": "http://www.panoramio.com/photo/1706995", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1706995.jpg", "longitude": 3.131152, "latitude": 39.868942, "width": 335, "height": 500, "upload_date": "09 April 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 575731, "photo_title": "Le Mont Saint-Michel (Francia)", "photo_url": "http://www.panoramio.com/photo/575731", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/575731.jpg", "longitude": -1.498604, "latitude": 48.636085, "width": 500, "height": 334, "upload_date": "26 January 2007", "owner_id": 38814, "owner_name": "Romeo Ferrari", "owner_url": "http://www.panoramio.com/user/38814"} +, +{"photo_id": 1960951, "photo_title": "Utah Autumn Aspen", "photo_url": "http://www.panoramio.com/photo/1960951", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1960951.jpg", "longitude": -111.620750, "latitude": 40.441721, "width": 500, "height": 332, "upload_date": "28 April 2007", "owner_id": 107359, "owner_name": "Ron Cooper", "owner_url": "http://www.panoramio.com/user/107359"} +, +{"photo_id": 162298, "photo_title": "Nuvole (Effetto Dio) sopra Marano Ticino (2 of 2), settembre 2005", "photo_url": "http://www.panoramio.com/photo/162298", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/162298.jpg", "longitude": 8.623238, "latitude": 45.629825, "width": 500, "height": 375, "upload_date": "16 December 2006", "owner_id": 18925, "owner_name": "Marco Ferrari", "owner_url": "http://www.panoramio.com/user/18925"} +, +{"photo_id": 9358587, "photo_title": "Sicilia, a me bedda!", "photo_url": "http://www.panoramio.com/photo/9358587", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9358587.jpg", "longitude": 14.652908, "latitude": 38.068172, "width": 500, "height": 375, "upload_date": "14 April 2008", "owner_id": 325031, "owner_name": "Gibrail", "owner_url": "http://www.panoramio.com/user/325031"} +, +{"photo_id": 11271799, "photo_title": "Candelaria, version completa ( Candelaria, full version )", "photo_url": "http://www.panoramio.com/photo/11271799", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/11271799.jpg", "longitude": -18.005776, "latitude": 27.750886, "width": 334, "height": 500, "upload_date": "16 June 2008", "owner_id": 787217, "owner_name": "♣ Víctor S de Lara ♣", "owner_url": "http://www.panoramio.com/user/787217"} +, +{"photo_id": 81, "photo_title": "North Cape from plane", "photo_url": "http://www.panoramio.com/photo/81", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/81.jpg", "longitude": 25.786285, "latitude": 71.171196, "width": 500, "height": 340, "upload_date": "30 July 2005", "owner_id": 7, "owner_name": "Eduardo Manchón", "owner_url": "http://www.panoramio.com/user/7"} +, +{"photo_id": 6548480, "photo_title": "ç å³°æ™“月", "photo_url": "http://www.panoramio.com/photo/6548480", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6548480.jpg", "longitude": 86.857567, "latitude": 28.119833, "width": 500, "height": 332, "upload_date": "18 December 2007", "owner_id": 1201050, "owner_name": "黄河影人", "owner_url": "http://www.panoramio.com/user/1201050"} +, +{"photo_id": 1989382, "photo_title": "", "photo_url": "http://www.panoramio.com/photo/1989382", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1989382.jpg", "longitude": 20.628827, "latitude": 52.062874, "width": 500, "height": 375, "upload_date": "29 April 2007", "owner_id": 234038, "owner_name": "Jacek M.", "owner_url": "http://www.panoramio.com/user/234038"} +, +{"photo_id": 3186699, "photo_title": "Ruta del Cares: Paredón de los Collainos -más 400 m. de vertical-", "photo_url": "http://www.panoramio.com/photo/3186699", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3186699.jpg", "longitude": -4.863296, "latitude": 43.253174, "width": 335, "height": 500, "upload_date": "08 July 2007", "owner_id": 129297, "owner_name": "Enrique Ortiz de Zárate", "owner_url": "http://www.panoramio.com/user/129297"} +, +{"photo_id": 9899533, "photo_title": "Grado: Are you Ready? . . . . . . . . . Honorable mention \"Scenery\" May Contest 2008", "photo_url": "http://www.panoramio.com/photo/9899533", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9899533.jpg", "longitude": 13.395016, "latitude": 45.676262, "width": 500, "height": 375, "upload_date": "04 May 2008", "owner_id": 381221, "owner_name": "Flavio Snidero", "owner_url": "http://www.panoramio.com/user/381221"} +, +{"photo_id": 324623, "photo_title": "richmond bridge", "photo_url": "http://www.panoramio.com/photo/324623", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/324623.jpg", "longitude": 147.439506, "latitude": -42.734358, "width": 500, "height": 375, "upload_date": "06 January 2007", "owner_id": 66974, "owner_name": "lieskovec", "owner_url": "http://www.panoramio.com/user/66974"} +, +{"photo_id": 4450585, "photo_title": "Giorno di riposo", "photo_url": "http://www.panoramio.com/photo/4450585", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4450585.jpg", "longitude": 35.440521, "latitude": 33.732906, "width": 500, "height": 375, "upload_date": "06 September 2007", "owner_id": 407625, "owner_name": "Lyana Luna", "owner_url": "http://www.panoramio.com/user/407625"} +, +{"photo_id": 1088801, "photo_title": "Kalászos impresszió", "photo_url": "http://www.panoramio.com/photo/1088801", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1088801.jpg", "longitude": 17.727127, "latitude": 47.444575, "width": 500, "height": 360, "upload_date": "28 February 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 290083, "photo_title": "Beach full of life", "photo_url": "http://www.panoramio.com/photo/290083", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/290083.jpg", "longitude": -59.072113, "latitude": -52.430478, "width": 335, "height": 500, "upload_date": "03 January 2007", "owner_id": 61890, "owner_name": "enriquevidalphoto.com", "owner_url": "http://www.panoramio.com/user/61890"} +, +{"photo_id": 5734694, "photo_title": "Virginia Horse Country", "photo_url": "http://www.panoramio.com/photo/5734694", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5734694.jpg", "longitude": -78.754292, "latitude": 38.014964, "width": 500, "height": 375, "upload_date": "05 November 2007", "owner_id": 523038, "owner_name": "Yank in Dixie", "owner_url": "http://www.panoramio.com/user/523038"} +, +{"photo_id": 6012970, "photo_title": "Herbstliches Venedig", "photo_url": "http://www.panoramio.com/photo/6012970", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6012970.jpg", "longitude": 12.343435, "latitude": 45.433752, "width": 500, "height": 336, "upload_date": "19 November 2007", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 6321454, "photo_title": "Sea Storm III - \" Dragonara \" Castle", "photo_url": "http://www.panoramio.com/photo/6321454", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6321454.jpg", "longitude": 9.151177, "latitude": 44.350211, "width": 444, "height": 500, "upload_date": "05 December 2007", "owner_id": 180947, "owner_name": "gilberto silvestri", "owner_url": "http://www.panoramio.com/user/180947"} +, +{"photo_id": 459569, "photo_title": "mt hakkai", "photo_url": "http://www.panoramio.com/photo/459569", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459569.jpg", "longitude": 138.921432, "latitude": 37.092157, "width": 500, "height": 389, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 940337, "photo_title": "Sunrising Monuments", "photo_url": "http://www.panoramio.com/photo/940337", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/940337.jpg", "longitude": -110.110474, "latitude": 36.980255, "width": 500, "height": 287, "upload_date": "21 February 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 2400305, "photo_title": "Cape of Favaritx, Gateway to Another Planet", "photo_url": "http://www.panoramio.com/photo/2400305", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2400305.jpg", "longitude": 4.264122, "latitude": 39.996608, "width": 500, "height": 352, "upload_date": "26 May 2007", "owner_id": 213866, "owner_name": "Nicolas Mertens", "owner_url": "http://www.panoramio.com/user/213866"} +, +{"photo_id": 398130, "photo_title": "Aiguille du Chardonnet", "photo_url": "http://www.panoramio.com/photo/398130", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/398130.jpg", "longitude": 7.013569, "latitude": 45.979190, "width": 500, "height": 333, "upload_date": "12 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 283954, "photo_title": "Dong-ao:The most beautiful coast of Taiwan", "photo_url": "http://www.panoramio.com/photo/283954", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/283954.jpg", "longitude": 121.850481, "latitude": 24.524822, "width": 500, "height": 375, "upload_date": "02 January 2007", "owner_id": 60214, "owner_name": "swinelin", "owner_url": "http://www.panoramio.com/user/60214"} +, +{"photo_id": 5115188, "photo_title": "Iceland", "photo_url": "http://www.panoramio.com/photo/5115188", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5115188.jpg", "longitude": -23.008804, "latitude": 64.947976, "width": 500, "height": 333, "upload_date": "05 October 2007", "owner_id": 588149, "owner_name": "Adam Salwanowicz", "owner_url": "http://www.panoramio.com/user/588149"} +, +{"photo_id": 1865268, "photo_title": "Rainbow Ridge Sunset", "photo_url": "http://www.panoramio.com/photo/1865268", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1865268.jpg", "longitude": -112.404728, "latitude": 36.426808, "width": 500, "height": 333, "upload_date": "21 April 2007", "owner_id": 66847, "owner_name": "Lukas Novak", "owner_url": "http://www.panoramio.com/user/66847"} +, +{"photo_id": 1633076, "photo_title": "Parliament", "photo_url": "http://www.panoramio.com/photo/1633076", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1633076.jpg", "longitude": 19.046752, "latitude": 47.512998, "width": 500, "height": 500, "upload_date": "04 April 2007", "owner_id": 52226, "owner_name": "jenoapu", "owner_url": "http://www.panoramio.com/user/52226"} +, +{"photo_id": 800056, "photo_title": "Karst Landscape in Guangxi, China", "photo_url": "http://www.panoramio.com/photo/800056", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/800056.jpg", "longitude": 107.121944, "latitude": 23.605000, "width": 500, "height": 191, "upload_date": "13 February 2007", "owner_id": 164125, "owner_name": "DannyXu", "owner_url": "http://www.panoramio.com/user/164125"} +, +{"photo_id": 21304, "photo_title": "Matterhorn", "photo_url": "http://www.panoramio.com/photo/21304", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/21304.jpg", "longitude": 7.718582, "latitude": 45.994577, "width": 375, "height": 500, "upload_date": "28 May 2006", "owner_id": 3404, "owner_name": "Csongor Böröczky", "owner_url": "http://www.panoramio.com/user/3404"} +, +{"photo_id": 402493, "photo_title": "Burg-Eltz", "photo_url": "http://www.panoramio.com/photo/402493", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/402493.jpg", "longitude": 7.336400, "latitude": 50.206104, "width": 369, "height": 500, "upload_date": "12 January 2007", "owner_id": 6105, "owner_name": "hackltom", "owner_url": "http://www.panoramio.com/user/6105"} +, +{"photo_id": 411453, "photo_title": "Dune 45 in Sosussvlei", "photo_url": "http://www.panoramio.com/photo/411453", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/411453.jpg", "longitude": 15.397339, "latitude": -24.739972, "width": 500, "height": 333, "upload_date": "13 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 1813822, "photo_title": "Csendes délután", "photo_url": "http://www.panoramio.com/photo/1813822", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1813822.jpg", "longitude": 17.779655, "latitude": 47.507229, "width": 500, "height": 334, "upload_date": "17 April 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 798783, "photo_title": "Georgia, Antelope Canyon, AZ", "photo_url": "http://www.panoramio.com/photo/798783", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/798783.jpg", "longitude": -111.385489, "latitude": 36.873441, "width": 376, "height": 500, "upload_date": "12 February 2007", "owner_id": 52440, "owner_name": "Hank Waxman", "owner_url": "http://www.panoramio.com/user/52440"} +, +{"photo_id": 5193281, "photo_title": "The park at Gamlehaugen a bautiful day in September 2007, Bergen - Norway", "photo_url": "http://www.panoramio.com/photo/5193281", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5193281.jpg", "longitude": 5.336909, "latitude": 60.341253, "width": 500, "height": 279, "upload_date": "09 October 2007", "owner_id": 121518, "owner_name": "S.M Tunli - www.tunliweb.no", "owner_url": "http://www.panoramio.com/user/121518"} +, +{"photo_id": 642882, "photo_title": "La Presolana e la Cometa Hale-Bopp", "photo_url": "http://www.panoramio.com/photo/642882", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/642882.jpg", "longitude": 10.094032, "latitude": 45.927991, "width": 500, "height": 375, "upload_date": "01 February 2007", "owner_id": 38814, "owner_name": "Romeo Ferrari", "owner_url": "http://www.panoramio.com/user/38814"} +, +{"photo_id": 304963, "photo_title": "Calanque d'En Vau 2", "photo_url": "http://www.panoramio.com/photo/304963", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/304963.jpg", "longitude": 5.500288, "latitude": 43.201422, "width": 500, "height": 375, "upload_date": "05 January 2007", "owner_id": 64344, "owner_name": "Seb - Lyon", "owner_url": "http://www.panoramio.com/user/64344"} +, +{"photo_id": 6126154, "photo_title": "Swan - EPping Forest", "photo_url": "http://www.panoramio.com/photo/6126154", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6126154.jpg", "longitude": 0.025658, "latitude": 51.638836, "width": 499, "height": 500, "upload_date": "25 November 2007", "owner_id": 1130880, "owner_name": "marksimms", "owner_url": "http://www.panoramio.com/user/1130880"} +, +{"photo_id": 441426, "photo_title": "Dettifoss", "photo_url": "http://www.panoramio.com/photo/441426", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/441426.jpg", "longitude": -16.390743, "latitude": 65.819939, "width": 500, "height": 350, "upload_date": "15 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 4105301, "photo_title": "Eikesdalsvatnet. Norway.", "photo_url": "http://www.panoramio.com/photo/4105301", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4105301.jpg", "longitude": 8.171768, "latitude": 62.561718, "width": 500, "height": 326, "upload_date": "22 August 2007", "owner_id": 806637, "owner_name": "Bjørn Fransgjerde", "owner_url": "http://www.panoramio.com/user/806637"} +, +{"photo_id": 519765, "photo_title": "Derűs szeglet", "photo_url": "http://www.panoramio.com/photo/519765", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/519765.jpg", "longitude": 17.173862, "latitude": 46.633997, "width": 500, "height": 282, "upload_date": "21 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 4401751, "photo_title": "Fire Escape", "photo_url": "http://www.panoramio.com/photo/4401751", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4401751.jpg", "longitude": -2.315347, "latitude": 52.644873, "width": 366, "height": 500, "upload_date": "04 September 2007", "owner_id": 1295, "owner_name": "Matthew Walters", "owner_url": "http://www.panoramio.com/user/1295"} +, +{"photo_id": 1747294, "photo_title": "Red Fort II / Fuerte rojo II", "photo_url": "http://www.panoramio.com/photo/1747294", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1747294.jpg", "longitude": 73.017197, "latitude": 26.296801, "width": 500, "height": 375, "upload_date": "12 April 2007", "owner_id": 414, "owner_name": "Sonia Villegas", "owner_url": "http://www.panoramio.com/user/414"} +, +{"photo_id": 2856289, "photo_title": "Copacabana Praia", "photo_url": "http://www.panoramio.com/photo/2856289", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2856289.jpg", "longitude": -43.179188, "latitude": -22.969457, "width": 500, "height": 375, "upload_date": "20 June 2007", "owner_id": 496676, "owner_name": "Quasebart", "owner_url": "http://www.panoramio.com/user/496676"} +, +{"photo_id": 3116906, "photo_title": "Mototaki Falls", "photo_url": "http://www.panoramio.com/photo/3116906", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/3116906.jpg", "longitude": 139.954662, "latitude": 39.158750, "width": 500, "height": 375, "upload_date": "04 July 2007", "owner_id": 164173, "owner_name": "tsushima", "owner_url": "http://www.panoramio.com/user/164173"} +, +{"photo_id": 8919659, "photo_title": "Bavarian Forest", "photo_url": "http://www.panoramio.com/photo/8919659", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/8919659.jpg", "longitude": 12.429099, "latitude": 49.084548, "width": 500, "height": 332, "upload_date": "28 March 2008", "owner_id": 696605, "owner_name": "© alfredschaffer", "owner_url": "http://www.panoramio.com/user/696605"} +, +{"photo_id": 2040174, "photo_title": "Looking east from Sognefjellet - april 29", "photo_url": "http://www.panoramio.com/photo/2040174", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2040174.jpg", "longitude": 7.974873, "latitude": 61.561141, "width": 375, "height": 500, "upload_date": "03 May 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 1195122, "photo_title": "Cerro Macon", "photo_url": "http://www.panoramio.com/photo/1195122", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1195122.jpg", "longitude": -67.356405, "latitude": -24.528540, "width": 335, "height": 500, "upload_date": "06 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 1182587, "photo_title": "Gaggenau-Moosbronn, Wallfahrtskirche", "photo_url": "http://www.panoramio.com/photo/1182587", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1182587.jpg", "longitude": 8.384285, "latitude": 48.840486, "width": 382, "height": 500, "upload_date": "05 March 2007", "owner_id": 66229, "owner_name": "Mast", "owner_url": "http://www.panoramio.com/user/66229"} +, +{"photo_id": 4787323, "photo_title": "Hell's Gate(Antigua-Caribe)", "photo_url": "http://www.panoramio.com/photo/4787323", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4787323.jpg", "longitude": -61.722651, "latitude": 17.140052, "width": 500, "height": 375, "upload_date": "20 September 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 5474175, "photo_title": "Chemin bucolique au Lauterbrunnental 2", "photo_url": "http://www.panoramio.com/photo/5474175", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/5474175.jpg", "longitude": 7.909877, "latitude": 46.580479, "width": 500, "height": 384, "upload_date": "22 October 2007", "owner_id": 359127, "owner_name": "wx", "owner_url": "http://www.panoramio.com/user/359127"} +, +{"photo_id": 479364, "photo_title": "The Earth Above Us II", "photo_url": "http://www.panoramio.com/photo/479364", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/479364.jpg", "longitude": 19.053029, "latitude": 47.601392, "width": 500, "height": 317, "upload_date": "18 January 2007", "owner_id": 57869, "owner_name": "NAGY Albert", "owner_url": "http://www.panoramio.com/user/57869"} +, +{"photo_id": 575110, "photo_title": "A huge wave crashes against the front of Kiama Blowhole www.ozthunder.com", "photo_url": "http://www.panoramio.com/photo/575110", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/575110.jpg", "longitude": 150.863657, "latitude": -34.671264, "width": 500, "height": 338, "upload_date": "26 January 2007", "owner_id": 67208, "owner_name": "Michael Thompson", "owner_url": "http://www.panoramio.com/user/67208"} +, +{"photo_id": 543624, "photo_title": "Dalmát álom", "photo_url": "http://www.panoramio.com/photo/543624", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/543624.jpg", "longitude": 15.969143, "latitude": 43.624768, "width": 500, "height": 333, "upload_date": "23 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 121224, "photo_title": "ParadisePW", "photo_url": "http://www.panoramio.com/photo/121224", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/121224.jpg", "longitude": -62.907715, "latitude": -64.830254, "width": 500, "height": 329, "upload_date": "12 December 2006", "owner_id": 19856, "owner_name": "Juan Kratzmaier", "owner_url": "http://www.panoramio.com/user/19856"} +, +{"photo_id": 10074505, "photo_title": "Volcàn Chaitèn, Chaitèn, Palena, Chile Por Daniel Basualto", "photo_url": "http://www.panoramio.com/photo/10074505", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10074505.jpg", "longitude": -72.759705, "latitude": -42.908160, "width": 375, "height": 500, "upload_date": "10 May 2008", "owner_id": 88547, "owner_name": "Patricia Santini", "owner_url": "http://www.panoramio.com/user/88547"} +, +{"photo_id": 10378, "photo_title": "Chiang Mai, temple", "photo_url": "http://www.panoramio.com/photo/10378", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10378.jpg", "longitude": 98.921596, "latitude": 18.805157, "width": 319, "height": 500, "upload_date": "06 February 2006", "owner_id": 414, "owner_name": "Sonia Villegas", "owner_url": "http://www.panoramio.com/user/414"} +, +{"photo_id": 532620, "photo_title": "Morning mist near Skjønhaug", "photo_url": "http://www.panoramio.com/photo/532620", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532620.jpg", "longitude": 11.297293, "latitude": 59.639511, "width": 333, "height": 500, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 625805, "photo_title": "Primosten blue(s)", "photo_url": "http://www.panoramio.com/photo/625805", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/625805.jpg", "longitude": 15.932236, "latitude": 43.575168, "width": 500, "height": 334, "upload_date": "30 January 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 247704, "photo_title": "Paris in the night", "photo_url": "http://www.panoramio.com/photo/247704", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/247704.jpg", "longitude": 2.294512, "latitude": 48.858052, "width": 327, "height": 500, "upload_date": "27 December 2006", "owner_id": 51517, "owner_name": "threshold2000", "owner_url": "http://www.panoramio.com/user/51517"} +, +{"photo_id": 73888, "photo_title": "Fitz-Roy", "photo_url": "http://www.panoramio.com/photo/73888", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/73888.jpg", "longitude": -72.987328, "latitude": -49.277885, "width": 500, "height": 204, "upload_date": "01 November 2006", "owner_id": 7372, "owner_name": "vuillet", "owner_url": "http://www.panoramio.com/user/7372"} +, +{"photo_id": 6065568, "photo_title": "Amigos para siempre Paris-Francia", "photo_url": "http://www.panoramio.com/photo/6065568", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6065568.jpg", "longitude": 2.288697, "latitude": 48.861906, "width": 375, "height": 500, "upload_date": "22 November 2007", "owner_id": 83865, "owner_name": "Epi F.Villanueva", "owner_url": "http://www.panoramio.com/user/83865"} +, +{"photo_id": 9643938, "photo_title": "Occhio indiscreto ... sulla città ... illuminata ", "photo_url": "http://www.panoramio.com/photo/9643938", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/9643938.jpg", "longitude": 13.818569, "latitude": 45.641329, "width": 500, "height": 449, "upload_date": "23 April 2008", "owner_id": 1121720, "owner_name": "â–¬ Mauro Antonini â–¬", "owner_url": "http://www.panoramio.com/user/1121720"} +, +{"photo_id": 532643, "photo_title": "Icecarved granite at Herføl", "photo_url": "http://www.panoramio.com/photo/532643", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/532643.jpg", "longitude": 11.054649, "latitude": 58.986512, "width": 375, "height": 500, "upload_date": "22 January 2007", "owner_id": 39160, "owner_name": "Snemann", "owner_url": "http://www.panoramio.com/user/39160"} +, +{"photo_id": 112298, "photo_title": "paris06_004IR", "photo_url": "http://www.panoramio.com/photo/112298", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/112298.jpg", "longitude": 2.343779, "latitude": 48.887746, "width": 500, "height": 500, "upload_date": "11 December 2006", "owner_id": 17599, "owner_name": "Dmitry Andreev", "owner_url": "http://www.panoramio.com/user/17599"} +, +{"photo_id": 525997, "photo_title": "Grand Canyon Desert View", "photo_url": "http://www.panoramio.com/photo/525997", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/525997.jpg", "longitude": -111.824341, "latitude": 36.043547, "width": 500, "height": 333, "upload_date": "22 January 2007", "owner_id": 85489, "owner_name": "Bruce MacIver", "owner_url": "http://www.panoramio.com/user/85489"} +, +{"photo_id": 2972849, "photo_title": "Donadea Forest", "photo_url": "http://www.panoramio.com/photo/2972849", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2972849.jpg", "longitude": -6.743374, "latitude": 53.346555, "width": 500, "height": 377, "upload_date": "27 June 2007", "owner_id": 137785, "owner_name": "W@Z", "owner_url": "http://www.panoramio.com/user/137785"} +, +{"photo_id": 1175992, "photo_title": "Mt. Roberts Tram, Juneau, Alaska", "photo_url": "http://www.panoramio.com/photo/1175992", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1175992.jpg", "longitude": -134.391643, "latitude": 58.294679, "width": 500, "height": 347, "upload_date": "05 March 2007", "owner_id": 52440, "owner_name": "Hank Waxman", "owner_url": "http://www.panoramio.com/user/52440"} +, +{"photo_id": 462521, "photo_title": "Fontaine de Trevi", "photo_url": "http://www.panoramio.com/photo/462521", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/462521.jpg", "longitude": 12.483280, "latitude": 41.901047, "width": 500, "height": 333, "upload_date": "17 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 848316, "photo_title": "Malyovitsa, Rila", "photo_url": "http://www.panoramio.com/photo/848316", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/848316.jpg", "longitude": 23.383627, "latitude": 42.201517, "width": 500, "height": 357, "upload_date": "17 February 2007", "owner_id": 16880, "owner_name": "evgenidinev.com", "owner_url": "http://www.panoramio.com/user/16880"} +, +{"photo_id": 459453, "photo_title": "bandaibashi3", "photo_url": "http://www.panoramio.com/photo/459453", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/459453.jpg", "longitude": 139.055586, "latitude": 37.920436, "width": 500, "height": 382, "upload_date": "16 January 2007", "owner_id": 86411, "owner_name": "中æ‘è„©-Osamu nakamura", "owner_url": "http://www.panoramio.com/user/86411"} +, +{"photo_id": 968639, "photo_title": "张永富 黄山风光06 Huangshan", "photo_url": "http://www.panoramio.com/photo/968639", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/968639.jpg", "longitude": 118.166199, "latitude": 30.105633, "width": 348, "height": 500, "upload_date": "23 February 2007", "owner_id": 203011, "owner_name": "SammyZhang", "owner_url": "http://www.panoramio.com/user/203011"} +, +{"photo_id": 97731, "photo_title": "Kaimondake", "photo_url": "http://www.panoramio.com/photo/97731", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/97731.jpg", "longitude": 130.652161, "latitude": 31.247443, "width": 500, "height": 212, "upload_date": "09 December 2006", "owner_id": 11781, "owner_name": "ANDRE GARDELLA", "owner_url": "http://www.panoramio.com/user/11781"} +, +{"photo_id": 2859205, "photo_title": "Lundy Lake Sunset", "photo_url": "http://www.panoramio.com/photo/2859205", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2859205.jpg", "longitude": -119.221230, "latitude": 38.031597, "width": 400, "height": 500, "upload_date": "21 June 2007", "owner_id": 376395, "owner_name": "JeffSullivan (www.MyPhotoGuides.com)", "owner_url": "http://www.panoramio.com/user/376395"} +, +{"photo_id": 309190, "photo_title": "Populonia, sunset", "photo_url": "http://www.panoramio.com/photo/309190", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/309190.jpg", "longitude": 10.490313, "latitude": 42.989581, "width": 308, "height": 500, "upload_date": "05 January 2007", "owner_id": 65478, "owner_name": "Gabriele Marabotti", "owner_url": "http://www.panoramio.com/user/65478"} +, +{"photo_id": 54982, "photo_title": "Baia dos Porcos", "photo_url": "http://www.panoramio.com/photo/54982", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/54982.jpg", "longitude": -32.443485, "latitude": -3.855177, "width": 500, "height": 333, "upload_date": "30 September 2006", "owner_id": 7562, "owner_name": "Marcelo E. Salgado", "owner_url": "http://www.panoramio.com/user/7562"} +, +{"photo_id": 58316, "photo_title": "800_Schafberg03", "photo_url": "http://www.panoramio.com/photo/58316", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/58316.jpg", "longitude": 13.429413, "latitude": 47.775445, "width": 500, "height": 316, "upload_date": "07 October 2006", "owner_id": 8060, "owner_name": "Norbert MAIER", "owner_url": "http://www.panoramio.com/user/8060"} +, +{"photo_id": 423887, "photo_title": "Dunes near Zagora", "photo_url": "http://www.panoramio.com/photo/423887", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/423887.jpg", "longitude": -5.872707, "latitude": 30.280713, "width": 500, "height": 333, "upload_date": "14 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 4136144, "photo_title": "Égi jel", "photo_url": "http://www.panoramio.com/photo/4136144", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4136144.jpg", "longitude": 17.564564, "latitude": 47.633181, "width": 500, "height": 376, "upload_date": "23 August 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 6620113, "photo_title": "Winterlandschaft - Winter Scenery - Emmental", "photo_url": "http://www.panoramio.com/photo/6620113", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6620113.jpg", "longitude": 7.787676, "latitude": 47.055856, "width": 500, "height": 374, "upload_date": "22 December 2007", "owner_id": 635422, "owner_name": "♫ Swissmay", "owner_url": "http://www.panoramio.com/user/635422"} +, +{"photo_id": 2702545, "photo_title": "Church at Oia, Santorini", "photo_url": "http://www.panoramio.com/photo/2702545", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2702545.jpg", "longitude": 25.376015, "latitude": 36.461330, "width": 375, "height": 500, "upload_date": "11 June 2007", "owner_id": 555551, "owner_name": "Marilyn Whiteley", "owner_url": "http://www.panoramio.com/user/555551"} +, +{"photo_id": 416472, "photo_title": "Ice Crystal Clouds", "photo_url": "http://www.panoramio.com/photo/416472", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/416472.jpg", "longitude": -105.650969, "latitude": 40.294126, "width": 500, "height": 374, "upload_date": "13 January 2007", "owner_id": 87752, "owner_name": "Richard Ryer", "owner_url": "http://www.panoramio.com/user/87752"} +, +{"photo_id": 6080988, "photo_title": "Zion Tree (HDR)", "photo_url": "http://www.panoramio.com/photo/6080988", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/6080988.jpg", "longitude": -112.946116, "latitude": 37.213331, "width": 500, "height": 333, "upload_date": "23 November 2007", "owner_id": 17488, "owner_name": "John Gillett", "owner_url": "http://www.panoramio.com/user/17488"} +, +{"photo_id": 2321382, "photo_title": "Old Wreck at Bannack", "photo_url": "http://www.panoramio.com/photo/2321382", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/2321382.jpg", "longitude": -112.997518, "latitude": 45.162614, "width": 500, "height": 375, "upload_date": "21 May 2007", "owner_id": 71099, "owner_name": "Eve in Montana", "owner_url": "http://www.panoramio.com/user/71099"} +, +{"photo_id": 122858, "photo_title": "Antelope Canyon - Page, Arizona", "photo_url": "http://www.panoramio.com/photo/122858", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/122858.jpg", "longitude": -111.399908, "latitude": 36.887447, "width": 332, "height": 500, "upload_date": "12 December 2006", "owner_id": 20332, "owner_name": "RJ", "owner_url": "http://www.panoramio.com/user/20332"} +, +{"photo_id": 4445933, "photo_title": "Tavi alkony", "photo_url": "http://www.panoramio.com/photo/4445933", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/4445933.jpg", "longitude": 17.465172, "latitude": 47.864486, "width": 500, "height": 350, "upload_date": "06 September 2007", "owner_id": 109117, "owner_name": "Busa Péter", "owner_url": "http://www.panoramio.com/user/109117"} +, +{"photo_id": 1238515, "photo_title": "EDEN", "photo_url": "http://www.panoramio.com/photo/1238515", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/1238515.jpg", "longitude": -83.677711, "latitude": 22.661542, "width": 500, "height": 345, "upload_date": "09 March 2007", "owner_id": 232099, "owner_name": "mabut", "owner_url": "http://www.panoramio.com/user/232099"} +, +{"photo_id": 398585, "photo_title": "Near Glittertind", "photo_url": "http://www.panoramio.com/photo/398585", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/398585.jpg", "longitude": 8.489170, "latitude": 61.621820, "width": 500, "height": 333, "upload_date": "12 January 2007", "owner_id": 78506, "owner_name": "Philippe Stoop", "owner_url": "http://www.panoramio.com/user/78506"} +, +{"photo_id": 10240311, "photo_title": "two planes", "photo_url": "http://www.panoramio.com/photo/10240311", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/10240311.jpg", "longitude": 20.306683, "latitude": 49.750107, "width": 332, "height": 500, "upload_date": "15 May 2008", "owner_id": 454219, "owner_name": "Rafal Ociepka", "owner_url": "http://www.panoramio.com/user/454219"} +, +{"photo_id": 7593894, "photo_title": "æ¡‚æž—å胜百景——é‡é¾™æ²³", "photo_url": "http://www.panoramio.com/photo/7593894", "photo_file_url": "http://mw2.google.com/mw-panoramio/photos/medium/7593894.jpg", "longitude": 110.424957, "latitude": 24.781747, "width": 500, "height": 375, "upload_date": "04 February 2008", "owner_id": 161470, "owner_name": "John Su", "owner_url": "http://www.panoramio.com/user/161470"} +]} + diff --git a/webdata/mapdata/mcplus/src/index.html b/webdata/mapdata/mcplus/src/index.html new file mode 100644 index 0000000..aedcbe8 --- /dev/null +++ b/webdata/mapdata/mcplus/src/index.html @@ -0,0 +1,11 @@ +google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus/src + +

    google-maps-utility-library-v3 - Revision 473: /tags/markerclustererplus/2.1.2/markerclustererplus/src

    + +
    Google Code powered by Subversion + \ No newline at end of file diff --git a/webdata/mapdata/mcplus/src/markerclusterer.js b/webdata/mapdata/mcplus/src/markerclusterer.js new file mode 100644 index 0000000..722015a --- /dev/null +++ b/webdata/mapdata/mcplus/src/markerclusterer.js @@ -0,0 +1,1632 @@ +/** + * @name MarkerClustererPlus for Google Maps V3 + * @version 2.1.2 [May 28, 2014] + * @author Gary Little + * @fileoverview + * The library creates and manages per-zoom-level clusters for large amounts of markers. + *

    + * This is an enhanced V3 implementation of the + * V2 MarkerClusterer by Xiaoxi Wu. It is based on the + * V3 MarkerClusterer port by Luke Mahe. MarkerClustererPlus was created by Gary Little. + *

    + * v2.0 release: MarkerClustererPlus v2.0 is backward compatible with MarkerClusterer v1.0. It + * adds support for the ignoreHidden, title, batchSizeIE, + * and calculator properties as well as support for four more events. It also allows + * greater control over the styling of the text that appears on the cluster marker. The + * documentation has been significantly improved and the overall code has been simplified and + * polished. Very large numbers of markers can now be managed without causing Javascript timeout + * errors on Internet Explorer. Note that the name of the clusterclick event has been + * deprecated. The new name is click, so please change your application code now. + */ + +/** + * 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. + */ + + +/** + * @name ClusterIconStyle + * @class This class represents the object for values in the styles array passed + * to the {@link MarkerClusterer} constructor. The element in this array that is used to + * style the cluster icon is determined by calling the calculator function. + * + * @property {string} url The URL of the cluster icon image file. Required. + * @property {number} height The display height (in pixels) of the cluster icon. Required. + * @property {number} width The display width (in pixels) of the cluster icon. Required. + * @property {Array} [anchorText] The position (in pixels) from the center of the cluster icon to + * where the text label is to be centered and drawn. The format is [yoffset, xoffset] + * where yoffset increases as you go down from center and xoffset + * increases to the right of center. The default is [0, 0]. + * @property {Array} [anchorIcon] The anchor position (in pixels) of the cluster icon. This is the + * spot on the cluster icon that is to be aligned with the cluster position. The format is + * [yoffset, xoffset] where yoffset increases as you go down and + * xoffset increases to the right of the top-left corner of the icon. The default + * anchor position is the center of the cluster icon. + * @property {string} [textColor="black"] The color of the label text shown on the + * cluster icon. + * @property {number} [textSize=11] The size (in pixels) of the label text shown on the + * cluster icon. + * @property {string} [textDecoration="none"] The value of the CSS text-decoration + * property for the label text shown on the cluster icon. + * @property {string} [fontWeight="bold"] The value of the CSS font-weight + * property for the label text shown on the cluster icon. + * @property {string} [fontStyle="normal"] The value of the CSS font-style + * property for the label text shown on the cluster icon. + * @property {string} [fontFamily="Arial,sans-serif"] The value of the CSS font-family + * property for the label text shown on the cluster icon. + * @property {string} [backgroundPosition="0 0"] The position of the cluster icon image + * within the image defined by url. The format is "xpos ypos" + * (the same format as for the CSS background-position property). You must set + * this property appropriately when the image defined by url represents a sprite + * containing multiple images. Note that the position must be specified in px units. + */ +/** + * @name ClusterIconInfo + * @class This class is an object containing general information about a cluster icon. This is + * the object that a calculator function returns. + * + * @property {string} text The text of the label to be shown on the cluster icon. + * @property {number} index The index plus 1 of the element in the styles + * array to be used to style the cluster icon. + * @property {string} title The tooltip to display when the mouse moves over the cluster icon. + * If this value is undefined or "", title is set to the + * value of the title property passed to the MarkerClusterer. + */ +/** + * A cluster icon. + * + * @constructor + * @extends google.maps.OverlayView + * @param {Cluster} cluster The cluster with which the icon is to be associated. + * @param {Array} [styles] An array of {@link ClusterIconStyle} defining the cluster icons + * to use for various cluster sizes. + * @private + */ +function ClusterIcon(cluster, styles) { + cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); + + this.cluster_ = cluster; + this.className_ = cluster.getMarkerClusterer().getClusterClass(); + this.styles_ = styles; + this.center_ = null; + this.div_ = null; + this.sums_ = null; + this.visible_ = false; + + this.setMap(cluster.getMap()); // Note: this causes onAdd to be called +} + + +/** + * Adds the icon to the DOM. + */ +ClusterIcon.prototype.onAdd = function () { + var cClusterIcon = this; + var cMouseDownInCluster; + var cDraggingMapByCluster; + + this.div_ = document.createElement("div"); + this.div_.className = this.className_; + if (this.visible_) { + this.show(); + } + + this.getPanes().overlayMouseTarget.appendChild(this.div_); + + // Fix for Issue 157 + this.boundsChangedListener_ = google.maps.event.addListener(this.getMap(), "bounds_changed", function () { + cDraggingMapByCluster = cMouseDownInCluster; + }); + + google.maps.event.addDomListener(this.div_, "mousedown", function () { + cMouseDownInCluster = true; + cDraggingMapByCluster = false; + }); + + google.maps.event.addDomListener(this.div_, "click", function (e) { + cMouseDownInCluster = false; + if (!cDraggingMapByCluster) { + var theBounds; + var mz; + var mc = cClusterIcon.cluster_.getMarkerClusterer(); + /** + * This event is fired when a cluster marker is clicked. + * @name MarkerClusterer#click + * @param {Cluster} c The cluster that was clicked. + * @event + */ + google.maps.event.trigger(mc, "click", cClusterIcon.cluster_); + google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name + + // The default click handler follows. Disable it by setting + // the zoomOnClick property to false. + if (mc.getZoomOnClick()) { + // Zoom into the cluster. + mz = mc.getMaxZoom(); + theBounds = cClusterIcon.cluster_.getBounds(); + mc.getMap().fitBounds(theBounds); + // There is a fix for Issue 170 here: + setTimeout(function () { + mc.getMap().fitBounds(theBounds); + // Don't zoom beyond the max zoom level + if (mz !== null && (mc.getMap().getZoom() > mz)) { + mc.getMap().setZoom(mz + 1); + } + }, 100); + } + + // Prevent event propagation to the map: + e.cancelBubble = true; + if (e.stopPropagation) { + e.stopPropagation(); + } + } + }); + + google.maps.event.addDomListener(this.div_, "mouseover", function () { + var mc = cClusterIcon.cluster_.getMarkerClusterer(); + /** + * This event is fired when the mouse moves over a cluster marker. + * @name MarkerClusterer#mouseover + * @param {Cluster} c The cluster that the mouse moved over. + * @event + */ + google.maps.event.trigger(mc, "mouseover", cClusterIcon.cluster_); + }); + + google.maps.event.addDomListener(this.div_, "mouseout", function () { + var mc = cClusterIcon.cluster_.getMarkerClusterer(); + /** + * This event is fired when the mouse moves out of a cluster marker. + * @name MarkerClusterer#mouseout + * @param {Cluster} c The cluster that the mouse moved out of. + * @event + */ + google.maps.event.trigger(mc, "mouseout", cClusterIcon.cluster_); + }); +}; + + +/** + * Removes the icon from the DOM. + */ +ClusterIcon.prototype.onRemove = function () { + if (this.div_ && this.div_.parentNode) { + this.hide(); + google.maps.event.removeListener(this.boundsChangedListener_); + google.maps.event.clearInstanceListeners(this.div_); + this.div_.parentNode.removeChild(this.div_); + this.div_ = null; + } +}; + + +/** + * Draws the icon. + */ +ClusterIcon.prototype.draw = function () { + if (this.visible_) { + var pos = this.getPosFromLatLng_(this.center_); + this.div_.style.top = pos.y + "px"; + this.div_.style.left = pos.x + "px"; + } +}; + + +/** + * Hides the icon. + */ +ClusterIcon.prototype.hide = function () { + if (this.div_) { + this.div_.style.display = "none"; + } + this.visible_ = false; +}; + + +/** + * Positions and shows the icon. + */ +ClusterIcon.prototype.show = function () { + if (this.div_) { + var img = ""; + // NOTE: values must be specified in px units + var bp = this.backgroundPosition_.split(" "); + var spriteH = parseInt(bp[0].replace(/^\s+|\s+$/g, ""), 10); + var spriteV = parseInt(bp[1].replace(/^\s+|\s+$/g, ""), 10); + var pos = this.getPosFromLatLng_(this.center_); + this.div_.style.cssText = this.createCss(pos); + img = ""; + this.div_.innerHTML = img + "

    " + this.sums_.text + "
    "; + if (typeof this.sums_.title === "undefined" || this.sums_.title === "") { + this.div_.title = this.cluster_.getMarkerClusterer().getTitle(); + } else { + this.div_.title = this.sums_.title; + } + this.div_.style.display = ""; + } + this.visible_ = true; +}; + + +/** + * Sets the icon styles to the appropriate element in the styles array. + * + * @param {ClusterIconInfo} sums The icon label text and styles index. + */ +ClusterIcon.prototype.useStyle = function (sums) { + this.sums_ = sums; + var index = Math.max(0, sums.index - 1); + index = Math.min(this.styles_.length - 1, index); + var style = this.styles_[index]; + this.url_ = style.url; + this.height_ = style.height; + this.width_ = style.width; + this.anchorText_ = style.anchorText || [0, 0]; + this.anchorIcon_ = style.anchorIcon || [parseInt(this.height_ / 2, 10), parseInt(this.width_ / 2, 10)]; + this.textColor_ = style.textColor || "black"; + this.textSize_ = style.textSize || 11; + this.textDecoration_ = style.textDecoration || "none"; + this.fontWeight_ = style.fontWeight || "bold"; + this.fontStyle_ = style.fontStyle || "normal"; + this.fontFamily_ = style.fontFamily || "Arial,sans-serif"; + this.backgroundPosition_ = style.backgroundPosition || "0 0"; +}; + + +/** + * Sets the position at which to center the icon. + * + * @param {google.maps.LatLng} center The latlng to set as the center. + */ +ClusterIcon.prototype.setCenter = function (center) { + this.center_ = center; +}; + + +/** + * Creates the cssText style parameter based on the position of the icon. + * + * @param {google.maps.Point} pos The position of the icon. + * @return {string} The CSS style text. + */ +ClusterIcon.prototype.createCss = function (pos) { + var style = []; + style.push("cursor: pointer;"); + style.push("position: absolute; top: " + pos.y + "px; left: " + pos.x + "px;"); + style.push("width: " + this.width_ + "px; height: " + this.height_ + "px;"); + return style.join(""); +}; + + +/** + * Returns the position at which to place the DIV depending on the latlng. + * + * @param {google.maps.LatLng} latlng The position in latlng. + * @return {google.maps.Point} The position in pixels. + */ +ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) { + var pos = this.getProjection().fromLatLngToDivPixel(latlng); + pos.x -= this.anchorIcon_[1]; + pos.y -= this.anchorIcon_[0]; + pos.x = parseInt(pos.x, 10); + pos.y = parseInt(pos.y, 10); + return pos; +}; + + +/** + * Creates a single cluster that manages a group of proximate markers. + * Used internally, do not call this constructor directly. + * @constructor + * @param {MarkerClusterer} mc The MarkerClusterer object with which this + * cluster is associated. + */ +function Cluster(mc) { + this.markerClusterer_ = mc; + this.map_ = mc.getMap(); + this.gridSize_ = mc.getGridSize(); + this.minClusterSize_ = mc.getMinimumClusterSize(); + this.averageCenter_ = mc.getAverageCenter(); + this.markers_ = []; + this.center_ = null; + this.bounds_ = null; + this.clusterIcon_ = new ClusterIcon(this, mc.getStyles()); +} + + +/** + * Returns the number of markers managed by the cluster. You can call this from + * a click, mouseover, or mouseout event handler + * for the MarkerClusterer object. + * + * @return {number} The number of markers in the cluster. + */ +Cluster.prototype.getSize = function () { + return this.markers_.length; +}; + + +/** + * Returns the array of markers managed by the cluster. You can call this from + * a click, mouseover, or mouseout event handler + * for the MarkerClusterer object. + * + * @return {Array} The array of markers in the cluster. + */ +Cluster.prototype.getMarkers = function () { + return this.markers_; +}; + + +/** + * Returns the center of the cluster. You can call this from + * a click, mouseover, or mouseout event handler + * for the MarkerClusterer object. + * + * @return {google.maps.LatLng} The center of the cluster. + */ +Cluster.prototype.getCenter = function () { + return this.center_; +}; + + +/** + * Returns the map with which the cluster is associated. + * + * @return {google.maps.Map} The map. + * @ignore + */ +Cluster.prototype.getMap = function () { + return this.map_; +}; + + +/** + * Returns the MarkerClusterer object with which the cluster is associated. + * + * @return {MarkerClusterer} The associated marker clusterer. + * @ignore + */ +Cluster.prototype.getMarkerClusterer = function () { + return this.markerClusterer_; +}; + + +/** + * Returns the bounds of the cluster. + * + * @return {google.maps.LatLngBounds} the cluster bounds. + * @ignore + */ +Cluster.prototype.getBounds = function () { + var i; + var bounds = new google.maps.LatLngBounds(this.center_, this.center_); + var markers = this.getMarkers(); + for (i = 0; i < markers.length; i++) { + bounds.extend(markers[i].getPosition()); + } + return bounds; +}; + + +/** + * Removes the cluster from the map. + * + * @ignore + */ +Cluster.prototype.remove = function () { + this.clusterIcon_.setMap(null); + this.markers_ = []; + delete this.markers_; +}; + + +/** + * Adds a marker to the cluster. + * + * @param {google.maps.Marker} marker The marker to be added. + * @return {boolean} True if the marker was added. + * @ignore + */ +Cluster.prototype.addMarker = function (marker) { + var i; + var mCount; + var mz; + + if (this.isMarkerAlreadyAdded_(marker)) { + return false; + } + + if (!this.center_) { + this.center_ = marker.getPosition(); + this.calculateBounds_(); + } else { + if (this.averageCenter_) { + var l = this.markers_.length + 1; + var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l; + var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l; + this.center_ = new google.maps.LatLng(lat, lng); + this.calculateBounds_(); + } + } + + marker.isAdded = true; + this.markers_.push(marker); + + mCount = this.markers_.length; + mz = this.markerClusterer_.getMaxZoom(); + if (mz !== null && this.map_.getZoom() > mz) { + // Zoomed in past max zoom, so show the marker. + if (marker.getMap() !== this.map_) { + marker.setMap(this.map_); + } + } else if (mCount < this.minClusterSize_) { + // Min cluster size not reached so show the marker. + if (marker.getMap() !== this.map_) { + marker.setMap(this.map_); + } + } else if (mCount === this.minClusterSize_) { + // Hide the markers that were showing. + for (i = 0; i < mCount; i++) { + this.markers_[i].setMap(null); + } + } else { + marker.setMap(null); + } + + this.updateIcon_(); + return true; +}; + + +/** + * Determines if a marker lies within the cluster's bounds. + * + * @param {google.maps.Marker} marker The marker to check. + * @return {boolean} True if the marker lies in the bounds. + * @ignore + */ +Cluster.prototype.isMarkerInClusterBounds = function (marker) { + return this.bounds_.contains(marker.getPosition()); +}; + + +/** + * Calculates the extended bounds of the cluster with the grid. + */ +Cluster.prototype.calculateBounds_ = function () { + var bounds = new google.maps.LatLngBounds(this.center_, this.center_); + this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds); +}; + + +/** + * Updates the cluster icon. + */ +Cluster.prototype.updateIcon_ = function () { + var mCount = this.markers_.length; + var mz = this.markerClusterer_.getMaxZoom(); + + if (mz !== null && this.map_.getZoom() > mz) { + this.clusterIcon_.hide(); + return; + } + + if (mCount < this.minClusterSize_) { + // Min cluster size not yet reached. + this.clusterIcon_.hide(); + return; + } + + var numStyles = this.markerClusterer_.getStyles().length; + var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles); + this.clusterIcon_.setCenter(this.center_); + this.clusterIcon_.useStyle(sums); + this.clusterIcon_.show(); +}; + + +/** + * Determines if a marker has already been added to the cluster. + * + * @param {google.maps.Marker} marker The marker to check. + * @return {boolean} True if the marker has already been added. + */ +Cluster.prototype.isMarkerAlreadyAdded_ = function (marker) { + var i; + if (this.markers_.indexOf) { + return this.markers_.indexOf(marker) !== -1; + } else { + for (i = 0; i < this.markers_.length; i++) { + if (marker === this.markers_[i]) { + return true; + } + } + } + return false; +}; + + +/** + * @name MarkerClustererOptions + * @class This class represents the optional parameter passed to + * the {@link MarkerClusterer} constructor. + * @property {number} [gridSize=60] The grid size of a cluster in pixels. The grid is a square. + * @property {number} [maxZoom=null] The maximum zoom level at which clustering is enabled or + * null if clustering is to be enabled at all zoom levels. + * @property {boolean} [zoomOnClick=true] Whether to zoom the map when a cluster marker is + * clicked. You may want to set this to false if you have installed a handler + * for the click event and it deals with zooming on its own. + * @property {boolean} [averageCenter=false] Whether the position of a cluster marker should be + * the average position of all markers in the cluster. If set to false, the + * cluster marker is positioned at the location of the first marker added to the cluster. + * @property {number} [minimumClusterSize=2] The minimum number of markers needed in a cluster + * before the markers are hidden and a cluster marker appears. + * @property {boolean} [ignoreHidden=false] Whether to ignore hidden markers in clusters. You + * may want to set this to true to ensure that hidden markers are not included + * in the marker count that appears on a cluster marker (this count is the value of the + * text property of the result returned by the default calculator). + * If set to true and you change the visibility of a marker being clustered, be + * sure to also call MarkerClusterer.repaint(). + * @property {string} [title=""] The tooltip to display when the mouse moves over a cluster + * marker. (Alternatively, you can use a custom calculator function to specify a + * different tooltip for each cluster marker.) + * @property {function} [calculator=MarkerClusterer.CALCULATOR] The function used to determine + * the text to be displayed on a cluster marker and the index indicating which style to use + * for the cluster marker. The input parameters for the function are (1) the array of markers + * represented by a cluster marker and (2) the number of cluster icon styles. It returns a + * {@link ClusterIconInfo} object. The default calculator returns a + * text property which is the number of markers in the cluster and an + * index property which is one higher than the lowest integer such that + * 10^i exceeds the number of markers in the cluster, or the size of the styles + * array, whichever is less. The styles array element used has an index of + * index minus 1. For example, the default calculator returns a + * text value of "125" and an index of 3 + * for a cluster icon representing 125 markers so the element used in the styles + * array is 2. A calculator may also return a title + * property that contains the text of the tooltip to be used for the cluster marker. If + * title is not defined, the tooltip is set to the value of the title + * property for the MarkerClusterer. + * @property {string} [clusterClass="cluster"] The name of the CSS class defining general styles + * for the cluster markers. Use this class to define CSS styles that are not set up by the code + * that processes the styles array. + * @property {Array} [styles] An array of {@link ClusterIconStyle} elements defining the styles + * of the cluster markers to be used. The element to be used to style a given cluster marker + * is determined by the function defined by the calculator property. + * The default is an array of {@link ClusterIconStyle} elements whose properties are derived + * from the values for imagePath, imageExtension, and + * imageSizes. + * @property {boolean} [enableRetinaIcons=false] Whether to allow the use of cluster icons that + * have sizes that are some multiple (typically double) of their actual display size. Icons such + * as these look better when viewed on high-resolution monitors such as Apple's Retina displays. + * Note: if this property is true, sprites cannot be used as cluster icons. + * @property {number} [batchSize=MarkerClusterer.BATCH_SIZE] Set this property to the + * number of markers to be processed in a single batch when using a browser other than + * Internet Explorer (for Internet Explorer, use the batchSizeIE property instead). + * @property {number} [batchSizeIE=MarkerClusterer.BATCH_SIZE_IE] When Internet Explorer is + * being used, markers are processed in several batches with a small delay inserted between + * each batch in an attempt to avoid Javascript timeout errors. Set this property to the + * number of markers to be processed in a single batch; select as high a number as you can + * without causing a timeout error in the browser. This number might need to be as low as 100 + * if 15,000 markers are being managed, for example. + * @property {string} [imagePath=MarkerClusterer.IMAGE_PATH] + * The full URL of the root name of the group of image files to use for cluster icons. + * The complete file name is of the form imagePathn.imageExtension + * where n is the image file number (1, 2, etc.). + * @property {string} [imageExtension=MarkerClusterer.IMAGE_EXTENSION] + * The extension name for the cluster icon image files (e.g., "png" or + * "jpg"). + * @property {Array} [imageSizes=MarkerClusterer.IMAGE_SIZES] + * An array of numbers containing the widths of the group of + * imagePathn.imageExtension image files. + * (The images are assumed to be square.) + */ +/** + * Creates a MarkerClusterer object with the options specified in {@link MarkerClustererOptions}. + * @constructor + * @extends google.maps.OverlayView + * @param {google.maps.Map} map The Google map to attach to. + * @param {Array.} [opt_markers] The markers to be added to the cluster. + * @param {MarkerClustererOptions} [opt_options] The optional parameters. + */ +function MarkerClusterer(map, opt_markers, opt_options) { + // MarkerClusterer implements google.maps.OverlayView interface. We use the + // extend function to extend MarkerClusterer with google.maps.OverlayView + // because it might not always be available when the code is defined so we + // look for it at the last possible moment. If it doesn't exist now then + // there is no point going ahead :) + this.extend(MarkerClusterer, google.maps.OverlayView); + + opt_markers = opt_markers || []; + opt_options = opt_options || {}; + + this.markers_ = []; + this.clusters_ = []; + this.listeners_ = []; + this.activeMap_ = null; + this.ready_ = false; + + this.gridSize_ = opt_options.gridSize || 60; + this.minClusterSize_ = opt_options.minimumClusterSize || 2; + this.maxZoom_ = opt_options.maxZoom || null; + this.styles_ = opt_options.styles || []; + this.title_ = opt_options.title || ""; + this.zoomOnClick_ = true; + if (opt_options.zoomOnClick !== undefined) { + this.zoomOnClick_ = opt_options.zoomOnClick; + } + this.averageCenter_ = false; + if (opt_options.averageCenter !== undefined) { + this.averageCenter_ = opt_options.averageCenter; + } + this.ignoreHidden_ = false; + if (opt_options.ignoreHidden !== undefined) { + this.ignoreHidden_ = opt_options.ignoreHidden; + } + this.enableRetinaIcons_ = false; + if (opt_options.enableRetinaIcons !== undefined) { + this.enableRetinaIcons_ = opt_options.enableRetinaIcons; + } + this.imagePath_ = opt_options.imagePath || MarkerClusterer.IMAGE_PATH; + this.imageExtension_ = opt_options.imageExtension || MarkerClusterer.IMAGE_EXTENSION; + this.imageSizes_ = opt_options.imageSizes || MarkerClusterer.IMAGE_SIZES; + this.calculator_ = opt_options.calculator || MarkerClusterer.CALCULATOR; + this.batchSize_ = opt_options.batchSize || MarkerClusterer.BATCH_SIZE; + this.batchSizeIE_ = opt_options.batchSizeIE || MarkerClusterer.BATCH_SIZE_IE; + this.clusterClass_ = opt_options.clusterClass || "cluster"; + + if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1) { + // Try to avoid IE timeout when processing a huge number of markers: + this.batchSize_ = this.batchSizeIE_; + } + + this.setupStyles_(); + + this.addMarkers(opt_markers, true); + this.setMap(map); // Note: this causes onAdd to be called +} + + +/** + * Implementation of the onAdd interface method. + * @ignore + */ +MarkerClusterer.prototype.onAdd = function () { + var cMarkerClusterer = this; + + this.activeMap_ = this.getMap(); + this.ready_ = true; + + this.repaint(); + + // Add the map event listeners + this.listeners_ = [ + google.maps.event.addListener(this.getMap(), "zoom_changed", function () { + cMarkerClusterer.resetViewport_(false); + // Workaround for this Google bug: when map is at level 0 and "-" of + // zoom slider is clicked, a "zoom_changed" event is fired even though + // the map doesn't zoom out any further. In this situation, no "idle" + // event is triggered so the cluster markers that have been removed + // do not get redrawn. Same goes for a zoom in at maxZoom. + if (this.getZoom() === (this.get("minZoom") || 0) || this.getZoom() === this.get("maxZoom")) { + google.maps.event.trigger(this, "idle"); + } + }), + google.maps.event.addListener(this.getMap(), "idle", function () { + cMarkerClusterer.redraw_(); + }) + ]; +}; + + +/** + * Implementation of the onRemove interface method. + * Removes map event listeners and all cluster icons from the DOM. + * All managed markers are also put back on the map. + * @ignore + */ +MarkerClusterer.prototype.onRemove = function () { + var i; + + // Put all the managed markers back on the map: + for (i = 0; i < this.markers_.length; i++) { + if (this.markers_[i].getMap() !== this.activeMap_) { + this.markers_[i].setMap(this.activeMap_); + } + } + + // Remove all clusters: + for (i = 0; i < this.clusters_.length; i++) { + this.clusters_[i].remove(); + } + this.clusters_ = []; + + // Remove map event listeners: + for (i = 0; i < this.listeners_.length; i++) { + google.maps.event.removeListener(this.listeners_[i]); + } + this.listeners_ = []; + + this.activeMap_ = null; + this.ready_ = false; +}; + + +/** + * Implementation of the draw interface method. + * @ignore + */ +MarkerClusterer.prototype.draw = function () {}; + + +/** + * Sets up the styles object. + */ +MarkerClusterer.prototype.setupStyles_ = function () { + var i, size; + if (this.styles_.length > 0) { + return; + } + + for (i = 0; i < this.imageSizes_.length; i++) { + size = this.imageSizes_[i]; + this.styles_.push({ + url: this.imagePath_ + (i + 1) + "." + this.imageExtension_, + height: size, + width: size + }); + } +}; + + +/** + * Fits the map to the bounds of the markers managed by the clusterer. + */ +MarkerClusterer.prototype.fitMapToMarkers = function () { + var i; + var markers = this.getMarkers(); + var bounds = new google.maps.LatLngBounds(); + for (i = 0; i < markers.length; i++) { + bounds.extend(markers[i].getPosition()); + } + + this.getMap().fitBounds(bounds); +}; + + +/** + * Returns the value of the gridSize property. + * + * @return {number} The grid size. + */ +MarkerClusterer.prototype.getGridSize = function () { + return this.gridSize_; +}; + + +/** + * Sets the value of the gridSize property. + * + * @param {number} gridSize The grid size. + */ +MarkerClusterer.prototype.setGridSize = function (gridSize) { + this.gridSize_ = gridSize; +}; + + +/** + * Returns the value of the minimumClusterSize property. + * + * @return {number} The minimum cluster size. + */ +MarkerClusterer.prototype.getMinimumClusterSize = function () { + return this.minClusterSize_; +}; + +/** + * Sets the value of the minimumClusterSize property. + * + * @param {number} minimumClusterSize The minimum cluster size. + */ +MarkerClusterer.prototype.setMinimumClusterSize = function (minimumClusterSize) { + this.minClusterSize_ = minimumClusterSize; +}; + + +/** + * Returns the value of the maxZoom property. + * + * @return {number} The maximum zoom level. + */ +MarkerClusterer.prototype.getMaxZoom = function () { + return this.maxZoom_; +}; + + +/** + * Sets the value of the maxZoom property. + * + * @param {number} maxZoom The maximum zoom level. + */ +MarkerClusterer.prototype.setMaxZoom = function (maxZoom) { + this.maxZoom_ = maxZoom; +}; + + +/** + * Returns the value of the styles property. + * + * @return {Array} The array of styles defining the cluster markers to be used. + */ +MarkerClusterer.prototype.getStyles = function () { + return this.styles_; +}; + + +/** + * Sets the value of the styles property. + * + * @param {Array.} styles The array of styles to use. + */ +MarkerClusterer.prototype.setStyles = function (styles) { + this.styles_ = styles; +}; + + +/** + * Returns the value of the title property. + * + * @return {string} The content of the title text. + */ +MarkerClusterer.prototype.getTitle = function () { + return this.title_; +}; + + +/** + * Sets the value of the title property. + * + * @param {string} title The value of the title property. + */ +MarkerClusterer.prototype.setTitle = function (title) { + this.title_ = title; +}; + + +/** + * Returns the value of the zoomOnClick property. + * + * @return {boolean} True if zoomOnClick property is set. + */ +MarkerClusterer.prototype.getZoomOnClick = function () { + return this.zoomOnClick_; +}; + + +/** + * Sets the value of the zoomOnClick property. + * + * @param {boolean} zoomOnClick The value of the zoomOnClick property. + */ +MarkerClusterer.prototype.setZoomOnClick = function (zoomOnClick) { + this.zoomOnClick_ = zoomOnClick; +}; + + +/** + * Returns the value of the averageCenter property. + * + * @return {boolean} True if averageCenter property is set. + */ +MarkerClusterer.prototype.getAverageCenter = function () { + return this.averageCenter_; +}; + + +/** + * Sets the value of the averageCenter property. + * + * @param {boolean} averageCenter The value of the averageCenter property. + */ +MarkerClusterer.prototype.setAverageCenter = function (averageCenter) { + this.averageCenter_ = averageCenter; +}; + + +/** + * Returns the value of the ignoreHidden property. + * + * @return {boolean} True if ignoreHidden property is set. + */ +MarkerClusterer.prototype.getIgnoreHidden = function () { + return this.ignoreHidden_; +}; + + +/** + * Sets the value of the ignoreHidden property. + * + * @param {boolean} ignoreHidden The value of the ignoreHidden property. + */ +MarkerClusterer.prototype.setIgnoreHidden = function (ignoreHidden) { + this.ignoreHidden_ = ignoreHidden; +}; + + +/** + * Returns the value of the enableRetinaIcons property. + * + * @return {boolean} True if enableRetinaIcons property is set. + */ +MarkerClusterer.prototype.getEnableRetinaIcons = function () { + return this.enableRetinaIcons_; +}; + + +/** + * Sets the value of the enableRetinaIcons property. + * + * @param {boolean} enableRetinaIcons The value of the enableRetinaIcons property. + */ +MarkerClusterer.prototype.setEnableRetinaIcons = function (enableRetinaIcons) { + this.enableRetinaIcons_ = enableRetinaIcons; +}; + + +/** + * Returns the value of the imageExtension property. + * + * @return {string} The value of the imageExtension property. + */ +MarkerClusterer.prototype.getImageExtension = function () { + return this.imageExtension_; +}; + + +/** + * Sets the value of the imageExtension property. + * + * @param {string} imageExtension The value of the imageExtension property. + */ +MarkerClusterer.prototype.setImageExtension = function (imageExtension) { + this.imageExtension_ = imageExtension; +}; + + +/** + * Returns the value of the imagePath property. + * + * @return {string} The value of the imagePath property. + */ +MarkerClusterer.prototype.getImagePath = function () { + return this.imagePath_; +}; + + +/** + * Sets the value of the imagePath property. + * + * @param {string} imagePath The value of the imagePath property. + */ +MarkerClusterer.prototype.setImagePath = function (imagePath) { + this.imagePath_ = imagePath; +}; + + +/** + * Returns the value of the imageSizes property. + * + * @return {Array} The value of the imageSizes property. + */ +MarkerClusterer.prototype.getImageSizes = function () { + return this.imageSizes_; +}; + + +/** + * Sets the value of the imageSizes property. + * + * @param {Array} imageSizes The value of the imageSizes property. + */ +MarkerClusterer.prototype.setImageSizes = function (imageSizes) { + this.imageSizes_ = imageSizes; +}; + + +/** + * Returns the value of the calculator property. + * + * @return {function} the value of the calculator property. + */ +MarkerClusterer.prototype.getCalculator = function () { + return this.calculator_; +}; + + +/** + * Sets the value of the calculator property. + * + * @param {function(Array., number)} calculator The value + * of the calculator property. + */ +MarkerClusterer.prototype.setCalculator = function (calculator) { + this.calculator_ = calculator; +}; + + +/** + * Returns the value of the batchSizeIE property. + * + * @return {number} the value of the batchSizeIE property. + */ +MarkerClusterer.prototype.getBatchSizeIE = function () { + return this.batchSizeIE_; +}; + + +/** + * Sets the value of the batchSizeIE property. + * + * @param {number} batchSizeIE The value of the batchSizeIE property. + */ +MarkerClusterer.prototype.setBatchSizeIE = function (batchSizeIE) { + this.batchSizeIE_ = batchSizeIE; +}; + + +/** + * Returns the value of the clusterClass property. + * + * @return {string} the value of the clusterClass property. + */ +MarkerClusterer.prototype.getClusterClass = function () { + return this.clusterClass_; +}; + + +/** + * Sets the value of the clusterClass property. + * + * @param {string} clusterClass The value of the clusterClass property. + */ +MarkerClusterer.prototype.setClusterClass = function (clusterClass) { + this.clusterClass_ = clusterClass; +}; + + +/** + * Returns the array of markers managed by the clusterer. + * + * @return {Array} The array of markers managed by the clusterer. + */ +MarkerClusterer.prototype.getMarkers = function () { + return this.markers_; +}; + + +/** + * Returns the number of markers managed by the clusterer. + * + * @return {number} The number of markers. + */ +MarkerClusterer.prototype.getTotalMarkers = function () { + return this.markers_.length; +}; + + +/** + * Returns the current array of clusters formed by the clusterer. + * + * @return {Array} The array of clusters formed by the clusterer. + */ +MarkerClusterer.prototype.getClusters = function () { + return this.clusters_; +}; + + +/** + * Returns the number of clusters formed by the clusterer. + * + * @return {number} The number of clusters formed by the clusterer. + */ +MarkerClusterer.prototype.getTotalClusters = function () { + return this.clusters_.length; +}; + + +/** + * Adds a marker to the clusterer. The clusters are redrawn unless + * opt_nodraw is set to true. + * + * @param {google.maps.Marker} marker The marker to add. + * @param {boolean} [opt_nodraw] Set to true to prevent redrawing. + */ +MarkerClusterer.prototype.addMarker = function (marker, opt_nodraw) { + this.pushMarkerTo_(marker); + if (!opt_nodraw) { + this.redraw_(); + } +}; + + +/** + * Adds an array of markers to the clusterer. The clusters are redrawn unless + * opt_nodraw is set to true. + * + * @param {Array.} markers The markers to add. + * @param {boolean} [opt_nodraw] Set to true to prevent redrawing. + */ +MarkerClusterer.prototype.addMarkers = function (markers, opt_nodraw) { + var key; + for (key in markers) { + if (markers.hasOwnProperty(key)) { + this.pushMarkerTo_(markers[key]); + } + } + if (!opt_nodraw) { + this.redraw_(); + } +}; + + +/** + * Pushes a marker to the clusterer. + * + * @param {google.maps.Marker} marker The marker to add. + */ +MarkerClusterer.prototype.pushMarkerTo_ = function (marker) { + // If the marker is draggable add a listener so we can update the clusters on the dragend: + if (marker.getDraggable()) { + var cMarkerClusterer = this; + google.maps.event.addListener(marker, "dragend", function () { + if (cMarkerClusterer.ready_) { + this.isAdded = false; + cMarkerClusterer.repaint(); + } + }); + } + marker.isAdded = false; + this.markers_.push(marker); +}; + + +/** + * Removes a marker from the cluster. The clusters are redrawn unless + * opt_nodraw is set to true. Returns true if the + * marker was removed from the clusterer. + * + * @param {google.maps.Marker} marker The marker to remove. + * @param {boolean} [opt_nodraw] Set to true to prevent redrawing. + * @return {boolean} True if the marker was removed from the clusterer. + */ +MarkerClusterer.prototype.removeMarker = function (marker, opt_nodraw) { + var removed = this.removeMarker_(marker); + + if (!opt_nodraw && removed) { + this.repaint(); + } + + return removed; +}; + + +/** + * Removes an array of markers from the cluster. The clusters are redrawn unless + * opt_nodraw is set to true. Returns true if markers + * were removed from the clusterer. + * + * @param {Array.} markers The markers to remove. + * @param {boolean} [opt_nodraw] Set to true to prevent redrawing. + * @return {boolean} True if markers were removed from the clusterer. + */ +MarkerClusterer.prototype.removeMarkers = function (markers, opt_nodraw) { + var i, r; + var removed = false; + + for (i = 0; i < markers.length; i++) { + r = this.removeMarker_(markers[i]); + removed = removed || r; + } + + if (!opt_nodraw && removed) { + this.repaint(); + } + + return removed; +}; + + +/** + * Removes a marker and returns true if removed, false if not. + * + * @param {google.maps.Marker} marker The marker to remove + * @return {boolean} Whether the marker was removed or not + */ +MarkerClusterer.prototype.removeMarker_ = function (marker) { + var i; + var index = -1; + if (this.markers_.indexOf) { + index = this.markers_.indexOf(marker); + } else { + for (i = 0; i < this.markers_.length; i++) { + if (marker === this.markers_[i]) { + index = i; + break; + } + } + } + + if (index === -1) { + // Marker is not in our list of markers, so do nothing: + return false; + } + + marker.setMap(null); + this.markers_.splice(index, 1); // Remove the marker from the list of managed markers + return true; +}; + + +/** + * Removes all clusters and markers from the map and also removes all markers + * managed by the clusterer. + */ +MarkerClusterer.prototype.clearMarkers = function () { + this.resetViewport_(true); + this.markers_ = []; +}; + + +/** + * Recalculates and redraws all the marker clusters from scratch. + * Call this after changing any properties. + */ +MarkerClusterer.prototype.repaint = function () { + var oldClusters = this.clusters_.slice(); + this.clusters_ = []; + this.resetViewport_(false); + this.redraw_(); + + // Remove the old clusters. + // Do it in a timeout to prevent blinking effect. + setTimeout(function () { + var i; + for (i = 0; i < oldClusters.length; i++) { + oldClusters[i].remove(); + } + }, 0); +}; + + +/** + * Returns the current bounds extended by the grid size. + * + * @param {google.maps.LatLngBounds} bounds The bounds to extend. + * @return {google.maps.LatLngBounds} The extended bounds. + * @ignore + */ +MarkerClusterer.prototype.getExtendedBounds = function (bounds) { + var projection = this.getProjection(); + + // Turn the bounds into latlng. + var tr = new google.maps.LatLng(bounds.getNorthEast().lat(), + bounds.getNorthEast().lng()); + var bl = new google.maps.LatLng(bounds.getSouthWest().lat(), + bounds.getSouthWest().lng()); + + // Convert the points to pixels and the extend out by the grid size. + var trPix = projection.fromLatLngToDivPixel(tr); + trPix.x += this.gridSize_; + trPix.y -= this.gridSize_; + + var blPix = projection.fromLatLngToDivPixel(bl); + blPix.x -= this.gridSize_; + blPix.y += this.gridSize_; + + // Convert the pixel points back to LatLng + var ne = projection.fromDivPixelToLatLng(trPix); + var sw = projection.fromDivPixelToLatLng(blPix); + + // Extend the bounds to contain the new bounds. + bounds.extend(ne); + bounds.extend(sw); + + return bounds; +}; + + +/** + * Redraws all the clusters. + */ +MarkerClusterer.prototype.redraw_ = function () { + this.createClusters_(0); +}; + + +/** + * Removes all clusters from the map. The markers are also removed from the map + * if opt_hide is set to true. + * + * @param {boolean} [opt_hide] Set to true to also remove the markers + * from the map. + */ +MarkerClusterer.prototype.resetViewport_ = function (opt_hide) { + var i, marker; + // Remove all the clusters + for (i = 0; i < this.clusters_.length; i++) { + this.clusters_[i].remove(); + } + this.clusters_ = []; + + // Reset the markers to not be added and to be removed from the map. + for (i = 0; i < this.markers_.length; i++) { + marker = this.markers_[i]; + marker.isAdded = false; + if (opt_hide) { + marker.setMap(null); + } + } +}; + + +/** + * Calculates the distance between two latlng locations in km. + * + * @param {google.maps.LatLng} p1 The first lat lng point. + * @param {google.maps.LatLng} p2 The second lat lng point. + * @return {number} The distance between the two points in km. + * @see http://www.movable-type.co.uk/scripts/latlong.html +*/ +MarkerClusterer.prototype.distanceBetweenPoints_ = function (p1, p2) { + var R = 6371; // Radius of the Earth in km + var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; + var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; + var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var d = R * c; + return d; +}; + + +/** + * Determines if a marker is contained in a bounds. + * + * @param {google.maps.Marker} marker The marker to check. + * @param {google.maps.LatLngBounds} bounds The bounds to check against. + * @return {boolean} True if the marker is in the bounds. + */ +MarkerClusterer.prototype.isMarkerInBounds_ = function (marker, bounds) { + return bounds.contains(marker.getPosition()); +}; + + +/** + * Adds a marker to a cluster, or creates a new cluster. + * + * @param {google.maps.Marker} marker The marker to add. + */ +MarkerClusterer.prototype.addToClosestCluster_ = function (marker) { + var i, d, cluster, center; + var distance = 40000; // Some large number + var clusterToAddTo = null; + for (i = 0; i < this.clusters_.length; i++) { + cluster = this.clusters_[i]; + center = cluster.getCenter(); + if (center) { + d = this.distanceBetweenPoints_(center, marker.getPosition()); + if (d < distance) { + distance = d; + clusterToAddTo = cluster; + } + } + } + + if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) { + clusterToAddTo.addMarker(marker); + } else { + cluster = new Cluster(this); + cluster.addMarker(marker); + this.clusters_.push(cluster); + } +}; + + +/** + * Creates the clusters. This is done in batches to avoid timeout errors + * in some browsers when there is a huge number of markers. + * + * @param {number} iFirst The index of the first marker in the batch of + * markers to be added to clusters. + */ +MarkerClusterer.prototype.createClusters_ = function (iFirst) { + var i, marker; + var mapBounds; + var cMarkerClusterer = this; + if (!this.ready_) { + return; + } + + // Cancel previous batch processing if we're working on the first batch: + if (iFirst === 0) { + /** + * This event is fired when the MarkerClusterer begins + * clustering markers. + * @name MarkerClusterer#clusteringbegin + * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered. + * @event + */ + google.maps.event.trigger(this, "clusteringbegin", this); + + if (typeof this.timerRefStatic !== "undefined") { + clearTimeout(this.timerRefStatic); + delete this.timerRefStatic; + } + } + + // Get our current map view bounds. + // Create a new bounds object so we don't affect the map. + // + // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug: + if (this.getMap().getZoom() > 3) { + mapBounds = new google.maps.LatLngBounds(this.getMap().getBounds().getSouthWest(), + this.getMap().getBounds().getNorthEast()); + } else { + mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625)); + } + var bounds = this.getExtendedBounds(mapBounds); + + var iLast = Math.min(iFirst + this.batchSize_, this.markers_.length); + + for (i = iFirst; i < iLast; i++) { + marker = this.markers_[i]; + if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) { + if (!this.ignoreHidden_ || (this.ignoreHidden_ && marker.getVisible())) { + this.addToClosestCluster_(marker); + } + } + } + + if (iLast < this.markers_.length) { + this.timerRefStatic = setTimeout(function () { + cMarkerClusterer.createClusters_(iLast); + }, 0); + } else { + delete this.timerRefStatic; + + /** + * This event is fired when the MarkerClusterer stops + * clustering markers. + * @name MarkerClusterer#clusteringend + * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered. + * @event + */ + google.maps.event.trigger(this, "clusteringend", this); + } +}; + + +/** + * Extends an object's prototype by another's. + * + * @param {Object} obj1 The object to be extended. + * @param {Object} obj2 The object to extend with. + * @return {Object} The new extended object. + * @ignore + */ +MarkerClusterer.prototype.extend = function (obj1, obj2) { + return (function (object) { + var property; + for (property in object.prototype) { + this.prototype[property] = object.prototype[property]; + } + return this; + }).apply(obj1, [obj2]); +}; + + +/** + * The default function for determining the label text and style + * for a cluster icon. + * + * @param {Array.} markers The array of markers represented by the cluster. + * @param {number} numStyles The number of marker styles available. + * @return {ClusterIconInfo} The information resource for the cluster. + * @constant + * @ignore + */ +MarkerClusterer.CALCULATOR = function (markers, numStyles) { + var index = 0; + var title = ""; + var count = markers.length.toString(); + + var dv = count; + while (dv !== 0) { + dv = parseInt(dv / 10, 10); + index++; + } + + index = Math.min(index, numStyles); + return { + text: count, + index: index, + title: title + }; +}; + + +/** + * The number of markers to process in one batch. + * + * @type {number} + * @constant + */ +MarkerClusterer.BATCH_SIZE = 2000; + + +/** + * The number of markers to process in one batch (IE only). + * + * @type {number} + * @constant + */ +MarkerClusterer.BATCH_SIZE_IE = 500; + + +/** + * The default root name for the marker cluster images. + * + * @type {string} + * @constant + */ +MarkerClusterer.IMAGE_PATH = "http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m"; + + +/** + * The default extension name for the marker cluster images. + * + * @type {string} + * @constant + */ +MarkerClusterer.IMAGE_EXTENSION = "png"; + + +/** + * The default array of sizes for the marker cluster images. + * + * @type {Array.} + * @constant + */ +MarkerClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90]; diff --git a/webdata/mapdata/mcplus/src/markerclusterer_packed.js b/webdata/mapdata/mcplus/src/markerclusterer_packed.js new file mode 100644 index 0000000..7b0501d --- /dev/null +++ b/webdata/mapdata/mcplus/src/markerclusterer_packed.js @@ -0,0 +1 @@ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 G(b,a){b.N().14(G,o.n.31);4.H=b;4.2B=b.N().2q();4.M=a;4.C=u;4.q=u;4.16=u;4.1i=t;4.L(b.w())}G.6.2C=5(){7 d=4;7 g;7 f;4.q=3x.3r("1Z");4.q.5n=4.2B;9(4.1i){4.29()}4.4L().4D.4x(4.q);4.2W=o.n.v.1M(4.w(),"49",5(){f=g});o.n.v.1G(4.q,"3Z",5(){g=I;f=t});o.n.v.1G(4.q,"2L",5(e){g=t;9(!f){7 c;7 b;7 a=d.H.N();o.n.v.12(a,"2L",d.H);o.n.v.12(a,"3T",d.H);9(a.2z()){b=a.1s();c=d.H.1B();a.w().1O(c);1P(5(){a.w().1O(c);9(b!==u&&(a.w().15()>b)){a.w().3C(b+1)}},3w)}e.3t=I;9(e.2g){e.2g()}}});o.n.v.1G(4.q,"2f",5(){7 a=d.H.N();o.n.v.12(a,"2f",d.H)});o.n.v.1G(4.q,"2e",5(){7 a=d.H.N();o.n.v.12(a,"2e",d.H)})};G.6.2Q=5(){9(4.q&&4.q.3h){4.1N();o.n.v.2S(4.2W);o.n.v.55(4.q);4.q.3h.4X(4.q);4.q=u}};G.6.38=5(){9(4.1i){7 a=4.26(4.C);4.q.S.1L=a.y+"B";4.q.S.1I=a.x+"B"}};G.6.1N=5(){9(4.q){4.q.S.3a="2V"}4.1i=t};G.6.29=5(){9(4.q){7 e="";7 c=4.3e.4h(" ");7 b=Y(c[0].3f(/^\\s+|\\s+$/g,""),10);7 d=Y(c[1].3f(/^\\s+|\\s+$/g,""),10);7 a=4.26(4.C);4.q.S.3Y=4.2O(a);e="<3X 3W=\'"+4.2K+"\' S=\'1X: 1W; 1L: "+d+"B; 1I: "+b+"B; ";9(!4.H.N().1d){e+="3V: 3U("+(-1*d)+"B, "+((-1*b)+4.1h)+"B, "+((-1*d)+4.1m)+"B, "+(-1*b)+"B);"}e+="\'>";4.q.3S=e+"<1Z S=\'"+"1X: 1W;"+"1L: "+4.1V[0]+"B;"+"1I: "+4.1V[1]+"B;"+"3P: "+4.2F+";"+"1y-1o: "+4.2v+"B;"+"1y-3J: "+4.2s+";"+"1y-3H: "+4.2p+";"+"1y-S: "+4.2n+";"+"1x-3D: "+4.2l+";"+"1x-3A: 1c;"+"1C: "+4.1h+"B;"+"3v-1A:"+4.1m+"B;"+"\'>"+4.16.1x+"";9(2i 4.16.13==="1a"||4.16.13===""){4.q.13=4.H.N().2U()}K{4.q.13=4.16.13}4.q.S.3a=""}4.1i=I};G.6.2M=5(a){4.16=a;7 b=z.3l(0,a.2R-1);b=z.21(4.M.p-1,b);7 c=4.M[b];4.2K=c.3g;4.1m=c.1A;4.1h=c.1C;4.1V=c.5i||[0,0];4.2d=c.5c||[Y(4.1m/2,10),Y(4.1h/2,10)];4.2F=c.54||"4Z";4.2v=c.4W||11;4.2l=c.4Q||"2V";4.2p=c.4N||"4K";4.2n=c.4H||"4F";4.2s=c.4E||"4C,4B-4z";4.3e=c.4y||"0 0"};G.6.30=5(a){4.C=a};G.6.2O=5(b){7 a=[];a.Z("4v: 4t;");a.Z("1X: 1W; 1L: "+b.y+"B; 1I: "+b.x+"B;");a.Z("1C: "+4.1h+"B; 1A: "+4.1m+"B;");j a.4s("")};G.6.26=5(b){7 a=4.39().28(b);a.x-=4.2d[1];a.y-=4.2d[0];a.x=Y(a.x,10);a.y=Y(a.y,10);j a};5 D(a){4.V=a;4.T=a.w();4.U=a.2T();4.X=a.3d();4.19=a.3c();4.k=[];4.C=u;4.2c=u;4.W=F G(4,a.20())}D.6.41=5(){j 4.k.p};D.6.1D=5(){j 4.k};D.6.2P=5(){j 4.C};D.6.w=5(){j 4.T};D.6.N=5(){j 4.V};D.6.1B=5(){7 i;7 b=F o.n.1l(4.C,4.C);7 a=4.1D();A(i=0;ib){9(e.w()!==4.T){e.L(4.T)}}K 9(c<4.X){9(e.w()!==4.T){e.L(4.T)}}K 9(c===4.X){A(i=0;ia){4.W.1N();j}9(c<4.X){4.W.1N();j}7 b=4.V.20().p;7 d=4.V.2G()(4.k,b);4.W.30(4.C);4.W.2M(d);4.W.29()};D.6.2X=5(a){7 i;9(4.k.1g){j 4.k.1g(a)!==-1}K{A(i=0;i<4.k.p;i++){9(a===4.k[i]){j I}}}j t};5 8(a,c,b){4.14(8,o.n.31);c=c||[];b=b||{};4.k=[];4.E=[];4.1r=[];4.1f=u;4.1b=t;4.U=b.3R||3Q;4.X=b.3N||2;4.1U=b.2y||u;4.M=b.3K||[];4.1T=b.13||"";4.1v=I;9(b.2x!==1a){4.1v=b.2x}4.19=t;9(b.2w!==1a){4.19=b.2w}4.18=t;9(b.2u!==1a){4.18=b.2u}4.1d=t;9(b.2t!==1a){4.1d=b.2t}4.1t=b.3I||8.2r;4.1u=b.3G||8.2o;4.1e=b.3F||8.2j;4.1S=b.3E||8.2m;4.1Q=b.3B||8.2E;4.1z=b.3z||8.2k;4.1R=b.3y||"O";9(3L.3M.3u().1g("3O")!==-1){4.1Q=4.1z}4.2D();4.2A(c,I);4.L(a)}8.6.2C=5(){7 a=4;4.1f=4.w();4.1b=I;4.1q();4.1r=[o.n.v.1M(4.w(),"3s",5(){a.1w(t);9(4.15()===(4.2h("3q")||0)||4.15()===4.2h("2y")){o.n.v.12(4,"2N")}}),o.n.v.1M(4.w(),"2N",5(){a.1k()})]};8.6.2Q=5(){7 i;A(i=0;i<4.k.p;i++){9(4.k[i].w()!==4.1f){4.k[i].L(4.1f)}}A(i=0;i<4.E.p;i++){4.E[i].1F()}4.E=[];A(i=0;i<4.1r.p;i++){o.n.v.2S(4.1r[i])}4.1r=[];4.1f=u;4.1b=t};8.6.38=5(){};8.6.2D=5(){7 i,1o;9(4.M.p>0){j}A(i=0;i<4.1e.p;i++){1o=4.1e[i];4.M.Z({3g:4.1t+(i+1)+"."+4.1u,1A:1o,1C:1o})}};8.6.3p=5(){7 i;7 a=4.1D();7 b=F o.n.1l();A(i=0;i3){d=F o.n.1l(4.w().1B().22(),4.w().1B().25())}K{d=F o.n.1l(F o.n.1p(2Y.4r,-37.4q),F o.n.1p(-2Y.4p,37.4o))}7 a=4.2a(d);7 b=z.21(e+4.1Q,4.k.p);A(i=e;i + + + + + + + Traffic Mapping + "; + } + ?> + + + + + +
    +

    LiquidWeb Traffic Monitoring

    +

    Source IP Address Mapping

    + +
    +
    +

    YOU MUST SELECT A SERVICE TO VIEW DATA!

    +

    Plotted on the map are the GeoLocated Coordinates of every Source IP from the last 15 Minutes for the selected service.

    + + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +

    + +

    +

    + For which service would you like to see data? +
    + +
    + +
    +

    +
    +
    +
    + + (UNIX_TIMESTAMP() - 900) GROUP BY src_ip"; + $iplist = mysqli_query($conn1, $query1); + + echo "Now Viewing data for Destination port: $varPort"; + + //Initialize your first couple variables + $encodedString = ""; //This is the string that will hold all your location data + $x = 0; //This is a trigger to keep the string tidy + + + //Multiple rows are returned + while ($row = mysqli_fetch_array($iplist)) + { + $ip = $row['src_ip']; + $location = $geoip->lookupLocation($ip); + $varDestLink = "List"; + //This is to keep an empty first or last line from forming, when the string is split + if ( $x == 0 ) + { + $separator = ""; + } + else + { + //Each row in the database is separated in the string by four *'s + $separator = "****"; + } + //Saving to the String, each variable is separated by three &'s + $encodedString = $encodedString.$separator. + "

    IP: ".$row['src_ip']. + "
    Destinations: ".$varDestLink. + //"
    Lat: ".$location->latitude. + //"
    Long: ".$location->longitude. + "

    &&&".$location->latitude."&&&".$location->longitude; + $x = $x + 1; + } + $conn1->close(); + ?> + +
    +
    + + + diff --git a/webdata/search.php b/webdata/search.php new file mode 100644 index 0000000..179e729 --- /dev/null +++ b/webdata/search.php @@ -0,0 +1,98 @@ + + + + + Traffic Search + + +
    +

    LiquidWeb Traffic Monitoring

    +

    Source IP Search

    + +
    +
    +

    Data displayed here is from the last 7 days, and is updated every 5 minutes.

    + + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> + +
    +

    + Please enter the Source IP address for which you wish to search: +
    + +
    + For which service would you like to see data? +
    + +
    + +

    +
    + + connect_error) { + die("Connection Failed: " . $conn2->connect_error); + } + + //Query + + $sql = "SELECT src_ip, COUNT(DISTINCT(dst_ip)), COUNT(src_ip) FROM `rawdata` WHERE `src_ip` = '".$varIP."' AND `dst_port` = '".$varPort."'"; + + $result = $conn2->query($sql); + //If there are results, display them in a table + if ($result->num_rows >0) { + echo "Now viewing data for IP: $varIP for Destination Port: $varPort"; + echo ""; + + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
    Source IP# of targets# of connectionsSource WhoisDestination IPs
    ".$row["src_ip"]."".$row["COUNT(DISTINCT(dst_ip))"]."".$row["COUNT(src_ip)"]."WhoisList
    "; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
    + + diff --git a/webdata/sourceips.php b/webdata/sourceips.php new file mode 100644 index 0000000..732c9db --- /dev/null +++ b/webdata/sourceips.php @@ -0,0 +1,98 @@ + + + + + Traffic Sources + + +
    +

    LiquidWeb Traffic Monitoring

    +

    Source IPs by Destination

    + +
    +
    +

    Data displayed here is from the last 7 days, and is updated every 5 minutes.

    + + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +
    +

    + + Please enter the traffic Destination IP address for which you wish to search: +
    + +
    + For which service would you like to see data? +
    + +
    + +

    +
    + + connect_error) { + die("Connection Failed: " . $conn2->connect_error); + } + + //Query + + $sql = "SELECT src_ip, dst_ip FROM `rawdata` WHERE `dst_ip` = '".$varIP."' AND `dst_port` = '".$varPort."' AND time > (UNIX_TIMESTAMP() - 86400) GROUP BY src_ip ORDER BY src_ip;"; + + $result = $conn2->query($sql); + //If there are results of the query, display them. + if ($result->num_rows >0) { + echo "Now viewing data for Destination Port: $varPort"; + echo ""; + + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
    Destination IP: $varIP Netblock
    Source IPsWhois
    ".$row["src_ip"]."Whois
    "; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
    + + diff --git a/webdata/topdestinations.php b/webdata/topdestinations.php new file mode 100644 index 0000000..1243f5c --- /dev/null +++ b/webdata/topdestinations.php @@ -0,0 +1,94 @@ + + + + + Traffic Monitoring + "; + } + ?> + + +
    +

    LiquidWeb Traffic Monitoring

    +

    Top Destination IPs

    + +
    +
    +

    Busiest Internal IPs by number of inbound connections

    +

    YOU MUST SELECT A SERVICE TO VIEW DATA!

    +

    Data displayed here is from the last 30 minutes, and is updated every 5 minutes.

    + + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +

    + +

    +

    + For which service would you like to see data? +
    + +
    + +

    +
    + + (UNIX_TIMESTAMP() - 1800) GROUP BY dst_ip ORDER BY COUNT(DISTINCT(src_ip)) DESC LIMIT 50"; + + $result = $conn2->query($sql); + //If there are results, display them in a table + if ($result->num_rows >0) { + echo "Now viewing data for Destination Port $varPort"; + echo "
    "; + echo ""; + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
    Destination IP# of sources# of connectionsDestination NetblockSource IPs
    ".$row["dst_ip"]."".$row["COUNT(DISTINCT(src_ip))"]."".$row["COUNT(dst_ip)"]."NetblockList
    "; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
    + + diff --git a/webdata/topsources.php b/webdata/topsources.php new file mode 100644 index 0000000..8a6cc65 --- /dev/null +++ b/webdata/topsources.php @@ -0,0 +1,93 @@ + + + + + Traffic Monitoring + "; + } + ?> + + +
    +

    LiquidWeb Traffic Monitoring

    +

    Top Source IPs

    + +
    +
    +

    YOU MUST SELECT A SERVICE TO VIEW DATA!

    +

    Data displayed here is from the last 30 minutes, and is updated every 5 minutes.

    + + $id - $name"; + } + + //Check Connection + if ($conn->connect_error) { + die("Connection Failed: " . $conn->connect_error); + } + $conn->close(); + ?> +

    + +

    +

    + For which service would you like to see data? +
    + +
    + +

    +
    + + (UNIX_TIMESTAMP() - 1800) GROUP BY src_ip ORDER BY COUNT(DISTINCT(dst_ip)) DESC LIMIT 50"; + + $result = $conn2->query($sql); + //If there are results, display them in a table + if ($result->num_rows >0) { + echo "Now viewing data for Destination Port $varPort"; + echo "
    "; + echo ""; + while ($row = $result->fetch_assoc()) { + echo ""; + } + echo "
    Source IP# of targets# of connectionsSource WhoisDestination IPs
    ".$row["src_ip"]."".$row["COUNT(DISTINCT(dst_ip))"]."".$row["COUNT(src_ip)"]."WhoisList
    "; + } else { + echo "No Results, something is likely broken."; + } + $conn2->close(); + ?> +
    + + diff --git a/webdata/wallboard/30min24hr.php b/webdata/wallboard/30min24hr.php new file mode 100644 index 0000000..aa28676 --- /dev/null +++ b/webdata/wallboard/30min24hr.php @@ -0,0 +1,70 @@ + DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 24 HOUR) ORDER BY time"; //table name +$Result = mysql_query($Requete, $db); + +/*This fetches the data from the mysql database, and adds it to pchart as points*/ +while($row = mysql_fetch_array($Result)) +{ + //$Sample_Number = $row["Sample_Number"]; //Not using this data + //$myData->addPoints($Sample_Number,"Sample_Number"); + + $Time = $row["time"]; + $myData->addPoints($Time,"time"); + + $Amt = $row["amount"]; + $myData->addPoints($Amt,"amount"); + + // $Type = $row["type"]; + // $myData->addPoints($Type,"type"); +} + +$myData-> setSerieOnAxis("amount", 0); //assigns the data to the frist axis +$myData-> setAxisName(0, "# of Connections"); //adds the label to the first axis + +//$myData-> setSerieOnAxis("type", 1); +//$myData-> setAxisName(1, "Service"); + +$myData-> setAxisPosition(1,AXIS_POSITION_LEFT); //moves the second axis to the far left + +$myData->setAbscissa("time"); //sets the time data set as the x axis label + + +$myPicture = new pImage(900,320,$myData); /* Create a pChart object and associate your dataset */ +$rectsettings = array("R"=>40, "G"=>40, "B"=>40, "Dash"=>1, "DashR"=>80, "DashG"=>80, "DashB"=>80); +$myPicture->drawFilledRectangle(0,0,900,320,$rectsettings); +$myPicture->setFontProperties(array("FontName"=>"../graph/pchart/fonts/verdana.ttf","FontSize"=>8, "R"=>248, "G"=>248, "B"=>248)); /* Choose a nice font */ + +$myPicture->setGraphArea(60,20,850,200); /* Define the boundaries of the graph area */ + +$Settings = array("R"=>40, "G"=>40, "B"=>40, "Dash"=>1, "DashR"=>255, "DashG"=>255, "DashB"=>255); + +$myPicture->drawScale(array("LabelRotation"=>295)); /* Draw the scale, keep everything automatic */ +$myPicture->drawFilledRectangle(60,20,850,200,array("R"=>46,"G"=>46,"B"=>46,"Surrounding"=>-200,"Alpha"=>10)); +/*The combination makes a cool looking graph*/ +$myPicture->drawPlotChart(); +$myPicture->drawLineChart(); + + +//$myPicture->drawLegend(90,20); //adds the legend + +$myPicture->autoOutput(); /* Build the PNG file and send it to the web browser */ + +?> diff --git a/webdata/wallboard/graphs.php b/webdata/wallboard/graphs.php new file mode 100644 index 0000000..608a990 --- /dev/null +++ b/webdata/wallboard/graphs.php @@ -0,0 +1,27 @@ + + + + + Wallboard Graphs + + + + +

    Service Connection Totals Every 30 minutes, for the Past 24 Hours.

    + +
    +

    HTTP

    + +
    +

    HTTPS

    + +
    +
    +

    SSH

    + +
    +

    SMTP

    + +
    + + diff --git a/webdata/wallboard/map.php b/webdata/wallboard/map.php new file mode 100644 index 0000000..a796ba0 --- /dev/null +++ b/webdata/wallboard/map.php @@ -0,0 +1,151 @@ + + + + + + + + Wallboard Map + "; + } + ?> + + + + + + + (UNIX_TIMESTAMP() - 900) GROUP BY src_ip"; + $iplist = mysqli_query($conn1, $query1); + + echo "

    Locations of the Unique Source IP addresses for incoming traffic on Port $varPort from the last 15 minutes

    "; + + //Initialize your first couple variables + $encodedString = ""; //This is the string that will hold all your location data + $x = 0; //This is a trigger to keep the string tidy + + + //Multiple rows are returned + while ($row = mysqli_fetch_array($iplist)) + { + $ip = $row['src_ip']; + $location = $geoip->lookupLocation($ip); + //This is to keep an empty first or last line from forming, when the string is split + if ( $x == 0 ) + { + $separator = ""; + } + else + { + //Each row in the database is separated in the string by four *'s + $separator = "****"; + } + //Saving to the String, each variable is separated by three &'s + $encodedString = $encodedString.$separator. + "

    IP: ".$row['src_ip']. + "
    Lat: ".$location->latitude. + "
    Long: ".$location->longitude. + "

    &&&".$location->latitude."&&&".$location->longitude; + $x = $x + 1; + } + $conn1->close(); + ?> + +
    + +
    + + diff --git a/webdata/whoislookup.php b/webdata/whoislookup.php new file mode 100644 index 0000000..ff91f4e --- /dev/null +++ b/webdata/whoislookup.php @@ -0,0 +1,43 @@ + + + + + WhoIS Lookup + + +
    +

    LiquidWeb Traffic Monitoring

    +

    IP WhoIs Lookup

    + +
    +
    + +
    +

    + Please enter the IP address for which you wish to search: +
    + +
    + +

    +
    +
    +
    + query($varIPaddr); + //Display the results + echo "
    ".$result."
    "; + } + else + //If nothing is entered, send error message + echo "Please enter an IP Address" + ?> +
    + +