Commit 7c9ff67b authored by olau@iola.dk's avatar olau@iola.dk

Landed dual axis/hover event/finding nearby datapoints patch

git-svn-id: https://flot.googlecode.com/svn/trunk@73 1e0a6537-2640-0410-bfb7-f154510ff394
parent 6b1971ed
...@@ -57,6 +57,8 @@ The format of a single series object is as follows: ...@@ -57,6 +57,8 @@ The format of a single series object is as follows:
lines: specific lines options, lines: specific lines options,
bars: specific bars options, bars: specific bars options,
points: specific points options, points: specific points options,
xaxis: 1 or 2,
yaxis: 1 or 2,
shadowSize: number shadowSize: number
} }
...@@ -81,6 +83,11 @@ The latter is mostly useful if you let the user add and remove series, ...@@ -81,6 +83,11 @@ The latter is mostly useful if you let the user add and remove series,
in which case you can hard-code the color index to prevent the colors in which case you can hard-code the color index to prevent the colors
from jumping around between the series. from jumping around between the series.
The "xaxis" and "yaxis" options specify which axis to use, specify 2
to get the secondary axis (x axis at top or y axis to the right).
E.g., you can use this to make a dual axis plot by specifying
{ yaxis: 2 } for one data series.
The rest of the options are all documented below as they are the same The rest of the options are all documented below as they are the same
as the default options passed in via the options parameter in the plot as the default options passed in via the options parameter in the plot
commmand. When you specify them for a specific data series, they will commmand. When you specify them for a specific data series, they will
...@@ -148,7 +155,7 @@ that it will overwrite the contents of the container. ...@@ -148,7 +155,7 @@ that it will overwrite the contents of the container.
Customizing the axes Customizing the axes
==================== ====================
xaxis, yaxis: { xaxis, yaxis, x2axis, y2axis: {
mode: null or "time" mode: null or "time"
min: null or number min: null or number
max: null or number max: null or number
...@@ -163,7 +170,7 @@ Customizing the axes ...@@ -163,7 +170,7 @@ Customizing the axes
tickDecimals: null or number tickDecimals: null or number
} }
The two axes have the same kind of options. The "mode" option The axes have the same kind of options. The "mode" option
determines how the data is interpreted, the default of null means as determines how the data is interpreted, the default of null means as
decimal numbers. Use "time" for time series data, see the next section. decimal numbers. Use "time" for time series data, see the next section.
...@@ -447,11 +454,11 @@ Customizing the grid ...@@ -447,11 +454,11 @@ Customizing the grid
clickable: boolean clickable: boolean
} }
The grid is the thing with the two axes and a number of ticks. "color" The grid is the thing with the axes and a number of ticks. "color"
is the color of the grid itself whereas "backgroundColor" specifies is the color of the grid itself whereas "backgroundColor" specifies
the background color inside the grid area. The default value of null the background color inside the grid area. The default value of null
means that the background is transparent. You should only need to set means that the background is transparent. You should only need to set
backgroundColor if want the grid area to be a different color from the backgroundColor if you want the grid area to be a different color from the
page color. Otherwise you might as well just set the background color page color. Otherwise you might as well just set the background color
of the page with CSS. of the page with CSS.
...@@ -488,18 +495,42 @@ An example function might look like this: ...@@ -488,18 +495,42 @@ An example function might look like this:
If you set "clickable" to true, the plot will listen for click events If you set "clickable" to true, the plot will listen for click events
on the plot area and fire a "plotclick" event on the placeholder with on the plot area and fire a "plotclick" event on the placeholder with
an object { x: number, y: number } as parameter when one occurs. The a position and a nearby data item object as parameters. The returned
returned coordinates will be in the unit of the plot (not in pixels). coordinates are in the unit of the axes (not in pixels).
You can use it like this:
If you set "hoverable" to true, the plot will listen for mouse move
events on the plot area and fire a "plothover" event with the same
parameters as the "plotclick" event.
You can use "plotclick" and "plothover" events like this:
$.plot($("#placeholder"), [ d ], { grid: { clickable: true } }); $.plot($("#placeholder"), [ d ], { grid: { clickable: true } });
$("#placeholder").bind("plotclick", function (e, pos) { $("#placeholder").bind("plotclick", function (event, pos, item) {
// the values are in pos.x and pos.y alert("You clicked at " + pos.x + ", " + pos.y);
// secondary axis coordinates if present are in pos.x2, pos.y2
}); });
Support for hover indications or for associating the clicks with any The item object in this example is either null or a nearby object on the form:
specific data is still forthcoming.
item: {
datapoint: the point as you specified it in the data, e.g. [0, 2]
dataIndex: the index of the point in the data array
series: the series object
seriesIndex: the index of the series
}
For instance, if you have specified the data like this
$.plot($("#placeholder"), [ { label: "Foo", data: [[0, 10], [7, 3]] } ], ...);
and the mouse is near the point (7, 3), "datapoint" is the [7, 3] we
specified, "dataIndex" will be 1, "series" is a normalized series
object with among other things the "Foo" label in series.label and the
color in series.color, and "seriesIndex" is 0.
Note that the detection of nearby points is still limited to points,
and support for highlighting the point or graph is still forthcoming.
Customizing the selection Customizing the selection
...@@ -515,12 +546,15 @@ You enable selection support by setting the mode to one of "x", "y" or ...@@ -515,12 +546,15 @@ You enable selection support by setting the mode to one of "x", "y" or
similarly for "y" mode. For "xy", the selection becomes a rectangle similarly for "y" mode. For "xy", the selection becomes a rectangle
where both ranges can be specified. "color" is color of the selection. where both ranges can be specified. "color" is color of the selection.
When selection support is enabled, a "selected" event will be emitted When selection support is enabled, a "plotselected" event will be emitted
on the DOM element you passed into the plot function. The event on the DOM element you passed into the plot function. The event
handler gets one extra parameter with the area selected, like this: handler gets one extra parameter with the ranges selected on the axes,
like this:
placeholder.bind("selected", function(event, area) { placeholder.bind("plotselected", function(event, ranges) {
// area selected is area.x1 to area.x2 and area.y1 to area.y2 alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
// similar for yaxis, secondary axes are in x2axis
// and y2axis if present
}); });
...@@ -534,18 +568,20 @@ members: ...@@ -534,18 +568,20 @@ members:
Clear the selection rectangle. Clear the selection rectangle.
- setSelection(area) - setSelection(ranges)
Set the selection rectangle. The passed in area should have the Set the selection rectangle. The passed in ranges is on the same
members x1 and x2 if the selection mode is "x" and y1 and y2 if form as returned in the "plotselected" event. If the selection
the selection mode is "y" and both x1, x2 and y1, y2 if the mode is "x", you should put in either an xaxis (or x2axis) object,
selection mode is "xy", like this: if the mode is "y" you need to put in an yaxis (or y2axis) object
and both xaxis/x2axis and yaxis/y2axis if the selection mode is
"xy", like this:
setSelection({ x1: 0, x2: 10, y1: 40, y2: 60}); setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
setSelection will trigger the "selected" event when called so you setSelection will trigger the "plotselected" event when called so you
may have to do a bit of shortcircuiting to prevent an eternal loop may have to do a bit of shortcircuiting to prevent an eternal loop
if you invoke the method inside the "selected" handler. if you invoke setSelection inside a "plotselected" handler.
- getCanvas() - getCanvas()
...@@ -580,7 +616,7 @@ members: ...@@ -580,7 +616,7 @@ members:
var series = plot.getData(); var series = plot.getData();
for (var i = 0; i < series.length; ++i) for (var i = 0; i < series.length; ++i)
alert([i].color); alert(series[i].color);
- setupGrid() - setupGrid()
......
Flot x.x Flot x.x
-------- --------
API changes: timestamps in time mode are now displayed according to Backwards API change summary: Timestamps are now in UTC. Also
"selected" event -> becomes "plotselected" with new data, the
parameters for setSelection are now different (but backwards
compatibility hooks are in place).
Interactivity: added a new "plothover" event and this and the
"plotclick" event now returns the closest data item (based on patch by
/david).
Timestamps in time mode are now displayed according to
UTC instead of the time zone of the visitor. This affects the way the UTC instead of the time zone of the visitor. This affects the way the
timestamps should be input; you'll probably have to offset the timestamps should be input; you'll probably have to offset the
timestamps according to your local time zone. It also affects any timestamps according to your local time zone. It also affects any
...@@ -9,6 +18,14 @@ custom date handling code (which basically now should use the ...@@ -9,6 +18,14 @@ custom date handling code (which basically now should use the
equivalent UTC date mehods, e.g. .setUTCMonth() instead of equivalent UTC date mehods, e.g. .setUTCMonth() instead of
.setMonth(). .setMonth().
Support for dual axis has been added (based on patch by someone who's
annoyed and /david). For each data series you can specify which axes
it belongs to, and there are two more axes, x2axis and y2axis, to
customize. This affects the "selected" event which has been renamed to
"plotselected" and spews out { xaxis: { from: -10, to: 20 } ... } and
setSelection in which the parameters are on a new form (backwards
compatible hooks are in place so old code shouldn't break).
Added support for specifying the size of tick labels (axis.labelWidth, Added support for specifying the size of tick labels (axis.labelWidth,
axis.labelHeight). Useful for specifying a max label size to keep axis.labelHeight). Useful for specifying a max label size to keep
multiple plots aligned. multiple plots aligned.
...@@ -26,7 +43,8 @@ sets. Prevent the possibility of eternal looping in tick calculations. ...@@ -26,7 +43,8 @@ sets. Prevent the possibility of eternal looping in tick calculations.
Fixed a bug when borderWidth is set to 0 (reported by Fixed a bug when borderWidth is set to 0 (reported by
Rob/sanchothefat). Fixed a bug with drawing bars extending below 0 Rob/sanchothefat). Fixed a bug with drawing bars extending below 0
(reported by James Hewitt, convenient patch by Ryan Funduk). Fixed a (reported by James Hewitt, convenient patch by Ryan Funduk). Fixed a
bug with line widths of bars (reported by MikeM). bug with line widths of bars (reported by MikeM). Fixed a bug with
'nw' and 'sw' legend positions.
Flot 0.4 Flot 0.4
......
...@@ -24,16 +24,13 @@ support for highlighting stuff ...@@ -24,16 +24,13 @@ support for highlighting stuff
legend legend
- interactive auto-highlight of graph? - interactive auto-highlight of graph?
- ability to specify noRows instead of just noColumns
labels labels
- labels on bars, data points - labels on bars, data points
- plan "all points" option - plain "all points" option
- interactive "label this point" command - interactive "label this point" command
interactive hover over
- fire event with value for points
- fire event with graph id for lines
error margin indicators error margin indicators
- for scientific/statistical purposes - for scientific/statistical purposes
......
<!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">
<title>Flot Examples</title>
<link href="layout.css" rel="stylesheet" type="text/css"></link>
<!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.pack.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../jquery.js"></script>
<script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
</head>
<body>
<h1>Flot Examples</h1>
<div id="placeholder" style="width:600px;height:300px;"></div>
<p>Dual axis support showing the raw oil price in US $/barrel of
crude oil (left axis) vs. the exchange rate from US $ to € (right
axis).</p>
<p>As illustrated, you can put in secondary y and x axes if you
need to. For each data series, simply specify the axis number.</p>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var oilprices = [[1167692400000,61.05], [1167778800000,58.32], [1167865200000,57.35], [1167951600000,56.31], [1168210800000,55.55], [1168297200000,55.64], [1168383600000,54.02], [1168470000000,51.88], [1168556400000,52.99], [1168815600000,52.99], [1168902000000,51.21], [1168988400000,52.24], [1169074800000,50.48], [1169161200000,51.99], [1169420400000,51.13], [1169506800000,55.04], [1169593200000,55.37], [1169679600000,54.23], [1169766000000,55.42], [1170025200000,54.01], [1170111600000,56.97], [1170198000000,58.14], [1170284400000,58.14], [1170370800000,59.02], [1170630000000,58.74], [1170716400000,58.88], [1170802800000,57.71], [1170889200000,59.71], [1170975600000,59.89], [1171234800000,57.81], [1171321200000,59.06], [1171407600000,58.00], [1171494000000,57.99], [1171580400000,59.39], [1171839600000,59.39], [1171926000000,58.07], [1172012400000,60.07], [1172098800000,61.14], [1172444400000,61.39], [1172530800000,61.46], [1172617200000,61.79], [1172703600000,62.00], [1172790000000,60.07], [1173135600000,60.69], [1173222000000,61.82], [1173308400000,60.05], [1173654000000,58.91], [1173740400000,57.93], [1173826800000,58.16], [1173913200000,57.55], [1173999600000,57.11], [1174258800000,56.59], [1174345200000,59.61], [1174518000000,61.69], [1174604400000,62.28], [1174860000000,62.91], [1174946400000,62.93], [1175032800000,64.03], [1175119200000,66.03], [1175205600000,65.87], [1175464800000,64.64], [1175637600000,64.38], [1175724000000,64.28], [1175810400000,64.28], [1176069600000,61.51], [1176156000000,61.89], [1176242400000,62.01], [1176328800000,63.85], [1176415200000,63.63], [1176674400000,63.61], [1176760800000,63.10], [1176847200000,63.13], [1176933600000,61.83], [1177020000000,63.38], [1177279200000,64.58], [1177452000000,65.84], [1177538400000,65.06], [1177624800000,66.46], [1177884000000,64.40], [1178056800000,63.68], [1178143200000,63.19], [1178229600000,61.93], [1178488800000,61.47], [1178575200000,61.55], [1178748000000,61.81], [1178834400000,62.37], [1179093600000,62.46], [1179180000000,63.17], [1179266400000,62.55], [1179352800000,64.94], [1179698400000,66.27], [1179784800000,65.50], [1179871200000,65.77], [1179957600000,64.18], [1180044000000,65.20], [1180389600000,63.15], [1180476000000,63.49], [1180562400000,65.08], [1180908000000,66.30], [1180994400000,65.96], [1181167200000,66.93], [1181253600000,65.98], [1181599200000,65.35], [1181685600000,66.26], [1181858400000,68.00], [1182117600000,69.09], [1182204000000,69.10], [1182290400000,68.19], [1182376800000,68.19], [1182463200000,69.14], [1182722400000,68.19], [1182808800000,67.77], [1182895200000,68.97], [1182981600000,69.57], [1183068000000,70.68], [1183327200000,71.09], [1183413600000,70.92], [1183586400000,71.81], [1183672800000,72.81], [1183932000000,72.19], [1184018400000,72.56], [1184191200000,72.50], [1184277600000,74.15], [1184623200000,75.05], [1184796000000,75.92], [1184882400000,75.57], [1185141600000,74.89], [1185228000000,73.56], [1185314400000,75.57], [1185400800000,74.95], [1185487200000,76.83], [1185832800000,78.21], [1185919200000,76.53], [1186005600000,76.86], [1186092000000,76.00], [1186437600000,71.59], [1186696800000,71.47], [1186956000000,71.62], [1187042400000,71.00], [1187301600000,71.98], [1187560800000,71.12], [1187647200000,69.47], [1187733600000,69.26], [1187820000000,69.83], [1187906400000,71.09], [1188165600000,71.73], [1188338400000,73.36], [1188511200000,74.04], [1188856800000,76.30], [1189116000000,77.49], [1189461600000,78.23], [1189548000000,79.91], [1189634400000,80.09], [1189720800000,79.10], [1189980000000,80.57], [1190066400000,81.93], [1190239200000,83.32], [1190325600000,81.62], [1190584800000,80.95], [1190671200000,79.53], [1190757600000,80.30], [1190844000000,82.88], [1190930400000,81.66], [1191189600000,80.24], [1191276000000,80.05], [1191362400000,79.94], [1191448800000,81.44], [1191535200000,81.22], [1191794400000,79.02], [1191880800000,80.26], [1191967200000,80.30], [1192053600000,83.08], [1192140000000,83.69], [1192399200000,86.13], [1192485600000,87.61], [1192572000000,87.40], [1192658400000,89.47], [1192744800000,88.60], [1193004000000,87.56], [1193090400000,87.56], [1193176800000,87.10], [1193263200000,91.86], [1193612400000,93.53], [1193698800000,94.53], [1193871600000,95.93], [1194217200000,93.98], [1194303600000,96.37], [1194476400000,95.46], [1194562800000,96.32], [1195081200000,93.43], [1195167600000,95.10], [1195426800000,94.64], [1195513200000,95.10], [1196031600000,97.70], [1196118000000,94.42], [1196204400000,90.62], [1196290800000,91.01], [1196377200000,88.71], [1196636400000,88.32], [1196809200000,90.23], [1196982000000,88.28], [1197241200000,87.86], [1197327600000,90.02], [1197414000000,92.25], [1197586800000,90.63], [1197846000000,90.63], [1197932400000,90.49], [1198018800000,91.24], [1198105200000,91.06], [1198191600000,90.49], [1198710000000,96.62], [1198796400000,96.00], [1199142000000,99.62], [1199314800000,99.18], [1199401200000,95.09], [1199660400000,96.33], [1199833200000,95.67], [1200351600000,91.90], [1200438000000,90.84], [1200524400000,90.13], [1200610800000,90.57], [1200956400000,89.21], [1201042800000,86.99], [1201129200000,89.85], [1201474800000,90.99], [1201561200000,91.64], [1201647600000,92.33], [1201734000000,91.75], [1202079600000,90.02], [1202166000000,88.41], [1202252400000,87.14], [1202338800000,88.11], [1202425200000,91.77], [1202770800000,92.78], [1202857200000,93.27], [1202943600000,95.46], [1203030000000,95.46], [1203289200000,101.74], [1203462000000,98.81], [1203894000000,100.88], [1204066800000,99.64], [1204153200000,102.59], [1204239600000,101.84], [1204498800000,99.52], [1204585200000,99.52], [1204671600000,104.52], [1204758000000,105.47], [1204844400000,105.15], [1205103600000,108.75], [1205276400000,109.92], [1205362800000,110.33], [1205449200000,110.21], [1205708400000,105.68], [1205967600000,101.84], [1206313200000,100.86], [1206399600000,101.22], [1206486000000,105.90], [1206572400000,107.58], [1206658800000,105.62], [1206914400000,101.58], [1207000800000,100.98], [1207173600000,103.83], [1207260000000,106.23], [1207605600000,108.50], [1207778400000,110.11], [1207864800000,110.14], [1208210400000,113.79], [1208296800000,114.93], [1208383200000,114.86], [1208728800000,117.48], [1208815200000,118.30], [1208988000000,116.06], [1209074400000,118.52], [1209333600000,118.75], [1209420000000,113.46], [1209592800000,112.52], [1210024800000,121.84], [1210111200000,123.53], [1210197600000,123.69], [1210543200000,124.23], [1210629600000,125.80], [1210716000000,126.29], [1211148000000,127.05], [1211320800000,129.07], [1211493600000,132.19], [1211839200000,128.85], [1212357600000,127.76], [1212703200000,138.54], [1212962400000,136.80], [1213135200000,136.38], [1213308000000,134.86], [1213653600000,134.01], [1213740000000,136.68], [1213912800000,135.65], [1214172000000,134.62], [1214258400000,134.62], [1214344800000,134.62], [1214431200000,139.64], [1214517600000,140.21], [1214776800000,140.00], [1214863200000,140.97], [1214949600000,143.57], [1215036000000,145.29], [1215381600000,141.37], [1215468000000,136.04], [1215727200000,146.40], [1215986400000,145.18], [1216072800000,138.74], [1216159200000,134.60], [1216245600000,129.29], [1216332000000,130.65], [1216677600000,127.95], [1216850400000,127.95], [1217282400000,122.19], [1217455200000,124.08], [1217541600000,125.10], [1217800800000,121.41], [1217887200000,119.17], [1217973600000,118.58], [1218060000000,120.02], [1218405600000,114.45], [1218492000000,113.01], [1218578400000,116.00], [1218751200000,113.77], [1219010400000,112.87], [1219096800000,114.53], [1219269600000,114.98], [1219356000000,114.98], [1219701600000,116.27], [1219788000000,118.15], [1219874400000,115.59], [1219960800000,115.46], [1220306400000,109.71], [1220392800000,109.35], [1220565600000,106.23], [1220824800000,106.34]];
var exchangerates = [[1167606000000,0.7580], [1167692400000,0.7580], [1167778800000,0.75470], [1167865200000,0.75490], [1167951600000,0.76130], [1168038000000,0.76550], [1168124400000,0.76930], [1168210800000,0.76940], [1168297200000,0.76880], [1168383600000,0.76780], [1168470000000,0.77080], [1168556400000,0.77270], [1168642800000,0.77490], [1168729200000,0.77410], [1168815600000,0.77410], [1168902000000,0.77320], [1168988400000,0.77270], [1169074800000,0.77370], [1169161200000,0.77240], [1169247600000,0.77120], [1169334000000,0.7720], [1169420400000,0.77210], [1169506800000,0.77170], [1169593200000,0.77040], [1169679600000,0.7690], [1169766000000,0.77110], [1169852400000,0.7740], [1169938800000,0.77450], [1170025200000,0.77450], [1170111600000,0.7740], [1170198000000,0.77160], [1170284400000,0.77130], [1170370800000,0.76780], [1170457200000,0.76880], [1170543600000,0.77180], [1170630000000,0.77180], [1170716400000,0.77280], [1170802800000,0.77290], [1170889200000,0.76980], [1170975600000,0.76850], [1171062000000,0.76810], [1171148400000,0.7690], [1171234800000,0.7690], [1171321200000,0.76980], [1171407600000,0.76990], [1171494000000,0.76510], [1171580400000,0.76130], [1171666800000,0.76160], [1171753200000,0.76140], [1171839600000,0.76140], [1171926000000,0.76070], [1172012400000,0.76020], [1172098800000,0.76110], [1172185200000,0.76220], [1172271600000,0.76150], [1172358000000,0.75980], [1172444400000,0.75980], [1172530800000,0.75920], [1172617200000,0.75730], [1172703600000,0.75660], [1172790000000,0.75670], [1172876400000,0.75910], [1172962800000,0.75820], [1173049200000,0.75850], [1173135600000,0.76130], [1173222000000,0.76310], [1173308400000,0.76150], [1173394800000,0.760], [1173481200000,0.76130], [1173567600000,0.76270], [1173654000000,0.76270], [1173740400000,0.76080], [1173826800000,0.75830], [1173913200000,0.75750], [1173999600000,0.75620], [1174086000000,0.7520], [1174172400000,0.75120], [1174258800000,0.75120], [1174345200000,0.75170], [1174431600000,0.7520], [1174518000000,0.75110], [1174604400000,0.7480], [1174690800000,0.75090], [1174777200000,0.75310], [1174860000000,0.75310], [1174946400000,0.75270], [1175032800000,0.74980], [1175119200000,0.74930], [1175205600000,0.75040], [1175292000000,0.750], [1175378400000,0.74910], [1175464800000,0.74910], [1175551200000,0.74850], [1175637600000,0.74840], [1175724000000,0.74920], [1175810400000,0.74710], [1175896800000,0.74590], [1175983200000,0.74770], [1176069600000,0.74770], [1176156000000,0.74830], [1176242400000,0.74580], [1176328800000,0.74480], [1176415200000,0.7430], [1176501600000,0.73990], [1176588000000,0.73950], [1176674400000,0.73950], [1176760800000,0.73780], [1176847200000,0.73820], [1176933600000,0.73620], [1177020000000,0.73550], [1177106400000,0.73480], [1177192800000,0.73610], [1177279200000,0.73610], [1177365600000,0.73650], [1177452000000,0.73620], [1177538400000,0.73310], [1177624800000,0.73390], [1177711200000,0.73440], [1177797600000,0.73270], [1177884000000,0.73270], [1177970400000,0.73360], [1178056800000,0.73330], [1178143200000,0.73590], [1178229600000,0.73590], [1178316000000,0.73720], [1178402400000,0.7360], [1178488800000,0.7360], [1178575200000,0.7350], [1178661600000,0.73650], [1178748000000,0.73840], [1178834400000,0.73950], [1178920800000,0.74130], [1179007200000,0.73970], [1179093600000,0.73960], [1179180000000,0.73850], [1179266400000,0.73780], [1179352800000,0.73660], [1179439200000,0.740], [1179525600000,0.74110], [1179612000000,0.74060], [1179698400000,0.74050], [1179784800000,0.74140], [1179871200000,0.74310], [1179957600000,0.74310], [1180044000000,0.74380], [1180130400000,0.74430], [1180216800000,0.74430], [1180303200000,0.74430], [1180389600000,0.74340], [1180476000000,0.74290], [1180562400000,0.74420], [1180648800000,0.7440], [1180735200000,0.74390], [1180821600000,0.74370], [1180908000000,0.74370], [1180994400000,0.74290], [1181080800000,0.74030], [1181167200000,0.73990], [1181253600000,0.74180], [1181340000000,0.74680], [1181426400000,0.7480], [1181512800000,0.7480], [1181599200000,0.7490], [1181685600000,0.74940], [1181772000000,0.75220], [1181858400000,0.75150], [1181944800000,0.75020], [1182031200000,0.74720], [1182117600000,0.74720], [1182204000000,0.74620], [1182290400000,0.74550], [1182376800000,0.74490], [1182463200000,0.74670], [1182549600000,0.74580], [1182636000000,0.74270], [1182722400000,0.74270], [1182808800000,0.7430], [1182895200000,0.74290], [1182981600000,0.7440], [1183068000000,0.7430], [1183154400000,0.74220], [1183240800000,0.73880], [1183327200000,0.73880], [1183413600000,0.73690], [1183500000000,0.73450], [1183586400000,0.73450], [1183672800000,0.73450], [1183759200000,0.73520], [1183845600000,0.73410], [1183932000000,0.73410], [1184018400000,0.7340], [1184104800000,0.73240], [1184191200000,0.72720], [1184277600000,0.72640], [1184364000000,0.72550], [1184450400000,0.72580], [1184536800000,0.72580], [1184623200000,0.72560], [1184709600000,0.72570], [1184796000000,0.72470], [1184882400000,0.72430], [1184968800000,0.72440], [1185055200000,0.72350], [1185141600000,0.72350], [1185228000000,0.72350], [1185314400000,0.72350], [1185400800000,0.72620], [1185487200000,0.72880], [1185573600000,0.73010], [1185660000000,0.73370], [1185746400000,0.73370], [1185832800000,0.73240], [1185919200000,0.72970], [1186005600000,0.73170], [1186092000000,0.73150], [1186178400000,0.72880], [1186264800000,0.72630], [1186351200000,0.72630], [1186437600000,0.72420], [1186524000000,0.72530], [1186610400000,0.72640], [1186696800000,0.7270], [1186783200000,0.73120], [1186869600000,0.73050], [1186956000000,0.73050], [1187042400000,0.73180], [1187128800000,0.73580], [1187215200000,0.74090], [1187301600000,0.74540], [1187388000000,0.74370], [1187474400000,0.74240], [1187560800000,0.74240], [1187647200000,0.74150], [1187733600000,0.74190], [1187820000000,0.74140], [1187906400000,0.73770], [1187992800000,0.73550], [1188079200000,0.73150], [1188165600000,0.73150], [1188252000000,0.7320], [1188338400000,0.73320], [1188424800000,0.73460], [1188511200000,0.73280], [1188597600000,0.73230], [1188684000000,0.7340], [1188770400000,0.7340], [1188856800000,0.73360], [1188943200000,0.73510], [1189029600000,0.73460], [1189116000000,0.73210], [1189202400000,0.72940], [1189288800000,0.72660], [1189375200000,0.72660], [1189461600000,0.72540], [1189548000000,0.72420], [1189634400000,0.72130], [1189720800000,0.71970], [1189807200000,0.72090], [1189893600000,0.7210], [1189980000000,0.7210], [1190066400000,0.7210], [1190152800000,0.72090], [1190239200000,0.71590], [1190325600000,0.71330], [1190412000000,0.71050], [1190498400000,0.70990], [1190584800000,0.70990], [1190671200000,0.70930], [1190757600000,0.70930], [1190844000000,0.70760], [1190930400000,0.7070], [1191016800000,0.70490], [1191103200000,0.70120], [1191189600000,0.70110], [1191276000000,0.70190], [1191362400000,0.70460], [1191448800000,0.70630], [1191535200000,0.70890], [1191621600000,0.70770], [1191708000000,0.70770], [1191794400000,0.70770], [1191880800000,0.70910], [1191967200000,0.71180], [1192053600000,0.70790], [1192140000000,0.70530], [1192226400000,0.7050], [1192312800000,0.70550], [1192399200000,0.70550], [1192485600000,0.70450], [1192572000000,0.70510], [1192658400000,0.70510], [1192744800000,0.70170], [1192831200000,0.70], [1192917600000,0.69950], [1193004000000,0.69940], [1193090400000,0.70140], [1193176800000,0.70360], [1193263200000,0.70210], [1193349600000,0.70020], [1193436000000,0.69670], [1193522400000,0.6950], [1193612400000,0.6950], [1193698800000,0.69390], [1193785200000,0.6940], [1193871600000,0.69220], [1193958000000,0.69190], [1194044400000,0.69140], [1194130800000,0.68940], [1194217200000,0.68910], [1194303600000,0.69040], [1194390000000,0.6890], [1194476400000,0.68340], [1194562800000,0.68230], [1194649200000,0.68070], [1194735600000,0.68150], [1194822000000,0.68150], [1194908400000,0.68470], [1194994800000,0.68590], [1195081200000,0.68220], [1195167600000,0.68270], [1195254000000,0.68370], [1195340400000,0.68230], [1195426800000,0.68220], [1195513200000,0.68220], [1195599600000,0.67920], [1195686000000,0.67460], [1195772400000,0.67350], [1195858800000,0.67310], [1195945200000,0.67420], [1196031600000,0.67440], [1196118000000,0.67390], [1196204400000,0.67310], [1196290800000,0.67610], [1196377200000,0.67610], [1196463600000,0.67850], [1196550000000,0.68180], [1196636400000,0.68360], [1196722800000,0.68230], [1196809200000,0.68050], [1196895600000,0.67930], [1196982000000,0.68490], [1197068400000,0.68330], [1197154800000,0.68250], [1197241200000,0.68250], [1197327600000,0.68160], [1197414000000,0.67990], [1197500400000,0.68130], [1197586800000,0.68090], [1197673200000,0.68680], [1197759600000,0.69330], [1197846000000,0.69330], [1197932400000,0.69450], [1198018800000,0.69440], [1198105200000,0.69460], [1198191600000,0.69640], [1198278000000,0.69650], [1198364400000,0.69560], [1198450800000,0.69560], [1198537200000,0.6950], [1198623600000,0.69480], [1198710000000,0.69280], [1198796400000,0.68870], [1198882800000,0.68240], [1198969200000,0.67940], [1199055600000,0.67940], [1199142000000,0.68030], [1199228400000,0.68550], [1199314800000,0.68240], [1199401200000,0.67910], [1199487600000,0.67830], [1199574000000,0.67850], [1199660400000,0.67850], [1199746800000,0.67970], [1199833200000,0.680], [1199919600000,0.68030], [1200006000000,0.68050], [1200092400000,0.6760], [1200178800000,0.6770], [1200265200000,0.6770], [1200351600000,0.67360], [1200438000000,0.67260], [1200524400000,0.67640], [1200610800000,0.68210], [1200697200000,0.68310], [1200783600000,0.68420], [1200870000000,0.68420], [1200956400000,0.68870], [1201042800000,0.69030], [1201129200000,0.68480], [1201215600000,0.68240], [1201302000000,0.67880], [1201388400000,0.68140], [1201474800000,0.68140], [1201561200000,0.67970], [1201647600000,0.67690], [1201734000000,0.67650], [1201820400000,0.67330], [1201906800000,0.67290], [1201993200000,0.67580], [1202079600000,0.67580], [1202166000000,0.6750], [1202252400000,0.6780], [1202338800000,0.68330], [1202425200000,0.68560], [1202511600000,0.69030], [1202598000000,0.68960], [1202684400000,0.68960], [1202770800000,0.68820], [1202857200000,0.68790], [1202943600000,0.68620], [1203030000000,0.68520], [1203116400000,0.68230], [1203202800000,0.68130], [1203289200000,0.68130], [1203375600000,0.68220], [1203462000000,0.68020], [1203548400000,0.68020], [1203634800000,0.67840], [1203721200000,0.67480], [1203807600000,0.67470], [1203894000000,0.67470], [1203980400000,0.67480], [1204066800000,0.67330], [1204153200000,0.6650], [1204239600000,0.66110], [1204326000000,0.65830], [1204412400000,0.6590], [1204498800000,0.6590], [1204585200000,0.65810], [1204671600000,0.65780], [1204758000000,0.65740], [1204844400000,0.65320], [1204930800000,0.65020], [1205017200000,0.65140], [1205103600000,0.65140], [1205190000000,0.65070], [1205276400000,0.6510], [1205362800000,0.64890], [1205449200000,0.64240], [1205535600000,0.64060], [1205622000000,0.63820], [1205708400000,0.63820], [1205794800000,0.63410], [1205881200000,0.63440], [1205967600000,0.63780], [1206054000000,0.64390], [1206140400000,0.64780], [1206226800000,0.64810], [1206313200000,0.64810], [1206399600000,0.64940], [1206486000000,0.64380], [1206572400000,0.63770], [1206658800000,0.63290], [1206745200000,0.63360], [1206831600000,0.63330], [1206914400000,0.63330], [1207000800000,0.6330], [1207087200000,0.63710], [1207173600000,0.64030], [1207260000000,0.63960], [1207346400000,0.63640], [1207432800000,0.63560], [1207519200000,0.63560], [1207605600000,0.63680], [1207692000000,0.63570], [1207778400000,0.63540], [1207864800000,0.6320], [1207951200000,0.63320], [1208037600000,0.63280], [1208124000000,0.63310], [1208210400000,0.63420], [1208296800000,0.63210], [1208383200000,0.63020], [1208469600000,0.62780], [1208556000000,0.63080], [1208642400000,0.63240], [1208728800000,0.63240], [1208815200000,0.63070], [1208901600000,0.62770], [1208988000000,0.62690], [1209074400000,0.63350], [1209160800000,0.63920], [1209247200000,0.640], [1209333600000,0.64010], [1209420000000,0.63960], [1209506400000,0.64070], [1209592800000,0.64230], [1209679200000,0.64290], [1209765600000,0.64720], [1209852000000,0.64850], [1209938400000,0.64860], [1210024800000,0.64670], [1210111200000,0.64440], [1210197600000,0.64670], [1210284000000,0.65090], [1210370400000,0.64780], [1210456800000,0.64610], [1210543200000,0.64610], [1210629600000,0.64680], [1210716000000,0.64490], [1210802400000,0.6470], [1210888800000,0.64610], [1210975200000,0.64520], [1211061600000,0.64220], [1211148000000,0.64220], [1211234400000,0.64250], [1211320800000,0.64140], [1211407200000,0.63660], [1211493600000,0.63460], [1211580000000,0.6350], [1211666400000,0.63460], [1211752800000,0.63460], [1211839200000,0.63430], [1211925600000,0.63460], [1212012000000,0.63790], [1212098400000,0.64160], [1212184800000,0.64420], [1212271200000,0.64310], [1212357600000,0.64310], [1212444000000,0.64350], [1212530400000,0.6440], [1212616800000,0.64730], [1212703200000,0.64690], [1212789600000,0.63860], [1212876000000,0.63560], [1212962400000,0.6340], [1213048800000,0.63460], [1213135200000,0.6430], [1213221600000,0.64520], [1213308000000,0.64670], [1213394400000,0.65060], [1213480800000,0.65040], [1213567200000,0.65030], [1213653600000,0.64810], [1213740000000,0.64510], [1213826400000,0.6450], [1213912800000,0.64410], [1213999200000,0.64140], [1214085600000,0.64090], [1214172000000,0.64090], [1214258400000,0.64280], [1214344800000,0.64310], [1214431200000,0.64180], [1214517600000,0.63710], [1214604000000,0.63490], [1214690400000,0.63330], [1214776800000,0.63340], [1214863200000,0.63380], [1214949600000,0.63420], [1215036000000,0.6320], [1215122400000,0.63180], [1215208800000,0.6370], [1215295200000,0.63680], [1215381600000,0.63680], [1215468000000,0.63830], [1215554400000,0.63710], [1215640800000,0.63710], [1215727200000,0.63550], [1215813600000,0.6320], [1215900000000,0.62770], [1215986400000,0.62760], [1216072800000,0.62910], [1216159200000,0.62740], [1216245600000,0.62930], [1216332000000,0.63110], [1216418400000,0.6310], [1216504800000,0.63120], [1216591200000,0.63120], [1216677600000,0.63040], [1216764000000,0.62940], [1216850400000,0.63480], [1216936800000,0.63780], [1217023200000,0.63680], [1217109600000,0.63680], [1217196000000,0.63680], [1217282400000,0.6360], [1217368800000,0.6370], [1217455200000,0.64180], [1217541600000,0.64110], [1217628000000,0.64350], [1217714400000,0.64270], [1217800800000,0.64270], [1217887200000,0.64190], [1217973600000,0.64460], [1218060000000,0.64680], [1218146400000,0.64870], [1218232800000,0.65940], [1218319200000,0.66660], [1218405600000,0.66660], [1218492000000,0.66780], [1218578400000,0.67120], [1218664800000,0.67050], [1218751200000,0.67180], [1218837600000,0.67840], [1218924000000,0.68110], [1219010400000,0.68110], [1219096800000,0.67940], [1219183200000,0.68040], [1219269600000,0.67810], [1219356000000,0.67560], [1219442400000,0.67350], [1219528800000,0.67630], [1219615200000,0.67620], [1219701600000,0.67770], [1219788000000,0.68150], [1219874400000,0.68020], [1219960800000,0.6780], [1220047200000,0.67960], [1220133600000,0.68170], [1220220000000,0.68170], [1220306400000,0.68320], [1220392800000,0.68770], [1220479200000,0.69120], [1220565600000,0.69140], [1220652000000,0.70090], [1220738400000,0.70120], [1220824800000,0.7010], [1220911200000,0.70050]];
$.plot($("#placeholder"),
[ { data: oilprices, label: "Oil price ($)" },
{ data: exchangerates, label: "USD/EUR exchange rate", yaxis: 2 }],
{ xaxis: { mode: 'time' },
yaxis: { min: 0 },
y2axis: { tickFormatter: function (v, axis) { return v.toFixed(axis.tickDecimals) +"€" }},
legend: { position: 'sw' } });
});
</script>
</body>
</html>
...@@ -15,13 +15,11 @@ ...@@ -15,13 +15,11 @@
<ul> <ul>
<li><a href="basic.html">Basic example</a></li> <li><a href="basic.html">Basic example</a></li>
<li><a href="graph-types.html">Different graph types</a></li> <li><a href="graph-types.html">Different graph types</a> and <a href="setting-options.html">setting various options</a></li>
<li><a href="setting-options.html">Setting various options</a></li> <li><a href="turning-series.html">Turning series on/off</a></li>
<li><a href="real-data.html">Real data with a bit of interactivity</a></li> <li><a href="selection.html">Selection support and zooming</a> and <a href="zooming.html">zooming with overview</a></li>
<li><a href="selection.html">Selection support and zooming</a></li> <li><a href="time.html">Plotting time series</a> and <a href="visitors.html">visitors per day with zooming and weekends</a></li>
<li><a href="zooming.html">Zooming with overview</a></li> <li><a href="dual-axis.html">Dual axis support</a></li>
<li><a href="time.html">Plotting time series</a></li>
<li><a href="visitors.html">Visitors per day with zooming and weekends</a></li>
<li><a href="interacting.html">Interacting with the data</a></li> <li><a href="interacting.html">Interacting with the data</a></li>
</ul> </ul>
</body> </body>
......
...@@ -13,23 +13,47 @@ ...@@ -13,23 +13,47 @@
<div id="placeholder" style="width:600px;height:300px"></div> <div id="placeholder" style="width:600px;height:300px"></div>
<p>Flot supports user interactions. It's currently still a bit <p>One of the goals of Flot is to support user interactions intelligently.
primitive, but you can enable the user to click on the plot and Try hovering over the graph above and clicking on the points (note that support for highlighting the points is still missing).</p>
get the corresponding x and y values back.</p>
<p>Try clicking on the plot above. <span id="result"></span></p> <p id="clickdata"></p>
<p id="hoverdata" style="display:none">Mouse hovers at
(<span id="x"></span>, <span id="y"></span>).<br>
Nearby item: <span id="nearby"></span>.</p>
<script id="source" language="javascript" type="text/javascript"> <script id="source" language="javascript" type="text/javascript">
$(function () { $(function () {
var d = []; var sin = [], cos = [];
for (var i = 0; i < 14; i += 0.5) for (var i = 0; i < 14; i += 0.5) {
d.push([i, Math.sin(i)]); sin.push([i, Math.sin(i)]);
cos.push([i, Math.cos(i)]);
}
$.plot($("#placeholder"),
[ { data: sin, label: "sin(x)"}, { data: cos, label: "cos(x)" } ],
{ lines: { show: true },
points: { show: true },
grid: { hoverable: true, clickable: true } });
$("#placeholder").bind("plothover", function (event, pos, item) {
$("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2));
$.plot($("#placeholder"), [ d ], { grid: { clickable: true } }); var nearby = "none";
if (item)
nearby = "point " + item.dataIndex + " in " + item.series.label + " at (" + item.datapoint[0].toFixed(2) + ", " + item.datapoint[1].toFixed(2) + ")";
$("#nearby").text(nearby);
$("#hoverdata").show();
});
$("#placeholder").bind("plotclick", function (e, pos) { $("#placeholder").bind("plotclick", function (event, pos, item) {
// the values are in pos.x and pos.y if (item) {
$("#result").text('You clicked on (' + pos.x.toFixed(2) + ', ' + pos.y.toFixed(2) + ')'); var x = item.datapoint[0].toFixed(2);
var y = item.datapoint[1].toFixed(2);
$("#clickdata").text(item.series.label + " of " + x + " = " + y);
}
}); });
}); });
</script> </script>
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<p>Selections are really useful for zooming. Just replot the <p>Selections are really useful for zooming. Just replot the
chart with min and max values for the axes set to the values chart with min and max values for the axes set to the values
in the "selected" event triggered. Try enabling the checkbox in the "plotselected" event triggered. Try enabling the checkbox
below and select a region again.</p> below and select a region again.</p>
<p><input id="zoom" type="checkbox">Zoom to selection.</input></p> <p><input id="zoom" type="checkbox">Zoom to selection.</input></p>
...@@ -80,14 +80,14 @@ $(function () { ...@@ -80,14 +80,14 @@ $(function () {
var placeholder = $("#placeholder"); var placeholder = $("#placeholder");
placeholder.bind("selected", function (event, area) { placeholder.bind("plotselected", function (event, ranges) {
$("#selection").text(area.x1.toFixed(1) + " to " + area.x2.toFixed(1)); $("#selection").text(ranges.xaxis.from.toFixed(1) + " to " + ranges.xaxis.to.toFixed(1));
var zoom = $("#zoom").attr("checked"); var zoom = $("#zoom").attr("checked");
if (zoom) if (zoom)
plot = $.plot(placeholder, data, plot = $.plot(placeholder, data,
$.extend(true, {}, options, { $.extend(true, {}, options, {
xaxis: { min: area.x1, max: area.x2 } xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
})); }));
}); });
......
...@@ -67,25 +67,25 @@ $(function () { ...@@ -67,25 +67,25 @@ $(function () {
// now connect the two // now connect the two
var internalSelection = false; var internalSelection = false;
$("#placeholder").bind("selected", function (event, area) { $("#placeholder").bind("plotselected", function (event, ranges) {
// do the zooming // do the zooming
plot = $.plot($("#placeholder"), [d], plot = $.plot($("#placeholder"), [d],
$.extend(true, {}, options, { $.extend(true, {}, options, {
xaxis: { min: area.x1, max: area.x2 } xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
})); }));
if (internalSelection) if (internalSelection)
return; // prevent eternal loop return; // prevent eternal loop
internalSelection = true; internalSelection = true;
overview.setSelection(area); overview.setSelection(ranges);
internalSelection = false; internalSelection = false;
}); });
$("#overview").bind("selected", function (event, area) { $("#overview").bind("plotselected", function (event, ranges) {
if (internalSelection) if (internalSelection)
return; return;
internalSelection = true; internalSelection = true;
plot.setSelection(area); plot.setSelection(ranges);
internalSelection = false; internalSelection = false;
}); });
}); });
......
...@@ -65,31 +65,31 @@ $(function () { ...@@ -65,31 +65,31 @@ $(function () {
// now connect the two // now connect the two
var internalSelection = false; var internalSelection = false;
$("#placeholder").bind("selected", function (event, area) { $("#placeholder").bind("plotselected", function (event, ranges) {
// clamp the zooming to prevent eternal zoom // clamp the zooming to prevent eternal zoom
if (area.x2 - area.x1 < 0.00001) if (ranges.xaxis.to - ranges.xaxis.from < 0.00001)
area.x2 = area.x1 + 0.00001; ranges.xaxis.to = ranges.xaxis.from + 0.00001;
if (area.y2 - area.y1 < 0.00001) if (ranges.yaxis.to - ranges.yaxis.from < 0.00001)
area.y2 = area.y1 + 0.00001; ranges.yaxis.to = ranges.yaxis.from + 0.00001;
// do the zooming // do the zooming
plot = $.plot($("#placeholder"), getData(area.x1, area.x2), plot = $.plot($("#placeholder"), getData(ranges.xaxis.from, ranges.xaxis.to),
$.extend(true, {}, options, { $.extend(true, {}, options, {
xaxis: { min: area.x1, max: area.x2 }, xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
yaxis: { min: area.y1, max: area.y2 } yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
})); }));
if (internalSelection) if (internalSelection)
return; // prevent eternal loop return; // prevent eternal loop
internalSelection = true; internalSelection = true;
overview.setSelection(area); overview.setSelection(ranges);
internalSelection = false; internalSelection = false;
}); });
$("#overview").bind("selected", function (event, area) { $("#overview").bind("plotselected", function (event, ranges) {
if (internalSelection) if (internalSelection)
return; return;
internalSelection = true; internalSelection = true;
plot.setSelection(area); plot.setSelection(ranges);
internalSelection = false; internalSelection = false;
}); });
}); });
......
...@@ -46,6 +46,12 @@ ...@@ -46,6 +46,12 @@
yaxis: { yaxis: {
autoscaleMargin: 0.02 autoscaleMargin: 0.02
}, },
x2axis: {
autoscaleMargin: null
},
y2axis: {
autoscaleMargin: 0.02
},
points: { points: {
show: false, show: false,
radius: 3, radius: 3,
...@@ -72,7 +78,9 @@ ...@@ -72,7 +78,9 @@
tickColor: "#dddddd", // color used for the ticks tickColor: "#dddddd", // color used for the ticks
labelMargin: 3, // in pixels labelMargin: 3, // in pixels
borderWidth: 2, borderWidth: 2,
clickable: null, clickable: false,
hoverable: false,
mouseCatchingArea: 30,
coloredAreas: null, // array of { x1, y1, x2, y2 } or fn: plot area -> areas coloredAreas: null, // array of { x1, y1, x2, y2 } or fn: plot area -> areas
coloredAreasColor: "#f4f4f4" coloredAreasColor: "#f4f4f4"
}, },
...@@ -86,10 +94,10 @@ ...@@ -86,10 +94,10 @@
ctx = null, octx = null, ctx = null, octx = null,
target = target_, target = target_,
xaxis = {}, yaxis = {}, xaxis = {}, yaxis = {},
x2axis = {}, y2axis = {},
plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
canvasWidth = 0, canvasHeight = 0, canvasWidth = 0, canvasHeight = 0,
plotWidth = 0, plotHeight = 0, plotWidth = 0, plotHeight = 0,
hozScale = 0, vertScale = 0,
// dedicated to storing data for buggy standard compliance cases // dedicated to storing data for buggy standard compliance cases
workarounds = {}; workarounds = {};
...@@ -101,7 +109,7 @@ ...@@ -101,7 +109,7 @@
this.getCanvas = function() { return canvas; }; this.getCanvas = function() { return canvas; };
this.getPlotOffset = function() { return plotOffset; }; this.getPlotOffset = function() { return plotOffset; };
this.getData = function() { return series; }; this.getData = function() { return series; };
this.getAxes = function() { return { xaxis: xaxis, yaxis: yaxis }; }; this.getAxes = function() { return { xaxis: xaxis, yaxis: yaxis, x2axis: x2axis, y2axis: y2axis }; };
// initialize // initialize
parseOptions(options_); parseOptions(options_);
...@@ -216,6 +224,14 @@ ...@@ -216,6 +224,14 @@
s.bars = $.extend(true, {}, options.bars, s.bars); s.bars = $.extend(true, {}, options.bars, s.bars);
if (s.shadowSize == null) if (s.shadowSize == null)
s.shadowSize = options.shadowSize; s.shadowSize = options.shadowSize;
if (s.xaxis && s.xaxis == 2)
s.xaxis = x2axis;
else
s.xaxis = xaxis;
if (s.yaxis && s.yaxis == 2)
s.yaxis = y2axis;
else
s.yaxis = yaxis;
} }
} }
...@@ -223,11 +239,15 @@ ...@@ -223,11 +239,15 @@
var top_sentry = Number.POSITIVE_INFINITY, var top_sentry = Number.POSITIVE_INFINITY,
bottom_sentry = Number.NEGATIVE_INFINITY; bottom_sentry = Number.NEGATIVE_INFINITY;
xaxis.datamin = yaxis.datamin = top_sentry; xaxis.datamin = yaxis.datamin = x2axis.datamin = y2axis.datamin = top_sentry;
xaxis.datamax = yaxis.datamax = bottom_sentry; xaxis.datamax = yaxis.datamax = x2axis.datamax = y2axis.datamax = bottom_sentry;
xaxis.used = yaxis.used = x2axis.used = y2axis.used = false;
for (var i = 0; i < series.length; ++i) { for (var i = 0; i < series.length; ++i) {
var data = series[i].data; var data = series[i].data,
axisx = series[i].xaxis,
axisy = series[i].yaxis;
for (var j = 0; j < data.length; ++j) { for (var j = 0; j < data.length; ++j) {
if (data[j] == null) if (data[j] == null)
continue; continue;
...@@ -240,25 +260,29 @@ ...@@ -240,25 +260,29 @@
continue; continue;
} }
if (x < xaxis.datamin) if (x < axisx.datamin)
xaxis.datamin = x; axisx.datamin = x;
if (x > xaxis.datamax) if (x > axisx.datamax)
xaxis.datamax = x; axisx.datamax = x;
if (y < yaxis.datamin) if (y < axisy.datamin)
yaxis.datamin = y; axisy.datamin = y;
if (y > yaxis.datamax) if (y > axisy.datamax)
yaxis.datamax = y; axisy.datamax = y;
axisx.used = axisy.used = true;
}
} }
function setDefaultMinMax(axis) {
if (axis.datamin == top_sentry)
axis.datamin = 0;
if (axis.datamax == bottom_sentry)
axis.datamax = 1;
} }
if (xaxis.datamin == top_sentry) setDefaultMinMax(xaxis);
xaxis.datamin = 0; setDefaultMinMax(yaxis);
if (yaxis.datamin == top_sentry) setDefaultMinMax(x2axis);
yaxis.datamin = 0; setDefaultMinMax(y2axis);
if (xaxis.datamax == bottom_sentry)
xaxis.datamax = 1;
if (yaxis.datamax == bottom_sentry)
yaxis.datamax = 1;
} }
function constructCanvas() { function constructCanvas() {
...@@ -286,15 +310,15 @@ ...@@ -286,15 +310,15 @@
// sometimes has trouble with the stacking order // sometimes has trouble with the stacking order
eventHolder = $([overlay, canvas]); eventHolder = $([overlay, canvas]);
// bind events // bind events
if (options.selection.mode != null) { if (options.selection.mode != null || options.grid.hoverable) {
eventHolder.mousedown(onMouseDown);
// FIXME: temp. work-around until jQuery bug 1871 is fixed // FIXME: temp. work-around until jQuery bug 1871 is fixed
eventHolder.each(function () { eventHolder.each(function () {
this.onmousemove = onMouseMove; this.onmousemove = onMouseMove;
}); });
if (options.selection.mode != null)
eventHolder.mousedown(onMouseDown);
} }
if (options.grid.clickable) if (options.grid.clickable)
...@@ -302,16 +326,42 @@ ...@@ -302,16 +326,42 @@
} }
function setupGrid() { function setupGrid() {
// x axis function setupAxis(axis, options) {
setRange(xaxis, options.xaxis); setRange(axis, options);
prepareTickGeneration(xaxis, options.xaxis); prepareTickGeneration(axis, options);
setTicks(xaxis, options.xaxis); setTicks(axis, options);
extendXRangeIfNeededByBar(); // add transformation helpers
if (axis == xaxis || axis == x2axis) {
// data point to canvas coordinate
axis.p2c = function (p) { return (p - axis.min) * axis.scale; };
// canvas coordinate to data point
axis.c2p = function (c) { return axis.min + c / axis.scale; };
}
else {
axis.p2c = function (p) { return (axis.max - p) * axis.scale; };
axis.c2p = function (p) { return axis.max - p / axis.scale; };
}
}
// y axis function extendXRangeIfNeededByBar(axis, options) {
setRange(yaxis, options.yaxis); // extend x range so end bar graph won't be drawn on the chart border
prepareTickGeneration(yaxis, options.yaxis); if (options.max == null) {
setTicks(yaxis, options.yaxis); // great, we're autoscaling, check if we might need a bump
var newmax = axis.max;
for (var i = 0; i < series.length; ++i)
if (series[i].bars.show && series[i].bars.barWidth + axis.datamax > newmax)
newmax = axis.datamax + series[i].bars.barWidth;
axis.max = newmax;
}
}
setupAxis(xaxis, options.xaxis);
extendXRangeIfNeededByBar(xaxis,options.xaxis);
setupAxis(yaxis, options.yaxis);
setupAxis(x2axis, options.x2axis);
extendXRangeIfNeededByBar(x2axis, options.x2axis);
setupAxis(y2axis, options.y2axis);
setSpacing(); setSpacing();
insertLabels(); insertLabels();
...@@ -360,7 +410,7 @@ ...@@ -360,7 +410,7 @@
var noTicks; var noTicks;
if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0) if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0)
noTicks = axisOptions.ticks; noTicks = axisOptions.ticks;
else if (axis == xaxis) else if (axis == xaxis || axis == x2axis)
noTicks = canvasWidth / 100; noTicks = canvasWidth / 100;
else else
noTicks = canvasHeight / 60; noTicks = canvasHeight / 60;
...@@ -604,9 +654,13 @@ ...@@ -604,9 +654,13 @@
generator = function (axis) { generator = function (axis) {
var ticks = []; var ticks = [];
var start = floorInBase(axis.min, axis.tickSize);
// then spew out all possible ticks if (axis.min == null) // FIXME
var i = 0, v = Number.NaN, prev; return ticks;
// spew out all possible ticks
var start = floorInBase(axis.min, axis.tickSize),
i = 0, v = Number.NaN, prev;
do { do {
prev = v; prev = v;
v = start + i * axis.tickSize; v = start + i * axis.tickSize;
...@@ -633,21 +687,12 @@ ...@@ -633,21 +687,12 @@
axis.labelHeight = axisOptions.labelHeight; axis.labelHeight = axisOptions.labelHeight;
} }
function extendXRangeIfNeededByBar() {
if (options.xaxis.max == null) {
// great, we're autoscaling, check if we might need a bump
var newmax = xaxis.max;
for (var i = 0; i < series.length; ++i)
if (series[i].bars.show && series[i].bars.barWidth + xaxis.datamax > newmax)
newmax = xaxis.datamax + series[i].bars.barWidth;
xaxis.max = newmax;
}
}
function setTicks(axis, axisOptions) { function setTicks(axis, axisOptions) {
axis.ticks = []; axis.ticks = [];
if (!axis.used)
return;
if (axisOptions.ticks == null) if (axisOptions.ticks == null)
axis.ticks = axis.tickGenerator(axis); axis.ticks = axis.tickGenerator(axis);
else if (typeof axisOptions.ticks == "number") { else if (typeof axisOptions.ticks == "number") {
...@@ -689,11 +734,39 @@ ...@@ -689,11 +734,39 @@
} }
function setSpacing() { function setSpacing() {
function measureXLabels(axis) {
// to avoid measuring the widths of the labels, we
// construct fixed-size boxes and put the labels inside
// them, we don't need the exact figures and the
// fixed-size box content is easy to center
if (axis.labelWidth == null)
axis.labelWidth = canvasWidth / 6;
// measure x label heights
if (axis.labelHeight == null) {
labels = [];
for (i = 0; i < axis.ticks.length; ++i) {
l = axis.ticks[i].label;
if (l)
labels.push('<span class="tickLabel" width="' + axis.labelWidth + '">' + l + '</span>');
}
axis.labelHeight = 0;
if (labels.length > 0) {
var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">'
+ labels.join("") + '</div>').appendTo(target);
axis.labelHeight = dummyDiv.height();
dummyDiv.remove();
}
}
}
function measureYLabels(axis) {
if (axis.labelWidth == null || axis.labelHeight == null) {
var i, labels = [], l; var i, labels = [], l;
if (yaxis.labelWidth == null || yaxis.labelHeight == null) {
// calculate y label dimensions // calculate y label dimensions
for (i = 0; i < yaxis.ticks.length; ++i) { for (i = 0; i < axis.ticks.length; ++i) {
l = yaxis.ticks[i].label; l = axis.ticks[i].label;
if (l) if (l)
labels.push('<div class="tickLabel">' + l + '</div>'); labels.push('<div class="tickLabel">' + l + '</div>');
} }
...@@ -701,19 +774,27 @@ ...@@ -701,19 +774,27 @@
if (labels.length > 0) { if (labels.length > 0) {
var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">' var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">'
+ labels.join("") + '</div>').appendTo(target); + labels.join("") + '</div>').appendTo(target);
if (yaxis.labelWidth == null) if (axis.labelWidth == null)
yaxis.labelWidth = dummyDiv.width(); axis.labelWidth = dummyDiv.width();
if (yaxis.labelHeight == null) if (axis.labelHeight == null)
yaxis.labelHeight = dummyDiv.find("div").height(); axis.labelHeight = dummyDiv.find("div").height();
dummyDiv.remove(); dummyDiv.remove();
} }
if (yaxis.labelWidth == null) if (axis.labelWidth == null)
yaxis.labelWidth = 0; axis.labelWidth = 0;
if (yaxis.labelHeight == null) if (axis.labelHeight == null)
yaxis.labelHeight = 0; axis.labelHeight = 0;
}
} }
measureXLabels(xaxis);
measureYLabels(yaxis);
measureXLabels(x2axis);
measureYLabels(y2axis);
// get the most space needed around the grid for things
// that may stick out
var maxOutset = options.grid.borderWidth / 2; var maxOutset = options.grid.borderWidth / 2;
if (options.points.show) if (options.points.show)
maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2); maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2);
...@@ -724,41 +805,25 @@ ...@@ -724,41 +805,25 @@
plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = maxOutset; plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = maxOutset;
if (xaxis.labelHeight > 0)
plotOffset.bottom += xaxis.labelHeight + options.grid.labelMargin;
if (yaxis.labelWidth > 0) if (yaxis.labelWidth > 0)
plotOffset.left += yaxis.labelWidth + options.grid.labelMargin; plotOffset.left += yaxis.labelWidth + options.grid.labelMargin;
plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
// set width for labels; to avoid measuring the widths of if (x2axis.labelHeight > 0)
// the labels, we construct fixed-size boxes and put the plotOffset.top += x2axis.labelHeight + options.grid.labelMargin;
// labels inside them, the fixed-size boxes are easy to
// mid-align
if (xaxis.labelWidth == null)
xaxis.labelWidth = plotWidth / 6;
if (xaxis.labelHeight == null) { if (y2axis.labelWidth > 0)
// measure x label heights plotOffset.right += y2axis.labelWidth + options.grid.labelMargin;
labels = [];
for (i = 0; i < xaxis.ticks.length; ++i) {
l = xaxis.ticks[i].label;
if (l)
labels.push('<span class="tickLabel" width="' + xaxis.labelWidth + '">' + l + '</span>');
}
xaxis.labelHeight = 0;
if (labels.length > 0) {
var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">'
+ labels.join("") + '</div>').appendTo(target);
xaxis.labelHeight = dummyDiv.height();
dummyDiv.remove();
}
}
if (xaxis.labelHeight > 0)
plotOffset.bottom += xaxis.labelHeight + options.grid.labelMargin;
plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top; plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
hozScale = plotWidth / (xaxis.max - xaxis.min);
vertScale = plotHeight / (yaxis.max - yaxis.min); // precompute how much the axis is scaling a point in canvas space
xaxis.scale = plotWidth / (xaxis.max - xaxis.min);
yaxis.scale = plotHeight / (yaxis.max - yaxis.min);
x2axis.scale = plotWidth / (x2axis.max - x2axis.min);
y2axis.scale = plotHeight / (y2axis.max - y2axis.min);
} }
function draw() { function draw() {
...@@ -768,14 +833,6 @@ ...@@ -768,14 +833,6 @@
} }
} }
function tHoz(x) {
return (x - xaxis.min) * hozScale;
}
function tVert(y) {
return plotHeight - (y - yaxis.min) * vertScale;
}
function drawGrid() { function drawGrid() {
var i; var i;
...@@ -825,8 +882,8 @@ ...@@ -825,8 +882,8 @@
continue; continue;
ctx.fillStyle = a.color || options.grid.coloredAreasColor; ctx.fillStyle = a.color || options.grid.coloredAreasColor;
ctx.fillRect(Math.floor(tHoz(a.x1)), Math.floor(tVert(a.y2)), ctx.fillRect(Math.floor(xaxis.p2c(a.x1)), Math.floor(yaxis.p2c(a.y2)),
Math.floor(tHoz(a.x2) - tHoz(a.x1)), Math.floor(tVert(a.y1) - tVert(a.y2))); Math.floor(xaxis.p2c(a.x2) - xaxis.p2c(a.x1)), Math.floor(yaxis.p2c(a.y1) - yaxis.p2c(a.y2)));
} }
} }
...@@ -840,8 +897,8 @@ ...@@ -840,8 +897,8 @@
if (v <= xaxis.min || v >= xaxis.max) if (v <= xaxis.min || v >= xaxis.max)
continue; // skip those lying on the axes continue; // skip those lying on the axes
ctx.moveTo(Math.floor(tHoz(v)) + ctx.lineWidth/2, 0); ctx.moveTo(Math.floor(xaxis.p2c(v)) + ctx.lineWidth/2, 0);
ctx.lineTo(Math.floor(tHoz(v)) + ctx.lineWidth/2, plotHeight); ctx.lineTo(Math.floor(xaxis.p2c(v)) + ctx.lineWidth/2, plotHeight);
} }
for (i = 0; i < yaxis.ticks.length; ++i) { for (i = 0; i < yaxis.ticks.length; ++i) {
...@@ -849,9 +906,28 @@ ...@@ -849,9 +906,28 @@
if (v <= yaxis.min || v >= yaxis.max) if (v <= yaxis.min || v >= yaxis.max)
continue; continue;
ctx.moveTo(0, Math.floor(tVert(v)) + ctx.lineWidth/2); ctx.moveTo(0, Math.floor(yaxis.p2c(v)) + ctx.lineWidth/2);
ctx.lineTo(plotWidth, Math.floor(tVert(v)) + ctx.lineWidth/2); ctx.lineTo(plotWidth, Math.floor(yaxis.p2c(v)) + ctx.lineWidth/2);
}
for (i = 0; i < x2axis.ticks.length; ++i) {
v = x2axis.ticks[i].v;
if (v <= x2axis.min || v >= x2axis.max)
continue;
ctx.moveTo(Math.floor(x2axis.p2c(v)) + ctx.lineWidth/2, -5);
ctx.lineTo(Math.floor(x2axis.p2c(v)) + ctx.lineWidth/2, 5);
}
for (i = 0; i < y2axis.ticks.length; ++i) {
v = y2axis.ticks[i].v;
if (v <= y2axis.min || v >= y2axis.max)
continue;
ctx.moveTo(plotWidth-5, Math.floor(y2axis.p2c(v)) + ctx.lineWidth/2);
ctx.lineTo(plotWidth+5, Math.floor(y2axis.p2c(v)) + ctx.lineWidth/2);
} }
ctx.stroke(); ctx.stroke();
if (options.grid.borderWidth) { if (options.grid.borderWidth) {
...@@ -876,7 +952,7 @@ ...@@ -876,7 +952,7 @@
tick = xaxis.ticks[i]; tick = xaxis.ticks[i];
if (!tick.label || tick.v < xaxis.min || tick.v > xaxis.max) if (!tick.label || tick.v < xaxis.min || tick.v > xaxis.max)
continue; continue;
html += '<div style="position:absolute;top:' + (plotOffset.top + plotHeight + options.grid.labelMargin) + 'px;left:' + (plotOffset.left + tHoz(tick.v) - xaxis.labelWidth/2) + 'px;width:' + xaxis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>"; html += '<div style="position:absolute;top:' + (plotOffset.top + plotHeight + options.grid.labelMargin) + 'px;left:' + (plotOffset.left + xaxis.p2c(tick.v) - xaxis.labelWidth/2) + 'px;width:' + xaxis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
} }
// do the y-axis // do the y-axis
...@@ -884,7 +960,23 @@ ...@@ -884,7 +960,23 @@
tick = yaxis.ticks[i]; tick = yaxis.ticks[i];
if (!tick.label || tick.v < yaxis.min || tick.v > yaxis.max) if (!tick.label || tick.v < yaxis.min || tick.v > yaxis.max)
continue; continue;
html += '<div style="position:absolute;top:' + (plotOffset.top + tVert(tick.v) - yaxis.labelHeight/2) + 'px;left:0;width:' + yaxis.labelWidth + 'px;text-align:right" class="tickLabel">' + tick.label + "</div>"; html += '<div style="position:absolute;top:' + (plotOffset.top + yaxis.p2c(tick.v) - yaxis.labelHeight/2) + 'px;left:0;width:' + yaxis.labelWidth + 'px;text-align:right" class="tickLabel">' + tick.label + "</div>";
}
// do the x2-axis
for (i = 0; i < x2axis.ticks.length; ++i) {
tick = x2axis.ticks[i];
if (!tick.label || tick.v < x2axis.min || tick.v > x2axis.max)
continue;
html += '<div style="position:absolute;top:0;left:' + (plotOffset.left + x2axis.p2c(tick.v) - x2axis.labelWidth/2) + 'px;width:' + x2axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
}
// do the y2-axis
for (i = 0; i < y2axis.ticks.length; ++i) {
tick = y2axis.ticks[i];
if (!tick.label || tick.v < y2axis.min || tick.v > y2axis.max)
continue;
html += '<div style="position:absolute;top:' + (plotOffset.top + y2axis.p2c(tick.v) - y2axis.labelHeight/2) + 'px;left:' + (canvasWidth - y2axis.labelWidth) +'px;width:' + y2axis.labelWidth + 'px;text-align:left" class="tickLabel">' + tick.label + "</div>";
} }
html += '</div>'; html += '</div>';
...@@ -902,7 +994,7 @@ ...@@ -902,7 +994,7 @@
} }
function drawSeriesLines(series) { function drawSeriesLines(series) {
function plotLine(data, offset) { function plotLine(data, offset, axisx, axisy) {
var prev, cur = null, drawx = null, drawy = null; var prev, cur = null, drawx = null, drawy = null;
ctx.beginPath(); ctx.beginPath();
...@@ -917,76 +1009,76 @@ ...@@ -917,76 +1009,76 @@
x2 = cur[0], y2 = cur[1]; x2 = cur[0], y2 = cur[1];
// clip with ymin // clip with ymin
if (y1 <= y2 && y1 < yaxis.min) { if (y1 <= y2 && y1 < axisy.min) {
if (y2 < yaxis.min) if (y2 < axisy.min)
continue; // line segment is outside continue; // line segment is outside
// compute new intersection point // compute new intersection point
x1 = (yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = yaxis.min; y1 = axisy.min;
} }
else if (y2 <= y1 && y2 < yaxis.min) { else if (y2 <= y1 && y2 < axisy.min) {
if (y1 < yaxis.min) if (y1 < axisy.min)
continue; continue;
x2 = (yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = yaxis.min; y2 = axisy.min;
} }
// clip with ymax // clip with ymax
if (y1 >= y2 && y1 > yaxis.max) { if (y1 >= y2 && y1 > axisy.max) {
if (y2 > yaxis.max) if (y2 > axisy.max)
continue; continue;
x1 = (yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = yaxis.max; y1 = axisy.max;
} }
else if (y2 >= y1 && y2 > yaxis.max) { else if (y2 >= y1 && y2 > axisy.max) {
if (y1 > yaxis.max) if (y1 > axisy.max)
continue; continue;
x2 = (yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = yaxis.max; y2 = axisy.max;
} }
// clip with xmin // clip with xmin
if (x1 <= x2 && x1 < xaxis.min) { if (x1 <= x2 && x1 < axisx.min) {
if (x2 < xaxis.min) if (x2 < axisx.min)
continue; continue;
y1 = (xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xaxis.min; x1 = axisx.min;
} }
else if (x2 <= x1 && x2 < xaxis.min) { else if (x2 <= x1 && x2 < axisx.min) {
if (x1 < xaxis.min) if (x1 < axisx.min)
continue; continue;
y2 = (xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xaxis.min; x2 = axisx.min;
} }
// clip with xmax // clip with xmax
if (x1 >= x2 && x1 > xaxis.max) { if (x1 >= x2 && x1 > axisx.max) {
if (x2 > xaxis.max) if (x2 > axisx.max)
continue; continue;
y1 = (xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xaxis.max; x1 = axisx.max;
} }
else if (x2 >= x1 && x2 > xaxis.max) { else if (x2 >= x1 && x2 > axisx.max) {
if (x1 > xaxis.max) if (x1 > axisx.max)
continue; continue;
y2 = (xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xaxis.max; x2 = axisx.max;
} }
if (drawx != tHoz(x1) || drawy != tVert(y1) + offset) if (drawx != axisx.p2c(x1) || drawy != axisy.p2c(y1) + offset)
ctx.moveTo(tHoz(x1), tVert(y1) + offset); ctx.moveTo(axisx.p2c(x1), axisy.p2c(y1) + offset);
drawx = tHoz(x2); drawx = axisx.p2c(x2);
drawy = tVert(y2) + offset; drawy = axisy.p2c(y2) + offset;
ctx.lineTo(drawx, drawy); ctx.lineTo(drawx, drawy);
} }
ctx.stroke(); ctx.stroke();
} }
function plotLineArea(data) { function plotLineArea(data, axisx, axisy) {
var prev, cur = null; var prev, cur = null;
var bottom = Math.min(Math.max(0, yaxis.min), yaxis.max); var bottom = Math.min(Math.max(0, axisy.min), axisy.max);
var top, lastX = 0; var top, lastX = 0;
var areaOpen = false; var areaOpen = false;
...@@ -997,7 +1089,7 @@ ...@@ -997,7 +1089,7 @@
if (areaOpen && prev != null && cur == null) { if (areaOpen && prev != null && cur == null) {
// close area // close area
ctx.lineTo(tHoz(lastX), tVert(bottom)); ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
ctx.fill(); ctx.fill();
areaOpen = false; areaOpen = false;
continue; continue;
...@@ -1012,49 +1104,49 @@ ...@@ -1012,49 +1104,49 @@
// clip x values // clip x values
// clip with xmin // clip with xmin
if (x1 <= x2 && x1 < xaxis.min) { if (x1 <= x2 && x1 < axisx.min) {
if (x2 < xaxis.min) if (x2 < axisx.min)
continue; continue;
y1 = (xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xaxis.min; x1 = axisx.min;
} }
else if (x2 <= x1 && x2 < xaxis.min) { else if (x2 <= x1 && x2 < axisx.min) {
if (x1 < xaxis.min) if (x1 < axisx.min)
continue; continue;
y2 = (xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xaxis.min; x2 = axisx.min;
} }
// clip with xmax // clip with xmax
if (x1 >= x2 && x1 > xaxis.max) { if (x1 >= x2 && x1 > axisx.max) {
if (x2 > xaxis.max) if (x2 > axisx.max)
continue; continue;
y1 = (xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xaxis.max; x1 = axisx.max;
} }
else if (x2 >= x1 && x2 > xaxis.max) { else if (x2 >= x1 && x2 > axisx.max) {
if (x1 > xaxis.max) if (x1 > axisx.max)
continue; continue;
y2 = (xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xaxis.max; x2 = axisx.max;
} }
if (!areaOpen) { if (!areaOpen) {
// open area // open area
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(tHoz(x1), tVert(bottom)); ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
areaOpen = true; areaOpen = true;
} }
// now first check the case where both is outside // now first check the case where both is outside
if (y1 >= yaxis.max && y2 >= yaxis.max) { if (y1 >= axisy.max && y2 >= axisy.max) {
ctx.lineTo(tHoz(x1), tVert(yaxis.max)); ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
ctx.lineTo(tHoz(x2), tVert(yaxis.max)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
continue; continue;
} }
else if (y1 <= yaxis.min && y2 <= yaxis.min) { else if (y1 <= axisy.min && y2 <= axisy.min) {
ctx.lineTo(tHoz(x1), tVert(yaxis.min)); ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
ctx.lineTo(tHoz(x2), tVert(yaxis.min)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
continue; continue;
} }
...@@ -1066,58 +1158,58 @@ ...@@ -1066,58 +1158,58 @@
// and clip the y values, without shortcutting // and clip the y values, without shortcutting
// clip with ymin // clip with ymin
if (y1 <= y2 && y1 < yaxis.min && y2 >= yaxis.min) { if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
x1 = (yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = yaxis.min; y1 = axisy.min;
} }
else if (y2 <= y1 && y2 < yaxis.min && y1 >= yaxis.min) { else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
x2 = (yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = yaxis.min; y2 = axisy.min;
} }
// clip with ymax // clip with ymax
if (y1 >= y2 && y1 > yaxis.max && y2 <= yaxis.max) { if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
x1 = (yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = yaxis.max; y1 = axisy.max;
} }
else if (y2 >= y1 && y2 > yaxis.max && y1 <= yaxis.max) { else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
x2 = (yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = yaxis.max; y2 = axisy.max;
} }
// if the x value was changed we got a rectangle // if the x value was changed we got a rectangle
// to fill // to fill
if (x1 != x1old) { if (x1 != x1old) {
if (y1 <= yaxis.min) if (y1 <= axisy.min)
top = yaxis.min; top = axisy.min;
else else
top = yaxis.max; top = axisy.max;
ctx.lineTo(tHoz(x1old), tVert(top)); ctx.lineTo(axisx.p2c(x1old), axisy.p2c(top));
ctx.lineTo(tHoz(x1), tVert(top)); ctx.lineTo(axisx.p2c(x1), axisy.p2c(top));
} }
// fill the triangles // fill the triangles
ctx.lineTo(tHoz(x1), tVert(y1)); ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
ctx.lineTo(tHoz(x2), tVert(y2)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
// fill the other rectangle if it's there // fill the other rectangle if it's there
if (x2 != x2old) { if (x2 != x2old) {
if (y2 <= yaxis.min) if (y2 <= axisy.min)
top = yaxis.min; top = axisy.min;
else else
top = yaxis.max; top = axisy.max;
ctx.lineTo(tHoz(x2old), tVert(top)); ctx.lineTo(axisx.p2c(x2old), axisy.p2c(top));
ctx.lineTo(tHoz(x2), tVert(top)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(top));
} }
lastX = Math.max(x2, x2old); lastX = Math.max(x2, x2old);
} }
if (areaOpen) { if (areaOpen) {
ctx.lineTo(tHoz(lastX), tVert(bottom)); ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
ctx.fill(); ctx.fill();
} }
} }
...@@ -1133,50 +1225,50 @@ ...@@ -1133,50 +1225,50 @@
// draw shadow in two steps // draw shadow in two steps
ctx.lineWidth = sw / 2; ctx.lineWidth = sw / 2;
ctx.strokeStyle = "rgba(0,0,0,0.1)"; ctx.strokeStyle = "rgba(0,0,0,0.1)";
plotLine(series.data, lw/2 + sw/2 + ctx.lineWidth/2); plotLine(series.data, lw/2 + sw/2 + ctx.lineWidth/2, series.xaxis, series.yaxis);
ctx.lineWidth = sw / 2; ctx.lineWidth = sw / 2;
ctx.strokeStyle = "rgba(0,0,0,0.2)"; ctx.strokeStyle = "rgba(0,0,0,0.2)";
plotLine(series.data, lw/2 + ctx.lineWidth/2); plotLine(series.data, lw/2 + ctx.lineWidth/2, series.xaxis, series.yaxis);
} }
ctx.lineWidth = lw; ctx.lineWidth = lw;
ctx.strokeStyle = series.color; ctx.strokeStyle = series.color;
setFillStyle(series.lines, series.color); setFillStyle(series.lines, series.color);
if (series.lines.fill) if (series.lines.fill)
plotLineArea(series.data, 0); plotLineArea(series.data, series.xaxis, series.yaxis);
plotLine(series.data, 0); plotLine(series.data, 0, series.xaxis, series.yaxis);
ctx.restore(); ctx.restore();
} }
function drawSeriesPoints(series) { function drawSeriesPoints(series) {
function plotPoints(data, radius, fill) { function plotPoints(data, radius, fill, axisx, axisy) {
for (var i = 0; i < data.length; ++i) { for (var i = 0; i < data.length; ++i) {
if (data[i] == null) if (data[i] == null)
continue; continue;
var x = data[i][0], y = data[i][1]; var x = data[i][0], y = data[i][1];
if (x < xaxis.min || x > xaxis.max || y < yaxis.min || y > yaxis.max) if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
continue; continue;
ctx.beginPath(); ctx.beginPath();
ctx.arc(tHoz(x), tVert(y), radius, 0, 2 * Math.PI, true); ctx.arc(axisx.p2c(x), axisy.p2c(y), radius, 0, 2 * Math.PI, true);
if (fill) if (fill)
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
} }
} }
function plotPointShadows(data, offset, radius) { function plotPointShadows(data, offset, radius, axisx, axisy) {
for (var i = 0; i < data.length; ++i) { for (var i = 0; i < data.length; ++i) {
if (data[i] == null) if (data[i] == null)
continue; continue;
var x = data[i][0], y = data[i][1]; var x = data[i][0], y = data[i][1];
if (x < xaxis.min || x > xaxis.max || y < yaxis.min || y > yaxis.max) if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
continue; continue;
ctx.beginPath(); ctx.beginPath();
ctx.arc(tHoz(x), tVert(y) + offset, radius, 0, Math.PI, false); ctx.arc(axisx.p2c(x), axisy.p2c(y) + offset, radius, 0, Math.PI, false);
ctx.stroke(); ctx.stroke();
} }
} }
...@@ -1190,22 +1282,25 @@ ...@@ -1190,22 +1282,25 @@
// draw shadow in two steps // draw shadow in two steps
ctx.lineWidth = sw / 2; ctx.lineWidth = sw / 2;
ctx.strokeStyle = "rgba(0,0,0,0.1)"; ctx.strokeStyle = "rgba(0,0,0,0.1)";
plotPointShadows(series.data, sw/2 + ctx.lineWidth/2, series.points.radius); plotPointShadows(series.data, sw/2 + ctx.lineWidth/2,
series.points.radius, series.xaxis, series.yaxis);
ctx.lineWidth = sw / 2; ctx.lineWidth = sw / 2;
ctx.strokeStyle = "rgba(0,0,0,0.2)"; ctx.strokeStyle = "rgba(0,0,0,0.2)";
plotPointShadows(series.data, ctx.lineWidth/2, series.points.radius); plotPointShadows(series.data, ctx.lineWidth/2,
series.points.radius, series.xaxis, series.yaxis);
} }
ctx.lineWidth = series.points.lineWidth; ctx.lineWidth = series.points.lineWidth;
ctx.strokeStyle = series.color; ctx.strokeStyle = series.color;
setFillStyle(series.points, series.color); setFillStyle(series.points, series.color);
plotPoints(series.data, series.points.radius, series.points.fill); plotPoints(series.data, series.points.radius, series.points.fill,
series.xaxis, series.yaxis);
ctx.restore(); ctx.restore();
} }
function drawSeriesBars(series) { function drawSeriesBars(series) {
function plotBars(data, barWidth, offset, fill) { function plotBars(data, barWidth, offset, fill, axisx, axisy) {
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
if (data[i] == null) if (data[i] == null)
continue; continue;
...@@ -1216,55 +1311,55 @@ ...@@ -1216,55 +1311,55 @@
// determine the co-ordinates of the bar, account for negative bars having // determine the co-ordinates of the bar, account for negative bars having
// flipped top/bottom and draw/don't draw accordingly // flipped top/bottom and draw/don't draw accordingly
var left = x, right = x + barWidth, bottom = (y < 0 ? y : 0), top = (y < 0 ? 0 : y); var left = x, right = x + barWidth, bottom = (y < 0 ? y : 0), top = (y < 0 ? 0 : y);
if (right < xaxis.min || left > xaxis.max || top < yaxis.min || bottom > yaxis.max) if (right < axisx.min || left > axisx.max || top < axisy.min || bottom > axisy.max)
continue; continue;
// clip // clip
if (left < xaxis.min) { if (left < axisx.min) {
left = xaxis.min; left = axisx.min;
drawLeft = false; drawLeft = false;
} }
if (right > xaxis.max) { if (right > axisx.max) {
right = xaxis.max; right = axisx.max;
drawRight = false; drawRight = false;
} }
if (bottom < yaxis.min) if (bottom < axisy.min)
bottom = yaxis.min; bottom = axisy.min;
if (top > yaxis.max) { if (top > axisy.max) {
top = yaxis.max; top = axisy.max;
drawTop = false; drawTop = false;
} }
// fill the bar // fill the bar
if (fill) { if (fill) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(tHoz(left), tVert(bottom) + offset); ctx.moveTo(axisx.p2c(left), axisy.p2c(bottom) + offset);
ctx.lineTo(tHoz(left), tVert(top) + offset); ctx.lineTo(axisx.p2c(left), axisy.p2c(top) + offset);
ctx.lineTo(tHoz(right), tVert(top) + offset); ctx.lineTo(axisx.p2c(right), axisy.p2c(top) + offset);
ctx.lineTo(tHoz(right), tVert(bottom) + offset); ctx.lineTo(axisx.p2c(right), axisy.p2c(bottom) + offset);
ctx.fill(); ctx.fill();
} }
// draw outline // draw outline
if (drawLeft || drawRight || drawTop) { if (drawLeft || drawRight || drawTop) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(tHoz(left), tVert(bottom) + offset); ctx.moveTo(axisx.p2c(left), axisy.p2c(bottom) + offset);
if (drawLeft) if (drawLeft)
ctx.lineTo(tHoz(left), tVert(top) + offset); ctx.lineTo(axisx.p2c(left), axisy.p2c(top) + offset);
else else
ctx.moveTo(tHoz(left), tVert(top) + offset); ctx.moveTo(axisx.p2c(left), axisy.p2c(top) + offset);
if (drawTop) if (drawTop)
ctx.lineTo(tHoz(right), tVert(top) + offset); ctx.lineTo(axisx.p2c(right), axisy.p2c(top) + offset);
else else
ctx.moveTo(tHoz(right), tVert(top) + offset); ctx.moveTo(axisx.p2c(right), axisy.p2c(top) + offset);
if (drawRight) if (drawRight)
ctx.lineTo(tHoz(right), tVert(bottom) + offset); ctx.lineTo(axisx.p2c(right), axisy.p2c(bottom) + offset);
else else
ctx.moveTo(tHoz(right), tVert(bottom) + offset); ctx.moveTo(axisx.p2c(right), axisy.p2c(bottom) + offset);
ctx.stroke(); ctx.stroke();
} }
} }
...@@ -1293,7 +1388,7 @@ ...@@ -1293,7 +1388,7 @@
ctx.lineWidth = series.bars.lineWidth; ctx.lineWidth = series.bars.lineWidth;
ctx.strokeStyle = series.color; ctx.strokeStyle = series.color;
setFillStyle(series.bars, series.color); setFillStyle(series.bars, series.color);
plotBars(series.data, series.bars.barWidth, 0, series.bars.fill); plotBars(series.data, series.bars.barWidth, 0, series.bars.fill, series.xaxis, series.yaxis);
ctx.restore(); ctx.restore();
} }
...@@ -1342,7 +1437,9 @@ ...@@ -1342,7 +1437,9 @@
if (rowStarted) if (rowStarted)
fragments.push('</tr>'); fragments.push('</tr>');
if (fragments.length > 0) { if (fragments.length == 0)
return;
var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>'; var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
if (options.legend.container != null) if (options.legend.container != null)
options.legend.container.html(table); options.legend.container.html(table);
...@@ -1356,7 +1453,7 @@ ...@@ -1356,7 +1453,7 @@
if (p.charAt(1) == "e") if (p.charAt(1) == "e")
pos += 'right:' + (m + plotOffset.right) + 'px;'; pos += 'right:' + (m + plotOffset.right) + 'px;';
else if (p.charAt(1) == "w") else if (p.charAt(1) == "w")
pos += 'left:' + (m + plotOffset.bottom) + 'px;'; pos += 'left:' + (m + plotOffset.left) + 'px;';
var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(target); var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(target);
if (options.legend.backgroundOpacity != 0.0) { if (options.legend.backgroundOpacity != 0.0) {
// put in the transparent background // put in the transparent background
...@@ -1377,7 +1474,6 @@ ...@@ -1377,7 +1474,6 @@
} }
} }
} }
}
var lastMousePos = { pageX: null, pageY: null }; var lastMousePos = { pageX: null, pageY: null };
var selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} }; var selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} };
...@@ -1385,6 +1481,50 @@ ...@@ -1385,6 +1481,50 @@
var selectionInterval = null; var selectionInterval = null;
var ignoreClick = false; var ignoreClick = false;
// Returns the data item the mouse is over, or null if none is found
function findNearbyItem(mouseX, mouseY) {
var maxDistance = options.grid.mouseCatchingArea;
var lowestDistance = maxDistance * maxDistance + 0.1,
item = null;
for (var i = 0; i < series.length; ++i) {
var data = series[i].data,
axisx = series[i].xaxis,
axisy = series[i].yaxis;
var mx = axisx.c2p(mouseX), my = axisy.c2p(mouseY),
maxx = maxDistance / axisx.scale,
maxy = maxDistance / axisy.scale;
for (var j = 0; j < data.length; ++j) {
if (data[j] == null)
continue;
// We have to calculate distances in pixels, not in
// data units, because the scale of the axes may be different
var x = data[j][0], y = data[j][1];
if (x - mx > maxx || x - mx < -maxx)
continue; // Don't bother, we're too far
if (y - my > maxy || y - my < -maxy)
continue;
var dx = Math.abs(xaxis.p2c(x) - mouseX),
dy = Math.abs(yaxis.p2c(y) - mouseY);
var dist = dx * dx + dy * dy;
if (dist < lowestDistance) {
lowestDistance = dist;
item = { datapoint: data[j],
dataIndex: j,
series: series[i],
seriesIndex: i };
}
}
}
return item;
}
var hoverTimeout = null;
function onMouseMove(ev) { function onMouseMove(ev) {
// FIXME: temp. work-around until jQuery bug 1871 is fixed // FIXME: temp. work-around until jQuery bug 1871 is fixed
var e = ev || window.event; var e = ev || window.event;
...@@ -1397,6 +1537,9 @@ ...@@ -1397,6 +1537,9 @@
lastMousePos.pageX = e.pageX; lastMousePos.pageX = e.pageX;
lastMousePos.pageY = e.pageY; lastMousePos.pageY = e.pageY;
} }
if (options.grid.hoverable && !hoverTimeout)
hoverTimeout = setTimeout(emitHoverEvent, 100);
} }
function onMouseDown(e) { function onMouseDown(e) {
...@@ -1431,18 +1574,37 @@ ...@@ -1431,18 +1574,37 @@
return; return;
} }
var offset = eventHolder.offset(); triggerClickHoverEvent("plotclick", e);
var pos = {}; }
pos.x = e.pageX - offset.left - plotOffset.left;
pos.x = xaxis.min + pos.x / hozScale; function emitHoverEvent() {
pos.y = e.pageY - offset.top - plotOffset.top; triggerClickHoverEvent("plothover", lastMousePos);
pos.y = yaxis.max - pos.y / vertScale; hoverTimeout = null;
}
function triggerClickHoverEvent(eventname, event) {
var offset = eventHolder.offset(),
pos = {},
canvasX = event.pageX - offset.left - plotOffset.left,
canvasY = event.pageY - offset.top - plotOffset.top;
target.trigger("plotclick", [ pos ]); if (xaxis.used)
pos.x = xaxis.c2p(canvasX);
if (yaxis.used)
pos.y = yaxis.c2p(canvasY);
if (x2axis.used)
pos.x2 = x2axis.c2p(canvasX);
if (y2axis.used)
pos.y2 = y2axis.c2p(canvasY);
item = findNearbyItem(canvasX, canvasY);
target.trigger(eventname, [ pos, item ]);
} }
function triggerSelectedEvent() { function triggerSelectedEvent() {
var x1, x2, y1, y2; var x1, x2, y1, y2;
if (selection.first.x <= selection.second.x) { if (selection.first.x <= selection.second.x) {
x1 = selection.first.x; x1 = selection.first.x;
x2 = selection.second.x; x2 = selection.second.x;
...@@ -1461,13 +1623,21 @@ ...@@ -1461,13 +1623,21 @@
y2 = selection.first.y; y2 = selection.first.y;
} }
x1 = xaxis.min + x1 / hozScale; var r = {};
x2 = xaxis.min + x2 / hozScale; if (xaxis.used)
r.xaxis = { from: xaxis.c2p(x1), to: xaxis.c2p(x2) };
if (x2axis.used)
r.x2axis = { from: x2axis.c2p(x1), to: x2axis.c2p(x2) };
if (yaxis.used)
r.yaxis = { from: yaxis.c2p(y1), to: yaxis.c2p(y2) };
if (y2axis.used)
r.yaxis = { from: y2axis.c2p(y1), to: y2axis.c2p(y2) };
y1 = yaxis.max - y1 / vertScale; target.trigger("plotselected", [ r ]);
y2 = yaxis.max - y2 / vertScale;
target.trigger("selected", [ { x1: x1, y1: y1, x2: x2, y2: y2 } ]); // backwards-compat stuff, to be removed in future
if (xaxis.used && yaxis.used)
target.trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
} }
function onSelectionMouseUp(e) { function onSelectionMouseUp(e) {
...@@ -1545,24 +1715,61 @@ ...@@ -1545,24 +1715,61 @@
prevSelection = null; prevSelection = null;
} }
function setSelection(area) { function setSelection(ranges) {
clearSelection(); clearSelection();
var axis, from, to;
if (options.selection.mode == "y") {
selection.first.x = 0;
selection.second.x = plotWidth;
}
else {
if (ranges.yaxis) {
axis = xaxis;
from = ranges.xaxis.from;
to = ranges.xaxis.to;
}
else if (ranges.x2axis) {
axis = x2axis;
from = ranges.x2axis.from;
to = ranges.x2axis.to;
}
else {
// backwards-compat stuff - to be removed in future
axis = xaxis;
from = ranges.x1;
to = ranges.x2;
}
selection.first.x = axis.p2c(from);
selection.second.x = axis.p2c(to);
}
if (options.selection.mode == "x") { if (options.selection.mode == "x") {
selection.first.y = 0; selection.first.y = 0;
selection.second.y = plotHeight; selection.second.y = plotHeight;
} }
else { else {
selection.first.y = (yaxis.max - area.y1) * vertScale; if (ranges.yaxis) {
selection.second.y = (yaxis.max - area.y2) * vertScale; axis = yaxis;
from = ranges.yaxis.from;
to = ranges.yaxis.to;
} }
if (options.selection.mode == "y") { else if (ranges.y2axis) {
selection.first.x = 0; axis = y2axis;
selection.second.x = plotWidth; from = ranges.y2axis.from;
to = ranges.y2axis.to;
} }
else { else {
selection.first.x = (area.x1 - xaxis.min) * hozScale; // backwards-compat stuff - to be removed in future
selection.second.x = (area.x2 - xaxis.min) * hozScale; axis = yaxis;
from = ranges.y1;
to = ranges.y2;
}
selection.first.y = axis.p2c(from);
selection.second.y = axis.p2c(to);
} }
drawSelection(); drawSelection();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment