| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,265 @@ | ||
| /* ----------------------------------------------------------------------- | ||
| Blueprint CSS Framework 1.0 | ||
| http://blueprintcss.org | ||
| * Copyright (c) 2007-Present. See LICENSE for more info. | ||
| * See README for instructions on how to use Blueprint. | ||
| * For credits and origins, see AUTHORS. | ||
| * This is a compressed file. See the sources in the 'src' directory. | ||
| ----------------------------------------------------------------------- */ | ||
|
|
||
| /* reset.css */ | ||
| html {margin:0;padding:0;border:0;} | ||
| body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} | ||
| article, aside, dialog, figure, footer, header, hgroup, nav, section {display:block;} | ||
| body {line-height:1.5;background:white;} | ||
| table {border-collapse:separate;border-spacing:0;} | ||
| caption, th, td {text-align:left;font-weight:normal;float:none !important;} | ||
| table, th, td {vertical-align:middle;} | ||
| blockquote:before, blockquote:after, q:before, q:after {content:'';} | ||
| blockquote, q {quotes:"" "";} | ||
| a img {border:none;} | ||
| :focus {outline:0;} | ||
|
|
||
| /* typography.css */ | ||
| html {font-size:100.01%;} | ||
| body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} | ||
| h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} | ||
| h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} | ||
| h2 {font-size:2em;margin-bottom:0.75em;} | ||
| h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} | ||
| h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} | ||
| h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} | ||
| h6 {font-size:1em;font-weight:bold;} | ||
| h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} | ||
| p {margin:0 0 1.5em;} | ||
| .left {float:left !important;} | ||
| p .left {margin:1.5em 1.5em 1.5em 0;padding:0;} | ||
| .right {float:right !important;} | ||
| p .right {margin:1.5em 0 1.5em 1.5em;padding:0;} | ||
| a:focus, a:hover {color:#09f;} | ||
| a {color:#06c;text-decoration:underline;} | ||
| blockquote {margin:1.5em;color:#666;font-style:italic;} | ||
| strong, dfn {font-weight:bold;} | ||
| em, dfn {font-style:italic;} | ||
| sup, sub {line-height:0;} | ||
| abbr, acronym {border-bottom:1px dotted #666;} | ||
| address {margin:0 0 1.5em;font-style:italic;} | ||
| del {color:#666;} | ||
| pre {margin:1.5em 0;white-space:pre;} | ||
| pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} | ||
| li ul, li ol {margin:0;} | ||
| ul, ol {margin:0 1.5em 1.5em 0;padding-left:1.5em;} | ||
| ul {list-style-type:disc;} | ||
| ol {list-style-type:decimal;} | ||
| dl {margin:0 0 1.5em 0;} | ||
| dl dt {font-weight:bold;} | ||
| dd {margin-left:1.5em;} | ||
| table {margin-bottom:1.4em;width:100%;} | ||
| th {font-weight:bold;} | ||
| thead th {background:#c3d9ff;} | ||
| th, td, caption {padding:4px 10px 4px 5px;} | ||
| tbody tr:nth-child(even) td, tbody tr.even td {background:#e5ecf9;} | ||
| tfoot {font-style:italic;} | ||
| caption {background:#eee;} | ||
| .small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} | ||
| .large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} | ||
| .hide {display:none;} | ||
| .quiet {color:#666;} | ||
| .loud {color:#000;} | ||
| .highlight {background:#ff0;} | ||
| .added {background:#060;color:#fff;} | ||
| .removed {background:#900;color:#fff;} | ||
| .first {margin-left:0;padding-left:0;} | ||
| .last {margin-right:0;padding-right:0;} | ||
| .top {margin-top:0;padding-top:0;} | ||
| .bottom {margin-bottom:0;padding-bottom:0;} | ||
|
|
||
| /* forms.css */ | ||
| label {font-weight:bold;} | ||
| fieldset {padding:0 1.4em 1.4em 1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;} | ||
| legend {font-weight:bold;font-size:1.2em;margin-top:-0.2em;margin-bottom:1em;} | ||
| fieldset, #IE8#HACK {padding-top:1.4em;} | ||
| legend, #IE8#HACK {margin-top:0;margin-bottom:0;} | ||
| input[type=text], input[type=password], input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;} | ||
| input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus {border-color:#666;} | ||
| select {background-color:#fff;border-width:1px;border-style:solid;} | ||
| input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;} | ||
| input.text, input.title {width:300px;padding:5px;} | ||
| input.title {font-size:1.5em;} | ||
| textarea {width:390px;height:250px;padding:5px;} | ||
| form.inline {line-height:3;} | ||
| form.inline p {margin-bottom:0;} | ||
| .error, .alert, .notice, .success, .info {padding:0.8em;margin-bottom:1em;border:2px solid #ddd;} | ||
| .error, .alert {background:#fbe3e4;color:#8a1f11;border-color:#fbc2c4;} | ||
| .notice {background:#fff6bf;color:#514721;border-color:#ffd324;} | ||
| .success {background:#e6efc2;color:#264409;border-color:#c6d880;} | ||
| .info {background:#d5edf8;color:#205791;border-color:#92cae4;} | ||
| .error a, .alert a {color:#8a1f11;} | ||
| .notice a {color:#514721;} | ||
| .success a {color:#264409;} | ||
| .info a {color:#205791;} | ||
|
|
||
| /* grid.css */ | ||
| .container {width:595px;margin:0 auto;} | ||
| .showgrid {background:url(src/grid.png);} | ||
| .column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:5px;} | ||
| .last {margin-right:0;} | ||
| .span-1 {width:20px;} | ||
| .span-2 {width:45px;} | ||
| .span-3 {width:70px;} | ||
| .span-4 {width:95px;} | ||
| .span-5 {width:120px;} | ||
| .span-6 {width:145px;} | ||
| .span-7 {width:170px;} | ||
| .span-8 {width:195px;} | ||
| .span-9 {width:220px;} | ||
| .span-10 {width:245px;} | ||
| .span-11 {width:270px;} | ||
| .span-12 {width:295px;} | ||
| .span-13 {width:320px;} | ||
| .span-14 {width:345px;} | ||
| .span-15 {width:370px;} | ||
| .span-16 {width:395px;} | ||
| .span-17 {width:420px;} | ||
| .span-18 {width:445px;} | ||
| .span-19 {width:470px;} | ||
| .span-20 {width:495px;} | ||
| .span-21 {width:520px;} | ||
| .span-22 {width:545px;} | ||
| .span-23 {width:570px;} | ||
| .span-24 {width:595px;margin-right:0;} | ||
| input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;} | ||
| input.span-1, textarea.span-1 {width:8px;} | ||
| input.span-2, textarea.span-2 {width:33px;} | ||
| input.span-3, textarea.span-3 {width:58px;} | ||
| input.span-4, textarea.span-4 {width:83px;} | ||
| input.span-5, textarea.span-5 {width:108px;} | ||
| input.span-6, textarea.span-6 {width:133px;} | ||
| input.span-7, textarea.span-7 {width:158px;} | ||
| input.span-8, textarea.span-8 {width:183px;} | ||
| input.span-9, textarea.span-9 {width:208px;} | ||
| input.span-10, textarea.span-10 {width:233px;} | ||
| input.span-11, textarea.span-11 {width:258px;} | ||
| input.span-12, textarea.span-12 {width:283px;} | ||
| input.span-13, textarea.span-13 {width:308px;} | ||
| input.span-14, textarea.span-14 {width:333px;} | ||
| input.span-15, textarea.span-15 {width:358px;} | ||
| input.span-16, textarea.span-16 {width:383px;} | ||
| input.span-17, textarea.span-17 {width:408px;} | ||
| input.span-18, textarea.span-18 {width:433px;} | ||
| input.span-19, textarea.span-19 {width:458px;} | ||
| input.span-20, textarea.span-20 {width:483px;} | ||
| input.span-21, textarea.span-21 {width:508px;} | ||
| input.span-22, textarea.span-22 {width:533px;} | ||
| input.span-23, textarea.span-23 {width:558px;} | ||
| input.span-24, textarea.span-24 {width:583px;} | ||
| .append-1 {padding-right:25px;} | ||
| .append-2 {padding-right:50px;} | ||
| .append-3 {padding-right:75px;} | ||
| .append-4 {padding-right:100px;} | ||
| .append-5 {padding-right:125px;} | ||
| .append-6 {padding-right:150px;} | ||
| .append-7 {padding-right:175px;} | ||
| .append-8 {padding-right:200px;} | ||
| .append-9 {padding-right:225px;} | ||
| .append-10 {padding-right:250px;} | ||
| .append-11 {padding-right:275px;} | ||
| .append-12 {padding-right:300px;} | ||
| .append-13 {padding-right:325px;} | ||
| .append-14 {padding-right:350px;} | ||
| .append-15 {padding-right:375px;} | ||
| .append-16 {padding-right:400px;} | ||
| .append-17 {padding-right:425px;} | ||
| .append-18 {padding-right:450px;} | ||
| .append-19 {padding-right:475px;} | ||
| .append-20 {padding-right:500px;} | ||
| .append-21 {padding-right:525px;} | ||
| .append-22 {padding-right:550px;} | ||
| .append-23 {padding-right:575px;} | ||
| .prepend-1 {padding-left:25px;} | ||
| .prepend-2 {padding-left:50px;} | ||
| .prepend-3 {padding-left:75px;} | ||
| .prepend-4 {padding-left:100px;} | ||
| .prepend-5 {padding-left:125px;} | ||
| .prepend-6 {padding-left:150px;} | ||
| .prepend-7 {padding-left:175px;} | ||
| .prepend-8 {padding-left:200px;} | ||
| .prepend-9 {padding-left:225px;} | ||
| .prepend-10 {padding-left:250px;} | ||
| .prepend-11 {padding-left:275px;} | ||
| .prepend-12 {padding-left:300px;} | ||
| .prepend-13 {padding-left:325px;} | ||
| .prepend-14 {padding-left:350px;} | ||
| .prepend-15 {padding-left:375px;} | ||
| .prepend-16 {padding-left:400px;} | ||
| .prepend-17 {padding-left:425px;} | ||
| .prepend-18 {padding-left:450px;} | ||
| .prepend-19 {padding-left:475px;} | ||
| .prepend-20 {padding-left:500px;} | ||
| .prepend-21 {padding-left:525px;} | ||
| .prepend-22 {padding-left:550px;} | ||
| .prepend-23 {padding-left:575px;} | ||
| .border {padding-right:1px;margin-right:2px;border-right:1px solid #ddd;} | ||
| .colborder {padding-right:14px;margin-right:15px;border-right:1px solid #ddd;} | ||
| .pull-1 {margin-left:-25px;} | ||
| .pull-2 {margin-left:-50px;} | ||
| .pull-3 {margin-left:-75px;} | ||
| .pull-4 {margin-left:-100px;} | ||
| .pull-5 {margin-left:-125px;} | ||
| .pull-6 {margin-left:-150px;} | ||
| .pull-7 {margin-left:-175px;} | ||
| .pull-8 {margin-left:-200px;} | ||
| .pull-9 {margin-left:-225px;} | ||
| .pull-10 {margin-left:-250px;} | ||
| .pull-11 {margin-left:-275px;} | ||
| .pull-12 {margin-left:-300px;} | ||
| .pull-13 {margin-left:-325px;} | ||
| .pull-14 {margin-left:-350px;} | ||
| .pull-15 {margin-left:-375px;} | ||
| .pull-16 {margin-left:-400px;} | ||
| .pull-17 {margin-left:-425px;} | ||
| .pull-18 {margin-left:-450px;} | ||
| .pull-19 {margin-left:-475px;} | ||
| .pull-20 {margin-left:-500px;} | ||
| .pull-21 {margin-left:-525px;} | ||
| .pull-22 {margin-left:-550px;} | ||
| .pull-23 {margin-left:-575px;} | ||
| .pull-24 {margin-left:-600px;} | ||
| .pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;} | ||
| .push-1 {margin:0 -25px 1.5em 25px;} | ||
| .push-2 {margin:0 -50px 1.5em 50px;} | ||
| .push-3 {margin:0 -75px 1.5em 75px;} | ||
| .push-4 {margin:0 -100px 1.5em 100px;} | ||
| .push-5 {margin:0 -125px 1.5em 125px;} | ||
| .push-6 {margin:0 -150px 1.5em 150px;} | ||
| .push-7 {margin:0 -175px 1.5em 175px;} | ||
| .push-8 {margin:0 -200px 1.5em 200px;} | ||
| .push-9 {margin:0 -225px 1.5em 225px;} | ||
| .push-10 {margin:0 -250px 1.5em 250px;} | ||
| .push-11 {margin:0 -275px 1.5em 275px;} | ||
| .push-12 {margin:0 -300px 1.5em 300px;} | ||
| .push-13 {margin:0 -325px 1.5em 325px;} | ||
| .push-14 {margin:0 -350px 1.5em 350px;} | ||
| .push-15 {margin:0 -375px 1.5em 375px;} | ||
| .push-16 {margin:0 -400px 1.5em 400px;} | ||
| .push-17 {margin:0 -425px 1.5em 425px;} | ||
| .push-18 {margin:0 -450px 1.5em 450px;} | ||
| .push-19 {margin:0 -475px 1.5em 475px;} | ||
| .push-20 {margin:0 -500px 1.5em 500px;} | ||
| .push-21 {margin:0 -525px 1.5em 525px;} | ||
| .push-22 {margin:0 -550px 1.5em 550px;} | ||
| .push-23 {margin:0 -575px 1.5em 575px;} | ||
| .push-24 {margin:0 -600px 1.5em 600px;} | ||
| .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:left;position:relative;} | ||
| div.prepend-top, .prepend-top {margin-top:1.5em;} | ||
| div.append-bottom, .append-bottom {margin-bottom:1.5em;} | ||
| .box {padding:1.5em;margin-bottom:1.5em;background:#e5eCf9;} | ||
| hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:1px;margin:0 0 1.45em;border:none;} | ||
| hr.space {background:#fff;color:#fff;visibility:hidden;} | ||
| .clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} | ||
| .clearfix, .container {display:block;} | ||
| .clear {clear:both;} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| FILE(GLOB HTML_FILES *.*) | ||
|
|
||
| INSTALL(FILES ${HTML_FILES} DESTINATION ${QGIS_DATA_DIR}/resources/html) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | ||
| <html> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.js"></script> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.flot.js"></script> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.flot.navigate.js"></script> | ||
| </head> | ||
| <body> | ||
| <div id="chart"><h1>Histogram loading...</h1></div> | ||
| <script id="source" language="javascript" type="text/javascript"> | ||
| var d = new Array(); | ||
| function replot() | ||
| { | ||
| var options = { series : | ||
| { | ||
| points : { show : false }, | ||
| lines : { show : true }, | ||
| }, | ||
| yaxis : { zoomRange: null, panRange: null }, | ||
| xaxis : { zoomRange: null, panRange: null }, | ||
| zoom : { interactive : true }, | ||
| pan : { interactive : true }, | ||
| legend : { show : true } | ||
| }; | ||
| $.plot($("#chart"), d, options); | ||
| } | ||
| function addSeries( theSeries, theBand, theColor ) | ||
| { | ||
| d.push( { data: theSeries, label: "Band " + theBand, color: theColor } ); | ||
| replot(); | ||
| //alert( theSeries ); | ||
| } | ||
| $(function () | ||
| { | ||
| $("#chart").height(0.9*$(window).height()).width(0.90*$(window).width()).css("margin-left","auto").css("margin-right", "auto"); | ||
|
|
||
| }); | ||
| </script> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | ||
| <html> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | ||
| <!-- custom blueprint see http://ianli.com/blueprinter/?cw=20&gw=5&cc=24 --> | ||
| <link rel="stylesheet" href="../css/screen.css" type="text/css" media="screen, projection" /> | ||
| <link rel="stylesheet" href="../css/print.css" type="text/css" media="print" /> | ||
| <link rel="stylesheet" href="../css/qgisdoc.css" type="text/css" /> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.js"></script> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.flot.js"></script> | ||
| <script language="javascript" type="text/javascript" src="../js/jquery.flot.navigate.js"></script> | ||
| <script language="javascript" type="text/javascript" src="../js/json.js"></script> | ||
| <script id="source" language="javascript" type="text/javascript"> | ||
| //The raster layer properties dialog will pass an object 'mRasterLayer' | ||
| //to this javascript context which you can interrogate for all its metadata | ||
| //and invoke any of its slots | ||
| function showJson() | ||
| { | ||
| if (typeof mRasterLayer === 'undefined') | ||
| { | ||
| $("#notes").html("mRasterLayer is undefined"); | ||
| } | ||
| else | ||
| { | ||
| //for fun lets pickle the raster layer as a json object | ||
| //$("#notes").html(JSON.stringify(mRasterLayer)); | ||
| //also you can use any slots as native jscript methods: | ||
| $("#scale-range").hide().html("Minumum Scale: " + mRasterLayer.minimumScale() + " to Maximum Scale: " + mRasterLayer.maximumScale() ).slideToggle(); | ||
| } | ||
|
|
||
| } | ||
| /** Load the metadata object passed into this page from c++ context using | ||
| wvMetadata->page()->mainFrame()->addToJavaScriptWindowObject( "mRasterLayer", mRasterLayer ); | ||
| wvMetadata->page()->mainFrame()->evaluateJavaScript(QString("setMetadata()")); | ||
| */ | ||
| function setMetadata( ) | ||
| { | ||
| $("#metadata").html( mRasterLayer["metadata"] ); | ||
| } | ||
| </script> | ||
| </head> | ||
| <body> | ||
| <div class="container"> | ||
| <h1>Metadata</h1> | ||
| <hr/> | ||
| <div id="metadata" class="span-24"></div> | ||
| </hr> | ||
| <div id="footer">Generated by Quantum GIS (http://qgis.org)</div> | ||
| <div id="scale-range" class="span-24"></div> | ||
| <div id="notes" class="span-24"></div> | ||
| <button onclick="showJson()" >Show scale range</button> | ||
| </div> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| FILE(GLOB JS_FILES *.*) | ||
|
|
||
| INSTALL(FILES ${JS_FILES} DESTINATION ${QGIS_DATA_DIR}/resources/js) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| Frequently asked questions | ||
| -------------------------- | ||
|
|
||
| Q: How much data can Flot cope with? | ||
|
|
||
| A: Flot will happily draw everything you send to it so the answer | ||
| depends on the browser. The excanvas emulation used for IE (built with | ||
| VML) makes IE by far the slowest browser so be sure to test with that | ||
| if IE users are in your target group. | ||
|
|
||
| 1000 points is not a problem, but as soon as you start having more | ||
| points than the pixel width, you should probably start thinking about | ||
| downsampling/aggregation as this is near the resolution limit of the | ||
| chart anyway. If you downsample server-side, you also save bandwidth. | ||
|
|
||
|
|
||
| Q: Flot isn't working when I'm using JSON data as source! | ||
|
|
||
| A: Actually, Flot loves JSON data, you just got the format wrong. | ||
| Double check that you're not inputting strings instead of numbers, | ||
| like [["0", "-2.13"], ["5", "4.3"]]. This is most common mistake, and | ||
| the error might not show up immediately because Javascript can do some | ||
| conversion automatically. | ||
|
|
||
|
|
||
| Q: Can I export the graph? | ||
|
|
||
| A: This is a limitation of the canvas technology. There's a hook in | ||
| the canvas object for getting an image out, but you won't get the tick | ||
| labels. And it's not likely to be supported by IE. At this point, your | ||
| best bet is probably taking a screenshot, e.g. with PrtScn. | ||
|
|
||
|
|
||
| Q: The bars are all tiny in time mode? | ||
|
|
||
| A: It's not really possible to determine the bar width automatically. | ||
| So you have to set the width with the barWidth option which is NOT in | ||
| pixels, but in the units of the x axis (or the y axis for horizontal | ||
| bars). For time mode that's milliseconds so the default value of 1 | ||
| makes the bars 1 millisecond wide. | ||
|
|
||
|
|
||
| Q: Can I use Flot with libraries like Mootools or Prototype? | ||
|
|
||
| A: Yes, Flot supports it out of the box and it's easy! Just use jQuery | ||
| instead of $, e.g. call jQuery.plot instead of $.plot and use | ||
| jQuery(something) instead of $(something). As a convenience, you can | ||
| put in a DOM element for the graph placeholder where the examples and | ||
| the API documentation are using jQuery objects. | ||
|
|
||
| Depending on how you include jQuery, you may have to add one line of | ||
| code to prevent jQuery from overwriting functions from the other | ||
| libraries, see the documentation in jQuery ("Using jQuery with other | ||
| libraries") for details. | ||
|
|
||
|
|
||
| Q: Flot doesn't work with [insert name of Javascript UI framework]! | ||
|
|
||
| A: The only non-standard thing used by Flot is the canvas tag; | ||
| otherwise it is simply a series of absolute positioned divs within the | ||
| placeholder tag you put in. If this is not working, it's probably | ||
| because the framework you're using is doing something weird with the | ||
| DOM, or you're using it the wrong way. | ||
|
|
||
| A common problem is that there's display:none on a container until the | ||
| user does something. Many tab widgets work this way, and there's | ||
| nothing wrong with it - you just can't call Flot inside a display:none | ||
| container as explained in the README so you need to hold off the Flot | ||
| call until the container is actually displayed (or use | ||
| visibility:hidden instead of display:none or move the container | ||
| off-screen). | ||
|
|
||
| If you find there's a specific thing we can do to Flot to help, feel | ||
| free to submit a bug report. Otherwise, you're welcome to ask for help | ||
| on the forum/mailing list, but please don't submit a bug report to | ||
| Flot. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| Copyright (c) 2007-2009 IOLA and Ole Laursen | ||
|
|
||
| Permission is hereby granted, free of charge, to any person | ||
| obtaining a copy of this software and associated documentation | ||
| files (the "Software"), to deal in the Software without | ||
| restriction, including without limitation the rights to use, | ||
| copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the | ||
| Software is furnished to do so, subject to the following | ||
| conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be | ||
| included in all copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| OTHER DEALINGS IN THE SOFTWARE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| Writing plugins | ||
| --------------- | ||
|
|
||
| All you need to do to make a new plugin is creating an init function | ||
| and a set of options (if needed), stuffing it into an object and | ||
| putting it in the $.plot.plugins array. For example: | ||
|
|
||
| function myCoolPluginInit(plot) { | ||
| plot.coolstring = "Hello!"; | ||
| }; | ||
|
|
||
| $.plot.plugins.push({ init: myCoolPluginInit, options: { ... } }); | ||
|
|
||
| // if $.plot is called, it will return a plot object with the | ||
| // attribute "coolstring" | ||
|
|
||
| Now, given that the plugin might run in many different places, it's | ||
| a good idea to avoid leaking names. The usual trick here is wrap the | ||
| above lines in an anonymous function which is called immediately, like | ||
| this: (function () { inner code ... })(). To make it even more robust | ||
| in case $ is not bound to jQuery but some other Javascript library, we | ||
| can write it as | ||
|
|
||
| (function ($) { | ||
| // plugin definition | ||
| // ... | ||
| })(jQuery); | ||
|
|
||
| There's a complete example below, but you should also check out the | ||
| plugins bundled with Flot. | ||
|
|
||
|
|
||
| Complete example | ||
| ---------------- | ||
|
|
||
| Here is a simple debug plugin which alerts each of the series in the | ||
| plot. It has a single option that control whether it is enabled and | ||
| how much info to output: | ||
|
|
||
| (function ($) { | ||
| function init(plot) { | ||
| var debugLevel = 1; | ||
|
|
||
| function checkDebugEnabled(plot, options) { | ||
| if (options.debug) { | ||
| debugLevel = options.debug; | ||
|
|
||
| plot.hooks.processDatapoints.push(alertSeries); | ||
| } | ||
| } | ||
|
|
||
| function alertSeries(plot, series, datapoints) { | ||
| var msg = "series " + series.label; | ||
| if (debugLevel > 1) | ||
| msg += " with " + series.data.length + " points"; | ||
| alert(msg); | ||
| } | ||
|
|
||
| plot.hooks.processOptions.push(checkDebugEnabled); | ||
| } | ||
|
|
||
| var options = { debug: 0 }; | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: "simpledebug", | ||
| version: "0.1" | ||
| }); | ||
| })(jQuery); | ||
|
|
||
| We also define "name" and "version". It's not used by Flot, but might | ||
| be helpful for other plugins in resolving dependencies. | ||
|
|
||
| Put the above in a file named "jquery.flot.debug.js", include it in an | ||
| HTML page and then it can be used with: | ||
|
|
||
| $.plot($("#placeholder"), [...], { debug: 2 }); | ||
|
|
||
| This simple plugin illustrates a couple of points: | ||
|
|
||
| - It uses the anonymous function trick to avoid name pollution. | ||
| - It can be enabled/disabled through an option. | ||
| - Variables in the init function can be used to store plot-specific | ||
| state between the hooks. | ||
|
|
||
| The two last points are important because there may be multiple plots | ||
| on the same page, and you'd want to make sure they are not mixed up. | ||
|
|
||
|
|
||
| Shutting down a plugin | ||
| ---------------------- | ||
|
|
||
| Each plot object has a shutdown hook which is run when plot.shutdown() | ||
| is called. This usually mostly happens in case another plot is made on | ||
| top of an existing one. | ||
|
|
||
| The purpose of the hook is to give you a chance to unbind any event | ||
| handlers you've registered and remove any extra DOM things you've | ||
| inserted. | ||
|
|
||
| The problem with event handlers is that you can have registered a | ||
| handler which is run in some point in the future, e.g. with | ||
| setTimeout(). Meanwhile, the plot may have been shutdown and removed, | ||
| but because your event handler is still referencing it, it can't be | ||
| garbage collected yet, and worse, if your handler eventually runs, it | ||
| may overwrite stuff on a completely different plot. | ||
|
|
||
|
|
||
| Some hints on the options | ||
| ------------------------- | ||
|
|
||
| Plugins should always support appropriate options to enable/disable | ||
| them because the plugin user may have several plots on the same page | ||
| where only one should use the plugin. In most cases it's probably a | ||
| good idea if the plugin is turned off rather than on per default, just | ||
| like most of the powerful features in Flot. | ||
|
|
||
| If the plugin needs options that are specific to each series, like the | ||
| points or lines options in core Flot, you can put them in "series" in | ||
| the options object, e.g. | ||
|
|
||
| var options = { | ||
| series: { | ||
| downsample: { | ||
| algorithm: null, | ||
| maxpoints: 1000 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Then they will be copied by Flot into each series, providing default | ||
| values in case none are specified. | ||
|
|
||
| Think hard and long about naming the options. These names are going to | ||
| be public API, and code is going to depend on them if the plugin is | ||
| successful. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| About | ||
| ----- | ||
|
|
||
| Flot is a Javascript plotting library for jQuery. Read more at the | ||
| website: | ||
|
|
||
| http://code.google.com/p/flot/ | ||
|
|
||
| Take a look at the examples linked from above, they should give a good | ||
| impression of what Flot can do and the source code of the examples is | ||
| probably the fastest way to learn how to use Flot. | ||
|
|
||
|
|
||
| Installation | ||
| ------------ | ||
|
|
||
| Just include the Javascript file after you've included jQuery. | ||
|
|
||
| Generally, all browsers that support the HTML5 canvas tag are | ||
| supported. | ||
|
|
||
| For support for Internet Explorer < 9, you can use Excanvas, a canvas | ||
| emulator; this is used in the examples bundled with Flot. You just | ||
| include the excanvas script like this: | ||
|
|
||
| <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]--> | ||
|
|
||
| If it's not working on your development IE 6.0, check that it has | ||
| support for VML which Excanvas is relying on. It appears that some | ||
| stripped down versions used for test environments on virtual machines | ||
| lack the VML support. | ||
|
|
||
| You can also try using Flashcanvas (see | ||
| http://code.google.com/p/flashcanvas/), which uses Flash to do the | ||
| emulation. Although Flash can be a bit slower to load than VML, if | ||
| you've got a lot of points, the Flash version can be much faster | ||
| overall. Flot contains some wrapper code for activating Excanvas which | ||
| Flashcanvas is compatible with. | ||
|
|
||
| You need at least jQuery 1.2.6, but try at least 1.3.2 for interactive | ||
| charts because of performance improvements in event handling. | ||
|
|
||
|
|
||
| Basic usage | ||
| ----------- | ||
|
|
||
| Create a placeholder div to put the graph in: | ||
|
|
||
| <div id="placeholder"></div> | ||
|
|
||
| You need to set the width and height of this div, otherwise the plot | ||
| library doesn't know how to scale the graph. You can do it inline like | ||
| this: | ||
|
|
||
| <div id="placeholder" style="width:600px;height:300px"></div> | ||
|
|
||
| You can also do it with an external stylesheet. Make sure that the | ||
| placeholder isn't within something with a display:none CSS property - | ||
| in that case, Flot has trouble measuring label dimensions which | ||
| results in garbled looks and might have trouble measuring the | ||
| placeholder dimensions which is fatal (it'll throw an exception). | ||
|
|
||
| Then when the div is ready in the DOM, which is usually on document | ||
| ready, run the plot function: | ||
|
|
||
| $.plot($("#placeholder"), data, options); | ||
|
|
||
| Here, data is an array of data series and options is an object with | ||
| settings if you want to customize the plot. Take a look at the | ||
| examples for some ideas of what to put in or look at the reference | ||
| in the file "API.txt". Here's a quick example that'll draw a line from | ||
| (0, 0) to (1, 1): | ||
|
|
||
| $.plot($("#placeholder"), [ [[0, 0], [1, 1]] ], { yaxis: { max: 1 } }); | ||
|
|
||
| The plot function immediately draws the chart and then returns a plot | ||
| object with a couple of methods. | ||
|
|
||
|
|
||
| What's with the name? | ||
| --------------------- | ||
|
|
||
| First: it's pronounced with a short o, like "plot". Not like "flawed". | ||
|
|
||
| So "Flot" rhymes with "plot". | ||
|
|
||
| And if you look up "flot" in a Danish-to-English dictionary, some up | ||
| the words that come up are "good-looking", "attractive", "stylish", | ||
| "smart", "impressive", "extravagant". One of the main goals with Flot | ||
| is pretty looks. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| /* Plugin for jQuery for working with colors. | ||
| * | ||
| * Version 1.1. | ||
| * | ||
| * Inspiration from jQuery color animation plugin by John Resig. | ||
| * | ||
| * Released under the MIT license by Ole Laursen, October 2009. | ||
| * | ||
| * Examples: | ||
| * | ||
| * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() | ||
| * var c = $.color.extract($("#mydiv"), 'background-color'); | ||
| * console.log(c.r, c.g, c.b, c.a); | ||
| * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" | ||
| * | ||
| * Note that .scale() and .add() return the same modified object | ||
| * instead of making a new one. | ||
| * | ||
| * V. 1.1: Fix error handling so e.g. parsing an empty string does | ||
| * produce a color rather than just crashing. | ||
| */ | ||
|
|
||
| (function($) { | ||
| $.color = {}; | ||
|
|
||
| // construct color object with some convenient chainable helpers | ||
| $.color.make = function (r, g, b, a) { | ||
| var o = {}; | ||
| o.r = r || 0; | ||
| o.g = g || 0; | ||
| o.b = b || 0; | ||
| o.a = a != null ? a : 1; | ||
|
|
||
| o.add = function (c, d) { | ||
| for (var i = 0; i < c.length; ++i) | ||
| o[c.charAt(i)] += d; | ||
| return o.normalize(); | ||
| }; | ||
|
|
||
| o.scale = function (c, f) { | ||
| for (var i = 0; i < c.length; ++i) | ||
| o[c.charAt(i)] *= f; | ||
| return o.normalize(); | ||
| }; | ||
|
|
||
| o.toString = function () { | ||
| if (o.a >= 1.0) { | ||
| return "rgb("+[o.r, o.g, o.b].join(",")+")"; | ||
| } else { | ||
| return "rgba("+[o.r, o.g, o.b, o.a].join(",")+")"; | ||
| } | ||
| }; | ||
|
|
||
| o.normalize = function () { | ||
| function clamp(min, value, max) { | ||
| return value < min ? min: (value > max ? max: value); | ||
| } | ||
|
|
||
| o.r = clamp(0, parseInt(o.r), 255); | ||
| o.g = clamp(0, parseInt(o.g), 255); | ||
| o.b = clamp(0, parseInt(o.b), 255); | ||
| o.a = clamp(0, o.a, 1); | ||
| return o; | ||
| }; | ||
|
|
||
| o.clone = function () { | ||
| return $.color.make(o.r, o.b, o.g, o.a); | ||
| }; | ||
|
|
||
| return o.normalize(); | ||
| } | ||
|
|
||
| // extract CSS color property from element, going up in the DOM | ||
| // if it's "transparent" | ||
| $.color.extract = function (elem, css) { | ||
| var c; | ||
| do { | ||
| c = elem.css(css).toLowerCase(); | ||
| // keep going until we find an element that has color, or | ||
| // we hit the body | ||
| if (c != '' && c != 'transparent') | ||
| break; | ||
| elem = elem.parent(); | ||
| } while (!$.nodeName(elem.get(0), "body")); | ||
|
|
||
| // catch Safari's way of signalling transparent | ||
| if (c == "rgba(0, 0, 0, 0)") | ||
| c = "transparent"; | ||
|
|
||
| return $.color.parse(c); | ||
| } | ||
|
|
||
| // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"), | ||
| // returns color object, if parsing failed, you get black (0, 0, | ||
| // 0) out | ||
| $.color.parse = function (str) { | ||
| var res, m = $.color.make; | ||
|
|
||
| // Look for rgb(num,num,num) | ||
| if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)) | ||
| return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10)); | ||
|
|
||
| // Look for rgba(num,num,num,num) | ||
| if (res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)) | ||
| return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4])); | ||
|
|
||
| // Look for rgb(num%,num%,num%) | ||
| if (res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)) | ||
| return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55); | ||
|
|
||
| // Look for rgba(num%,num%,num%,num) | ||
| if (res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)) | ||
| return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55, parseFloat(res[4])); | ||
|
|
||
| // Look for #a0b1c2 | ||
| if (res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)) | ||
| return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16)); | ||
|
|
||
| // Look for #fff | ||
| if (res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)) | ||
| return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16)); | ||
|
|
||
| // Otherwise, we're most likely dealing with a named color | ||
| var name = $.trim(str).toLowerCase(); | ||
| if (name == "transparent") | ||
| return m(255, 255, 255, 0); | ||
| else { | ||
| // default to black | ||
| res = lookupColors[name] || [0, 0, 0]; | ||
| return m(res[0], res[1], res[2]); | ||
| } | ||
| } | ||
|
|
||
| var lookupColors = { | ||
| aqua:[0,255,255], | ||
| azure:[240,255,255], | ||
| beige:[245,245,220], | ||
| black:[0,0,0], | ||
| blue:[0,0,255], | ||
| brown:[165,42,42], | ||
| cyan:[0,255,255], | ||
| darkblue:[0,0,139], | ||
| darkcyan:[0,139,139], | ||
| darkgrey:[169,169,169], | ||
| darkgreen:[0,100,0], | ||
| darkkhaki:[189,183,107], | ||
| darkmagenta:[139,0,139], | ||
| darkolivegreen:[85,107,47], | ||
| darkorange:[255,140,0], | ||
| darkorchid:[153,50,204], | ||
| darkred:[139,0,0], | ||
| darksalmon:[233,150,122], | ||
| darkviolet:[148,0,211], | ||
| fuchsia:[255,0,255], | ||
| gold:[255,215,0], | ||
| green:[0,128,0], | ||
| indigo:[75,0,130], | ||
| khaki:[240,230,140], | ||
| lightblue:[173,216,230], | ||
| lightcyan:[224,255,255], | ||
| lightgreen:[144,238,144], | ||
| lightgrey:[211,211,211], | ||
| lightpink:[255,182,193], | ||
| lightyellow:[255,255,224], | ||
| lime:[0,255,0], | ||
| magenta:[255,0,255], | ||
| maroon:[128,0,0], | ||
| navy:[0,0,128], | ||
| olive:[128,128,0], | ||
| orange:[255,165,0], | ||
| pink:[255,192,203], | ||
| purple:[128,0,128], | ||
| violet:[128,0,128], | ||
| red:[255,0,0], | ||
| silver:[192,192,192], | ||
| white:[255,255,255], | ||
| yellow:[255,255,0] | ||
| }; | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| /* | ||
| Flot plugin for showing crosshairs, thin lines, when the mouse hovers | ||
| over the plot. | ||
| crosshair: { | ||
| mode: null or "x" or "y" or "xy" | ||
| color: color | ||
| lineWidth: number | ||
| } | ||
| Set the mode to one of "x", "y" or "xy". The "x" mode enables a | ||
| vertical crosshair that lets you trace the values on the x axis, "y" | ||
| enables a horizontal crosshair and "xy" enables them both. "color" is | ||
| the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"), | ||
| "lineWidth" is the width of the drawn lines (default is 1). | ||
| The plugin also adds four public methods: | ||
| - setCrosshair(pos) | ||
| Set the position of the crosshair. Note that this is cleared if | ||
| the user moves the mouse. "pos" is in coordinates of the plot and | ||
| should be on the form { x: xpos, y: ypos } (you can use x2/x3/... | ||
| if you're using multiple axes), which is coincidentally the same | ||
| format as what you get from a "plothover" event. If "pos" is null, | ||
| the crosshair is cleared. | ||
| - clearCrosshair() | ||
| Clear the crosshair. | ||
| - lockCrosshair(pos) | ||
| Cause the crosshair to lock to the current location, no longer | ||
| updating if the user moves the mouse. Optionally supply a position | ||
| (passed on to setCrosshair()) to move it to. | ||
| Example usage: | ||
| var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; | ||
| $("#graph").bind("plothover", function (evt, position, item) { | ||
| if (item) { | ||
| // Lock the crosshair to the data point being hovered | ||
| myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] }); | ||
| } | ||
| else { | ||
| // Return normal crosshair operation | ||
| myFlot.unlockCrosshair(); | ||
| } | ||
| }); | ||
| - unlockCrosshair() | ||
| Free the crosshair to move again after locking it. | ||
| */ | ||
|
|
||
| (function ($) { | ||
| var options = { | ||
| crosshair: { | ||
| mode: null, // one of null, "x", "y" or "xy", | ||
| color: "rgba(170, 0, 0, 0.80)", | ||
| lineWidth: 1 | ||
| } | ||
| }; | ||
|
|
||
| function init(plot) { | ||
| // position of crosshair in pixels | ||
| var crosshair = { x: -1, y: -1, locked: false }; | ||
|
|
||
| plot.setCrosshair = function setCrosshair(pos) { | ||
| if (!pos) | ||
| crosshair.x = -1; | ||
| else { | ||
| var o = plot.p2c(pos); | ||
| crosshair.x = Math.max(0, Math.min(o.left, plot.width())); | ||
| crosshair.y = Math.max(0, Math.min(o.top, plot.height())); | ||
| } | ||
|
|
||
| plot.triggerRedrawOverlay(); | ||
| }; | ||
|
|
||
| plot.clearCrosshair = plot.setCrosshair; // passes null for pos | ||
|
|
||
| plot.lockCrosshair = function lockCrosshair(pos) { | ||
| if (pos) | ||
| plot.setCrosshair(pos); | ||
| crosshair.locked = true; | ||
| } | ||
|
|
||
| plot.unlockCrosshair = function unlockCrosshair() { | ||
| crosshair.locked = false; | ||
| } | ||
|
|
||
| function onMouseOut(e) { | ||
| if (crosshair.locked) | ||
| return; | ||
|
|
||
| if (crosshair.x != -1) { | ||
| crosshair.x = -1; | ||
| plot.triggerRedrawOverlay(); | ||
| } | ||
| } | ||
|
|
||
| function onMouseMove(e) { | ||
| if (crosshair.locked) | ||
| return; | ||
|
|
||
| if (plot.getSelection && plot.getSelection()) { | ||
| crosshair.x = -1; // hide the crosshair while selecting | ||
| return; | ||
| } | ||
|
|
||
| var offset = plot.offset(); | ||
| crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); | ||
| crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); | ||
| plot.triggerRedrawOverlay(); | ||
| } | ||
|
|
||
| plot.hooks.bindEvents.push(function (plot, eventHolder) { | ||
| if (!plot.getOptions().crosshair.mode) | ||
| return; | ||
|
|
||
| eventHolder.mouseout(onMouseOut); | ||
| eventHolder.mousemove(onMouseMove); | ||
| }); | ||
|
|
||
| plot.hooks.drawOverlay.push(function (plot, ctx) { | ||
| var c = plot.getOptions().crosshair; | ||
| if (!c.mode) | ||
| return; | ||
|
|
||
| var plotOffset = plot.getPlotOffset(); | ||
|
|
||
| ctx.save(); | ||
| ctx.translate(plotOffset.left, plotOffset.top); | ||
|
|
||
| if (crosshair.x != -1) { | ||
| ctx.strokeStyle = c.color; | ||
| ctx.lineWidth = c.lineWidth; | ||
| ctx.lineJoin = "round"; | ||
|
|
||
| ctx.beginPath(); | ||
| if (c.mode.indexOf("x") != -1) { | ||
| ctx.moveTo(crosshair.x, 0); | ||
| ctx.lineTo(crosshair.x, plot.height()); | ||
| } | ||
| if (c.mode.indexOf("y") != -1) { | ||
| ctx.moveTo(0, crosshair.y); | ||
| ctx.lineTo(plot.width(), crosshair.y); | ||
| } | ||
| ctx.stroke(); | ||
| } | ||
| ctx.restore(); | ||
| }); | ||
|
|
||
| plot.hooks.shutdown.push(function (plot, eventHolder) { | ||
| eventHolder.unbind("mouseout", onMouseOut); | ||
| eventHolder.unbind("mousemove", onMouseMove); | ||
| }); | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'crosshair', | ||
| version: '1.0' | ||
| }); | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| /* | ||
| Flot plugin for computing bottoms for filled line and bar charts. | ||
| The case: you've got two series that you want to fill the area | ||
| between. In Flot terms, you need to use one as the fill bottom of the | ||
| other. You can specify the bottom of each data point as the third | ||
| coordinate manually, or you can use this plugin to compute it for you. | ||
| In order to name the other series, you need to give it an id, like this | ||
| var dataset = [ | ||
| { data: [ ... ], id: "foo" } , // use default bottom | ||
| { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom | ||
| ]; | ||
| $.plot($("#placeholder"), dataset, { line: { show: true, fill: true }}); | ||
| As a convenience, if the id given is a number that doesn't appear as | ||
| an id in the series, it is interpreted as the index in the array | ||
| instead (so fillBetween: 0 can also mean the first series). | ||
| Internally, the plugin modifies the datapoints in each series. For | ||
| line series, extra data points might be inserted through | ||
| interpolation. Note that at points where the bottom line is not | ||
| defined (due to a null point or start/end of line), the current line | ||
| will show a gap too. The algorithm comes from the jquery.flot.stack.js | ||
| plugin, possibly some code could be shared. | ||
| */ | ||
|
|
||
| (function ($) { | ||
| var options = { | ||
| series: { fillBetween: null } // or number | ||
| }; | ||
|
|
||
| function init(plot) { | ||
| function findBottomSeries(s, allseries) { | ||
| var i; | ||
| for (i = 0; i < allseries.length; ++i) { | ||
| if (allseries[i].id == s.fillBetween) | ||
| return allseries[i]; | ||
| } | ||
|
|
||
| if (typeof s.fillBetween == "number") { | ||
| i = s.fillBetween; | ||
|
|
||
| if (i < 0 || i >= allseries.length) | ||
| return null; | ||
|
|
||
| return allseries[i]; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| function computeFillBottoms(plot, s, datapoints) { | ||
| if (s.fillBetween == null) | ||
| return; | ||
|
|
||
| var other = findBottomSeries(s, plot.getData()); | ||
| if (!other) | ||
| return; | ||
|
|
||
| var ps = datapoints.pointsize, | ||
| points = datapoints.points, | ||
| otherps = other.datapoints.pointsize, | ||
| otherpoints = other.datapoints.points, | ||
| newpoints = [], | ||
| px, py, intery, qx, qy, bottom, | ||
| withlines = s.lines.show, | ||
| withbottom = ps > 2 && datapoints.format[2].y, | ||
| withsteps = withlines && s.lines.steps, | ||
| fromgap = true, | ||
| i = 0, j = 0, l; | ||
|
|
||
| while (true) { | ||
| if (i >= points.length) | ||
| break; | ||
|
|
||
| l = newpoints.length; | ||
|
|
||
| if (points[i] == null) { | ||
| // copy gaps | ||
| for (m = 0; m < ps; ++m) | ||
| newpoints.push(points[i + m]); | ||
| i += ps; | ||
| } | ||
| else if (j >= otherpoints.length) { | ||
| // for lines, we can't use the rest of the points | ||
| if (!withlines) { | ||
| for (m = 0; m < ps; ++m) | ||
| newpoints.push(points[i + m]); | ||
| } | ||
| i += ps; | ||
| } | ||
| else if (otherpoints[j] == null) { | ||
| // oops, got a gap | ||
| for (m = 0; m < ps; ++m) | ||
| newpoints.push(null); | ||
| fromgap = true; | ||
| j += otherps; | ||
| } | ||
| else { | ||
| // cases where we actually got two points | ||
| px = points[i]; | ||
| py = points[i + 1]; | ||
| qx = otherpoints[j]; | ||
| qy = otherpoints[j + 1]; | ||
| bottom = 0; | ||
|
|
||
| if (px == qx) { | ||
| for (m = 0; m < ps; ++m) | ||
| newpoints.push(points[i + m]); | ||
|
|
||
| //newpoints[l + 1] += qy; | ||
| bottom = qy; | ||
|
|
||
| i += ps; | ||
| j += otherps; | ||
| } | ||
| else if (px > qx) { | ||
| // we got past point below, might need to | ||
| // insert interpolated extra point | ||
| if (withlines && i > 0 && points[i - ps] != null) { | ||
| intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px); | ||
| newpoints.push(qx); | ||
| newpoints.push(intery) | ||
| for (m = 2; m < ps; ++m) | ||
| newpoints.push(points[i + m]); | ||
| bottom = qy; | ||
| } | ||
|
|
||
| j += otherps; | ||
| } | ||
| else { // px < qx | ||
| if (fromgap && withlines) { | ||
| // if we come from a gap, we just skip this point | ||
| i += ps; | ||
| continue; | ||
| } | ||
|
|
||
| for (m = 0; m < ps; ++m) | ||
| newpoints.push(points[i + m]); | ||
|
|
||
| // we might be able to interpolate a point below, | ||
| // this can give us a better y | ||
| if (withlines && j > 0 && otherpoints[j - otherps] != null) | ||
| bottom = qy + (otherpoints[j - otherps + 1] - qy) * (px - qx) / (otherpoints[j - otherps] - qx); | ||
|
|
||
| //newpoints[l + 1] += bottom; | ||
|
|
||
| i += ps; | ||
| } | ||
|
|
||
| fromgap = false; | ||
|
|
||
| if (l != newpoints.length && withbottom) | ||
| newpoints[l + 2] = bottom; | ||
| } | ||
|
|
||
| // maintain the line steps invariant | ||
| if (withsteps && l != newpoints.length && l > 0 | ||
| && newpoints[l] != null | ||
| && newpoints[l] != newpoints[l - ps] | ||
| && newpoints[l + 1] != newpoints[l - ps + 1]) { | ||
| for (m = 0; m < ps; ++m) | ||
| newpoints[l + ps + m] = newpoints[l + m]; | ||
| newpoints[l + 1] = newpoints[l - ps + 1]; | ||
| } | ||
| } | ||
|
|
||
| datapoints.points = newpoints; | ||
| } | ||
|
|
||
| plot.hooks.processDatapoints.push(computeFillBottoms); | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'fillbetween', | ||
| version: '1.0' | ||
| }); | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| /* | ||
| * The MIT License | ||
| Copyright (c) 2010 by Juergen Marsch | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in | ||
| all copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. | ||
| */ | ||
|
|
||
| (function ($) | ||
| { var options = | ||
| { series: { | ||
| grow: { | ||
| active: true, | ||
| valueIndex: 1, | ||
| stepDelay: 20, | ||
| steps:100, | ||
| stepMode: "linear", | ||
| stepDirection: "up" | ||
| } | ||
| } | ||
| }; | ||
| function init(plot) { | ||
| var done = false; | ||
| var growfunc; | ||
| var plt = plot; | ||
| var data = null; | ||
| var opt = null; | ||
| var valueIndex; | ||
| plot.hooks.bindEvents.push(processbindEvents); | ||
| plot.hooks.drawSeries.push(processSeries); | ||
| function processSeries(plot, canvascontext, series) | ||
| { opt = plot.getOptions(); | ||
| valueIndex = opt.series.grow.valueIndex; | ||
| if(opt.series.grow.active == true) | ||
| { if (done == false) | ||
| { data = plot.getData(); | ||
| data.actualStep = 0; | ||
| for (var j = 0; j < data.length; j++) | ||
| { data[j].dataOrg = clone(data[j].data); | ||
| for (var i = 0; i < data[j].data.length; i++) | ||
| data[j].data[i][valueIndex] = 0; | ||
| } | ||
| plot.setData(data); | ||
| done = true; | ||
| } | ||
| } | ||
| } | ||
| function processbindEvents(plot,eventHolder) | ||
| { opt = plot.getOptions(); | ||
| if (opt.series.grow.active == true) | ||
| { var d = plot.getData(); | ||
| for (var j = 0; j < data.length; j++) { | ||
| opt.series.grow.steps = Math.max(opt.series.grow.steps, d[j].grow.steps); | ||
| } | ||
| if(opt.series.grow.stepDelay == 0) opt.series.grow.stepDelay++; | ||
| growfunc = window.setInterval(growing, opt.series.grow.stepDelay); | ||
| } | ||
| } | ||
| function growing() | ||
| { if (data.actualStep < opt.series.grow.steps) | ||
| { data.actualStep++; | ||
| for(var j = 0; j < data.length; j++) | ||
| { if (typeof data[j].grow.stepMode == "function") | ||
| { data[j].grow.stepMode(data[j],data.actualStep,valueIndex); } | ||
| else | ||
| { if (data[j].grow.stepMode == "linear") growLinear(); | ||
| else if (data[j].grow.stepMode == "maximum") growMaximum(); | ||
| else if (data[j].grow.stepMode == "delay") growDelay(); | ||
| else growNone(); | ||
| } | ||
| } | ||
| plt.setData(data); | ||
| plt.draw(); | ||
| } | ||
| else | ||
| { window.clearInterval(growfunc); } | ||
| function growNone() | ||
| { if (data.actualStep == 1) | ||
| { for (var i = 0; i < data[j].data.length; i++) | ||
| { data[j].data[i][valueIndex] = data[j].dataOrg[i][valueIndex]; } | ||
| } | ||
| } | ||
| function growLinear() | ||
| { if (data.actualStep <= data[j].grow.steps) | ||
| { for (var i = 0; i < data[j].data.length; i++) | ||
| { if (data[j].grow.stepDirection == "up") | ||
| { data[j].data[i][valueIndex] = data[j].dataOrg[i][valueIndex] / data[j].grow.steps * data.actualStep;} | ||
| else if(data[j].grow.stepDirection == "down") | ||
| { data[j].data[i][valueIndex] = data[j].dataOrg[i][valueIndex] + (data[j].yaxis.max - data[j].dataOrg[i][valueIndex]) / data[j].grow.steps * (data[j].grow.steps - data.actualStep); } | ||
| } | ||
| } | ||
| } | ||
| function growMaximum() | ||
| { if (data.actualStep <= data[j].grow.steps) | ||
| { for (var i = 0; i < data[j].data.length; i++) | ||
| { if (data[j].grow.stepDirection == "up") | ||
| { data[j].data[i][valueIndex] = Math.min(data[j].dataOrg[i][valueIndex], data[j].yaxis.max / data[j].grow.steps * data.actualStep); } | ||
| else if (data[j].grow.stepDirection == "down") | ||
| { data[j].data[i][valueIndex] = Math.max(data[j].dataOrg[i][valueIndex], data[j].yaxis.max / data[j].grow.steps * (data[j].grow.steps - data.actualStep) ); } | ||
| } | ||
| } | ||
| } | ||
| function growDelay() | ||
| { if (data.actualStep == data[j].grow.steps) | ||
| { for (var i = 0; i < data[j].data.length; i++) | ||
| { data[j].data[i][valueIndex] = data[j].dataOrg[i][valueIndex]; } | ||
| } | ||
| } | ||
| } | ||
| function clone(obj) | ||
| { if(obj == null || typeof(obj) != 'object') return obj; | ||
| var temp = new obj.constructor(); | ||
| for(var key in obj) temp[key] = clone(obj[key]); | ||
| return temp; | ||
| } | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'grow', | ||
| version: '0.2' | ||
| }); | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,238 @@ | ||
| /* | ||
| Flot plugin for plotting images, e.g. useful for putting ticks on a | ||
| prerendered complex visualization. | ||
| The data syntax is [[image, x1, y1, x2, y2], ...] where (x1, y1) and | ||
| (x2, y2) are where you intend the two opposite corners of the image to | ||
| end up in the plot. Image must be a fully loaded Javascript image (you | ||
| can make one with new Image()). If the image is not complete, it's | ||
| skipped when plotting. | ||
| There are two helpers included for retrieving images. The easiest work | ||
| the way that you put in URLs instead of images in the data (like | ||
| ["myimage.png", 0, 0, 10, 10]), then call $.plot.image.loadData(data, | ||
| options, callback) where data and options are the same as you pass in | ||
| to $.plot. This loads the images, replaces the URLs in the data with | ||
| the corresponding images and calls "callback" when all images are | ||
| loaded (or failed loading). In the callback, you can then call $.plot | ||
| with the data set. See the included example. | ||
| A more low-level helper, $.plot.image.load(urls, callback) is also | ||
| included. Given a list of URLs, it calls callback with an object | ||
| mapping from URL to Image object when all images are loaded or have | ||
| failed loading. | ||
| Options for the plugin are | ||
| series: { | ||
| images: { | ||
| show: boolean | ||
| anchor: "corner" or "center" | ||
| alpha: [0,1] | ||
| } | ||
| } | ||
| which can be specified for a specific series | ||
| $.plot($("#placeholder"), [{ data: [ ... ], images: { ... } ]) | ||
| Note that because the data format is different from usual data points, | ||
| you can't use images with anything else in a specific data series. | ||
| Setting "anchor" to "center" causes the pixels in the image to be | ||
| anchored at the corner pixel centers inside of at the pixel corners, | ||
| effectively letting half a pixel stick out to each side in the plot. | ||
| A possible future direction could be support for tiling for large | ||
| images (like Google Maps). | ||
| */ | ||
|
|
||
| (function ($) { | ||
| var options = { | ||
| series: { | ||
| images: { | ||
| show: false, | ||
| alpha: 1, | ||
| anchor: "corner" // or "center" | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| $.plot.image = {}; | ||
|
|
||
| $.plot.image.loadDataImages = function (series, options, callback) { | ||
| var urls = [], points = []; | ||
|
|
||
| var defaultShow = options.series.images.show; | ||
|
|
||
| $.each(series, function (i, s) { | ||
| if (!(defaultShow || s.images.show)) | ||
| return; | ||
|
|
||
| if (s.data) | ||
| s = s.data; | ||
|
|
||
| $.each(s, function (i, p) { | ||
| if (typeof p[0] == "string") { | ||
| urls.push(p[0]); | ||
| points.push(p); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| $.plot.image.load(urls, function (loadedImages) { | ||
| $.each(points, function (i, p) { | ||
| var url = p[0]; | ||
| if (loadedImages[url]) | ||
| p[0] = loadedImages[url]; | ||
| }); | ||
|
|
||
| callback(); | ||
| }); | ||
| } | ||
|
|
||
| $.plot.image.load = function (urls, callback) { | ||
| var missing = urls.length, loaded = {}; | ||
| if (missing == 0) | ||
| callback({}); | ||
|
|
||
| $.each(urls, function (i, url) { | ||
| var handler = function () { | ||
| --missing; | ||
|
|
||
| loaded[url] = this; | ||
|
|
||
| if (missing == 0) | ||
| callback(loaded); | ||
| }; | ||
|
|
||
| $('<img />').load(handler).error(handler).attr('src', url); | ||
| }); | ||
| } | ||
|
|
||
| function drawSeries(plot, ctx, series) { | ||
| var plotOffset = plot.getPlotOffset(); | ||
|
|
||
| if (!series.images || !series.images.show) | ||
| return; | ||
|
|
||
| var points = series.datapoints.points, | ||
| ps = series.datapoints.pointsize; | ||
|
|
||
| for (var i = 0; i < points.length; i += ps) { | ||
| var img = points[i], | ||
| x1 = points[i + 1], y1 = points[i + 2], | ||
| x2 = points[i + 3], y2 = points[i + 4], | ||
| xaxis = series.xaxis, yaxis = series.yaxis, | ||
| tmp; | ||
|
|
||
| // actually we should check img.complete, but it | ||
| // appears to be a somewhat unreliable indicator in | ||
| // IE6 (false even after load event) | ||
| if (!img || img.width <= 0 || img.height <= 0) | ||
| continue; | ||
|
|
||
| if (x1 > x2) { | ||
| tmp = x2; | ||
| x2 = x1; | ||
| x1 = tmp; | ||
| } | ||
| if (y1 > y2) { | ||
| tmp = y2; | ||
| y2 = y1; | ||
| y1 = tmp; | ||
| } | ||
|
|
||
| // if the anchor is at the center of the pixel, expand the | ||
| // image by 1/2 pixel in each direction | ||
| if (series.images.anchor == "center") { | ||
| tmp = 0.5 * (x2-x1) / (img.width - 1); | ||
| x1 -= tmp; | ||
| x2 += tmp; | ||
| tmp = 0.5 * (y2-y1) / (img.height - 1); | ||
| y1 -= tmp; | ||
| y2 += tmp; | ||
| } | ||
|
|
||
| // clip | ||
| if (x1 == x2 || y1 == y2 || | ||
| x1 >= xaxis.max || x2 <= xaxis.min || | ||
| y1 >= yaxis.max || y2 <= yaxis.min) | ||
| continue; | ||
|
|
||
| var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height; | ||
| if (x1 < xaxis.min) { | ||
| sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1); | ||
| x1 = xaxis.min; | ||
| } | ||
|
|
||
| if (x2 > xaxis.max) { | ||
| sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1); | ||
| x2 = xaxis.max; | ||
| } | ||
|
|
||
| if (y1 < yaxis.min) { | ||
| sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1); | ||
| y1 = yaxis.min; | ||
| } | ||
|
|
||
| if (y2 > yaxis.max) { | ||
| sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1); | ||
| y2 = yaxis.max; | ||
| } | ||
|
|
||
| x1 = xaxis.p2c(x1); | ||
| x2 = xaxis.p2c(x2); | ||
| y1 = yaxis.p2c(y1); | ||
| y2 = yaxis.p2c(y2); | ||
|
|
||
| // the transformation may have swapped us | ||
| if (x1 > x2) { | ||
| tmp = x2; | ||
| x2 = x1; | ||
| x1 = tmp; | ||
| } | ||
| if (y1 > y2) { | ||
| tmp = y2; | ||
| y2 = y1; | ||
| y1 = tmp; | ||
| } | ||
|
|
||
| tmp = ctx.globalAlpha; | ||
| ctx.globalAlpha *= series.images.alpha; | ||
| ctx.drawImage(img, | ||
| sx1, sy1, sx2 - sx1, sy2 - sy1, | ||
| x1 + plotOffset.left, y1 + plotOffset.top, | ||
| x2 - x1, y2 - y1); | ||
| ctx.globalAlpha = tmp; | ||
| } | ||
| } | ||
|
|
||
| function processRawData(plot, series, data, datapoints) { | ||
| if (!series.images.show) | ||
| return; | ||
|
|
||
| // format is Image, x1, y1, x2, y2 (opposite corners) | ||
| datapoints.format = [ | ||
| { required: true }, | ||
| { x: true, number: true, required: true }, | ||
| { y: true, number: true, required: true }, | ||
| { x: true, number: true, required: true }, | ||
| { y: true, number: true, required: true } | ||
| ]; | ||
| } | ||
|
|
||
| function init(plot) { | ||
| plot.hooks.processRawData.push(processRawData); | ||
| plot.hooks.drawSeries.push(drawSeries); | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'image', | ||
| version: '1.1' | ||
| }); | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,336 @@ | ||
| /* | ||
| Flot plugin for adding panning and zooming capabilities to a plot. | ||
| The default behaviour is double click and scrollwheel up/down to zoom | ||
| in, drag to pan. The plugin defines plot.zoom({ center }), | ||
| plot.zoomOut() and plot.pan(offset) so you easily can add custom | ||
| controls. It also fires a "plotpan" and "plotzoom" event when | ||
| something happens, useful for synchronizing plots. | ||
| Options: | ||
| zoom: { | ||
| interactive: false | ||
| trigger: "dblclick" // or "click" for single click | ||
| amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) | ||
| } | ||
| pan: { | ||
| interactive: false | ||
| cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" | ||
| frameRate: 20 | ||
| } | ||
| xaxis, yaxis, x2axis, y2axis: { | ||
| zoomRange: null // or [number, number] (min range, max range) or false | ||
| panRange: null // or [number, number] (min, max) or false | ||
| } | ||
| "interactive" enables the built-in drag/click behaviour. If you enable | ||
| interactive for pan, then you'll have a basic plot that supports | ||
| moving around; the same for zoom. | ||
| "amount" specifies the default amount to zoom in (so 1.5 = 150%) | ||
| relative to the current viewport. | ||
| "cursor" is a standard CSS mouse cursor string used for visual | ||
| feedback to the user when dragging. | ||
| "frameRate" specifies the maximum number of times per second the plot | ||
| will update itself while the user is panning around on it (set to null | ||
| to disable intermediate pans, the plot will then not update until the | ||
| mouse button is released). | ||
| "zoomRange" is the interval in which zooming can happen, e.g. with | ||
| zoomRange: [1, 100] the zoom will never scale the axis so that the | ||
| difference between min and max is smaller than 1 or larger than 100. | ||
| You can set either end to null to ignore, e.g. [1, null]. If you set | ||
| zoomRange to false, zooming on that axis will be disabled. | ||
| "panRange" confines the panning to stay within a range, e.g. with | ||
| panRange: [-10, 20] panning stops at -10 in one end and at 20 in the | ||
| other. Either can be null, e.g. [-10, null]. If you set | ||
| panRange to false, panning on that axis will be disabled. | ||
| Example API usage: | ||
| plot = $.plot(...); | ||
| // zoom default amount in on the pixel (10, 20) | ||
| plot.zoom({ center: { left: 10, top: 20 } }); | ||
| // zoom out again | ||
| plot.zoomOut({ center: { left: 10, top: 20 } }); | ||
| // zoom 200% in on the pixel (10, 20) | ||
| plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); | ||
| // pan 100 pixels to the left and 20 down | ||
| plot.pan({ left: -100, top: 20 }) | ||
| Here, "center" specifies where the center of the zooming should | ||
| happen. Note that this is defined in pixel space, not the space of the | ||
| data points (you can use the p2c helpers on the axes in Flot to help | ||
| you convert between these). | ||
| "amount" is the amount to zoom the viewport relative to the current | ||
| range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is | ||
| 70% (zoom out). You can set the default in the options. | ||
| */ | ||
|
|
||
|
|
||
| // First two dependencies, jquery.event.drag.js and | ||
| // jquery.mousewheel.js, we put them inline here to save people the | ||
| // effort of downloading them. | ||
|
|
||
| /* | ||
| jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) | ||
| Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt | ||
| */ | ||
| (function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery); | ||
|
|
||
|
|
||
| /* jquery.mousewheel.min.js | ||
| * Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net) | ||
| * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) | ||
| * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. | ||
| * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. | ||
| * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. | ||
| * | ||
| * Version: 3.0.2 | ||
| * | ||
| * Requires: 1.2.2+ | ||
| */ | ||
| (function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery); | ||
|
|
||
|
|
||
|
|
||
|
|
||
| (function ($) { | ||
| var options = { | ||
| xaxis: { | ||
| zoomRange: null, // or [number, number] (min range, max range) | ||
| panRange: null // or [number, number] (min, max) | ||
| }, | ||
| zoom: { | ||
| interactive: false, | ||
| trigger: "dblclick", // or "click" for single click | ||
| amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out) | ||
| }, | ||
| pan: { | ||
| interactive: false, | ||
| cursor: "move", | ||
| frameRate: 20 | ||
| } | ||
| }; | ||
|
|
||
| function init(plot) { | ||
| function onZoomClick(e, zoomOut) { | ||
| var c = plot.offset(); | ||
| c.left = e.pageX - c.left; | ||
| c.top = e.pageY - c.top; | ||
| if (zoomOut) | ||
| plot.zoomOut({ center: c }); | ||
| else | ||
| plot.zoom({ center: c }); | ||
| } | ||
|
|
||
| function onMouseWheel(e, delta) { | ||
| onZoomClick(e, delta < 0); | ||
| return false; | ||
| } | ||
|
|
||
| var prevCursor = 'default', prevPageX = 0, prevPageY = 0, | ||
| panTimeout = null; | ||
|
|
||
| function onDragStart(e) { | ||
| if (e.which != 1) // only accept left-click | ||
| return false; | ||
| var c = plot.getPlaceholder().css('cursor'); | ||
| if (c) | ||
| prevCursor = c; | ||
| plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor); | ||
| prevPageX = e.pageX; | ||
| prevPageY = e.pageY; | ||
| } | ||
|
|
||
| function onDrag(e) { | ||
| var frameRate = plot.getOptions().pan.frameRate; | ||
| if (panTimeout || !frameRate) | ||
| return; | ||
|
|
||
| panTimeout = setTimeout(function () { | ||
| plot.pan({ left: prevPageX - e.pageX, | ||
| top: prevPageY - e.pageY }); | ||
| prevPageX = e.pageX; | ||
| prevPageY = e.pageY; | ||
|
|
||
| panTimeout = null; | ||
| }, 1 / frameRate * 1000); | ||
| } | ||
|
|
||
| function onDragEnd(e) { | ||
| if (panTimeout) { | ||
| clearTimeout(panTimeout); | ||
| panTimeout = null; | ||
| } | ||
|
|
||
| plot.getPlaceholder().css('cursor', prevCursor); | ||
| plot.pan({ left: prevPageX - e.pageX, | ||
| top: prevPageY - e.pageY }); | ||
| } | ||
|
|
||
| function bindEvents(plot, eventHolder) { | ||
| var o = plot.getOptions(); | ||
| if (o.zoom.interactive) { | ||
| eventHolder[o.zoom.trigger](onZoomClick); | ||
| eventHolder.mousewheel(onMouseWheel); | ||
| } | ||
|
|
||
| if (o.pan.interactive) { | ||
| eventHolder.bind("dragstart", { distance: 10 }, onDragStart); | ||
| eventHolder.bind("drag", onDrag); | ||
| eventHolder.bind("dragend", onDragEnd); | ||
| } | ||
| } | ||
|
|
||
| plot.zoomOut = function (args) { | ||
| if (!args) | ||
| args = {}; | ||
|
|
||
| if (!args.amount) | ||
| args.amount = plot.getOptions().zoom.amount | ||
|
|
||
| args.amount = 1 / args.amount; | ||
| plot.zoom(args); | ||
| } | ||
|
|
||
| plot.zoom = function (args) { | ||
| if (!args) | ||
| args = {}; | ||
|
|
||
| var c = args.center, | ||
| amount = args.amount || plot.getOptions().zoom.amount, | ||
| w = plot.width(), h = plot.height(); | ||
|
|
||
| if (!c) | ||
| c = { left: w / 2, top: h / 2 }; | ||
|
|
||
| var xf = c.left / w, | ||
| yf = c.top / h, | ||
| minmax = { | ||
| x: { | ||
| min: c.left - xf * w / amount, | ||
| max: c.left + (1 - xf) * w / amount | ||
| }, | ||
| y: { | ||
| min: c.top - yf * h / amount, | ||
| max: c.top + (1 - yf) * h / amount | ||
| } | ||
| }; | ||
|
|
||
| $.each(plot.getAxes(), function(_, axis) { | ||
| var opts = axis.options, | ||
| min = minmax[axis.direction].min, | ||
| max = minmax[axis.direction].max, | ||
| zr = opts.zoomRange; | ||
|
|
||
| if (zr === false) // no zooming on this axis | ||
| return; | ||
|
|
||
| min = axis.c2p(min); | ||
| max = axis.c2p(max); | ||
| if (min > max) { | ||
| // make sure min < max | ||
| var tmp = min; | ||
| min = max; | ||
| max = tmp; | ||
| } | ||
|
|
||
| var range = max - min; | ||
| if (zr && | ||
| ((zr[0] != null && range < zr[0]) || | ||
| (zr[1] != null && range > zr[1]))) | ||
| return; | ||
|
|
||
| opts.min = min; | ||
| opts.max = max; | ||
| }); | ||
|
|
||
| plot.setupGrid(); | ||
| plot.draw(); | ||
|
|
||
| if (!args.preventEvent) | ||
| plot.getPlaceholder().trigger("plotzoom", [ plot ]); | ||
| } | ||
|
|
||
| plot.pan = function (args) { | ||
| var delta = { | ||
| x: +args.left, | ||
| y: +args.top | ||
| }; | ||
|
|
||
| if (isNaN(delta.x)) | ||
| delta.x = 0; | ||
| if (isNaN(delta.y)) | ||
| delta.y = 0; | ||
|
|
||
| $.each(plot.getAxes(), function (_, axis) { | ||
| var opts = axis.options, | ||
| min, max, d = delta[axis.direction]; | ||
|
|
||
| min = axis.c2p(axis.p2c(axis.min) + d), | ||
| max = axis.c2p(axis.p2c(axis.max) + d); | ||
|
|
||
| var pr = opts.panRange; | ||
| if (pr === false) // no panning on this axis | ||
| return; | ||
|
|
||
| if (pr) { | ||
| // check whether we hit the wall | ||
| if (pr[0] != null && pr[0] > min) { | ||
| d = pr[0] - min; | ||
| min += d; | ||
| max += d; | ||
| } | ||
|
|
||
| if (pr[1] != null && pr[1] < max) { | ||
| d = pr[1] - max; | ||
| min += d; | ||
| max += d; | ||
| } | ||
| } | ||
|
|
||
| opts.min = min; | ||
| opts.max = max; | ||
| }); | ||
|
|
||
| plot.setupGrid(); | ||
| plot.draw(); | ||
|
|
||
| if (!args.preventEvent) | ||
| plot.getPlaceholder().trigger("plotpan", [ plot ]); | ||
| } | ||
|
|
||
| function shutdown(plot, eventHolder) { | ||
| eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick); | ||
| eventHolder.unbind("mousewheel", onMouseWheel); | ||
| eventHolder.unbind("dragstart", onDragStart); | ||
| eventHolder.unbind("drag", onDrag); | ||
| eventHolder.unbind("dragend", onDragEnd); | ||
| if (panTimeout) | ||
| clearTimeout(panTimeout); | ||
| } | ||
|
|
||
| plot.hooks.bindEvents.push(bindEvents); | ||
| plot.hooks.shutdown.push(shutdown); | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'navigate', | ||
| version: '1.3' | ||
| }); | ||
| })(jQuery); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| Flot plugin for automatically redrawing plots when the placeholder | ||
| size changes, e.g. on window resizes. | ||
| It works by listening for changes on the placeholder div (through the | ||
| jQuery resize event plugin) - if the size changes, it will redraw the | ||
| plot. | ||
| There are no options. If you need to disable the plugin for some | ||
| plots, you can just fix the size of their placeholders. | ||
| */ | ||
|
|
||
|
|
||
| /* Inline dependency: | ||
| * jQuery resize event - v1.1 - 3/14/2010 | ||
| * http://benalman.com/projects/jquery-resize-plugin/ | ||
| * | ||
| * Copyright (c) 2010 "Cowboy" Ben Alman | ||
| * Dual licensed under the MIT and GPL licenses. | ||
| * http://benalman.com/about/license/ | ||
| */ | ||
| (function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this); | ||
|
|
||
|
|
||
| (function ($) { | ||
| var options = { }; // no options | ||
|
|
||
| function init(plot) { | ||
| function onResize() { | ||
| var placeholder = plot.getPlaceholder(); | ||
|
|
||
| // somebody might have hidden us and we can't plot | ||
| // when we don't have the dimensions | ||
| if (placeholder.width() == 0 || placeholder.height() == 0) | ||
| return; | ||
|
|
||
| plot.resize(); | ||
| plot.setupGrid(); | ||
| plot.draw(); | ||
| } | ||
|
|
||
| function bindEvents(plot, eventHolder) { | ||
| plot.getPlaceholder().resize(onResize); | ||
| } | ||
|
|
||
| function shutdown(plot, eventHolder) { | ||
| plot.getPlaceholder().unbind("resize", onResize); | ||
| } | ||
|
|
||
| plot.hooks.bindEvents.push(bindEvents); | ||
| plot.hooks.shutdown.push(shutdown); | ||
| } | ||
|
|
||
| $.plot.plugins.push({ | ||
| init: init, | ||
| options: options, | ||
| name: 'resize', | ||
| version: '1.0' | ||
| }); | ||
| })(jQuery); |