Codebase list flot / 492d201
Imported Upstream version 0.7+dfsg Marcelo Jorge Vieira 12 years ago
50 changed file(s) with 4297 addition(s) and 1099 deletion(s). Raw diff Collapse all Expand all
1414 problem on IE 7.
1515
1616 The format of the data is documented below, as is the available
17 options. The "plot" object returned has some methods you can call.
18 These are documented separately below.
17 options. The plot object returned from the call has some methods you
18 can call. These are documented separately below.
1919
2020 Note that in general Flot gives no guarantees if you change any of the
2121 objects you pass in to the plot function or get out of it since
5151 line segment end, i.e. the points before and after the null value are
5252 not connected.
5353
54 Lines and points take two coordinates. For bars, you can specify a
55 third coordinate which is the bottom of the bar (defaults to 0).
54 Lines and points take two coordinates. For filled lines and bars, you
55 can specify a third coordinate which is the bottom of the filled
56 area/bar (defaults to 0).
5657
5758 The format of a single series object is as follows:
5859
6364 lines: specific lines options
6465 bars: specific bars options
6566 points: specific points options
66 xaxis: 1 or 2
67 yaxis: 1 or 2
67 xaxis: number
68 yaxis: number
6869 clickable: boolean
6970 hoverable: boolean
7071 shadowSize: number
9192 in which case you can hard-code the color index to prevent the colors
9293 from jumping around between the series.
9394
94 The "xaxis" and "yaxis" options specify which axis to use, specify 2
95 to get the secondary axis (x axis at top or y axis to the right).
96 E.g., you can use this to make a dual axis plot by specifying
97 { yaxis: 2 } for one data series.
95 The "xaxis" and "yaxis" options specify which axis to use. The axes
96 are numbered from 1 (default), so { yaxis: 2} means that the series
97 should be plotted against the second y axis.
9898
9999 "clickable" and "hoverable" can be set to false to disable
100100 interactivity for specific series if interactivity is turned on in
170170 Customizing the axes
171171 ====================
172172
173 xaxis, yaxis, x2axis, y2axis: {
173 xaxis, yaxis: {
174 show: null or true/false
175 position: "bottom" or "top" or "left" or "right"
174176 mode: null or "time"
177
178 color: null or color spec
179 tickColor: null or color spec
180
175181 min: null or number
176182 max: null or number
177183 autoscaleMargin: null or number
178184
179 labelWidth: null or number
180 labelHeight: null or number
181
182185 transform: null or fn: number -> number
183186 inverseTransform: null or fn: number -> number
184187
187190 minTickSize: number or array
188191 tickFormatter: (fn: number, object -> string) or string
189192 tickDecimals: null or number
190 }
191
192 All axes have the same kind of options. The "mode" option
193 determines how the data is interpreted, the default of null means as
194 decimal numbers. Use "time" for time series data, see the next section.
193
194 labelWidth: null or number
195 labelHeight: null or number
196 reserveSpace: null or true
197
198 tickLength: null or number
199
200 alignTicksWithAxis: null or number
201 }
202
203 All axes have the same kind of options. The following describes how to
204 configure one axis, see below for what to do if you've got more than
205 one x axis or y axis.
206
207 If you don't set the "show" option (i.e. it is null), visibility is
208 auto-detected, i.e. the axis will show up if there's data associated
209 with it. You can override this by setting the "show" option to true or
210 false.
211
212 The "position" option specifies where the axis is placed, bottom or
213 top for x axes, left or right for y axes. The "mode" option determines
214 how the data is interpreted, the default of null means as decimal
215 numbers. Use "time" for time series data, see the time series data
216 section.
217
218 The "color" option determines the color of the labels and ticks for
219 the axis (default is the grid color). For more fine-grained control
220 you can also set the color of the ticks separately with "tickColor"
221 (otherwise it's autogenerated as the base color with some
222 transparency).
195223
196224 The options "min"/"max" are the precise minimum/maximum value on the
197225 scale. If you don't specify either of them, a value will automatically
198 be chosen based on the minimum/maximum data values.
226 be chosen based on the minimum/maximum data values. Note that Flot
227 always examines all the data values you feed to it, even if a
228 restriction on another axis may make some of them invisible (this
229 makes interactive use more stable).
199230
200231 The "autoscaleMargin" is a bit esoteric: it's the fraction of margin
201232 that the scaling algorithm will add to avoid that the outermost points
202 ends up on the grid border. Note that this margin is only applied
203 when a min or max value is not explicitly set. If a margin is
204 specified, the plot will furthermore extend the axis end-point to the
205 nearest whole tick. The default value is "null" for the x axis and
206 0.02 for the y axis which seems appropriate for most cases.
207
208 "labelWidth" and "labelHeight" specifies a fixed size of the tick
209 labels in pixels. They're useful in case you need to align several
210 plots.
233 ends up on the grid border. Note that this margin is only applied when
234 a min or max value is not explicitly set. If a margin is specified,
235 the plot will furthermore extend the axis end-point to the nearest
236 whole tick. The default value is "null" for the x axes and 0.02 for y
237 axes which seems appropriate for most cases.
211238
212239 "transform" and "inverseTransform" are callbacks you can put in to
213240 change the way the data is drawn. You can design a function to
222249 inverseTransform: function (v) { return Math.exp(v); }
223250 }
224251
252 Similarly, for reversing the y axis so the values appear in inverse
253 order:
254
255 yaxis: {
256 transform: function (v) { return -v; },
257 inverseTransform: function (v) { return -v; }
258 }
259
225260 Note that for finding extrema, Flot assumes that the transform
226 function does not reorder values (monotonicity is assumed).
261 function does not reorder values (it should be monotone).
227262
228263 The inverseTransform is simply the inverse of the transform function
229264 (so v == inverseTransform(transform(v)) for all relevant v). It is
280315 return res;
281316 }
282317
283
284318 You can control how the ticks look like with "tickDecimals", the
285319 number of decimals to display (default is auto-detected).
286320
287 Alternatively, for ultimate control over how ticks look like you can
321 Alternatively, for ultimate control over how ticks are formatted you can
288322 provide a function to "tickFormatter". The function is passed two
289 parameters, the tick value and an "axis" object with information, and
323 parameters, the tick value and an axis object with information, and
290324 should return a string. The default formatter looks like this:
291325
292326 function formatter(val, axis) {
308342 return val.toFixed(axis.tickDecimals) + " B";
309343 }
310344
345 "labelWidth" and "labelHeight" specifies a fixed size of the tick
346 labels in pixels. They're useful in case you need to align several
347 plots. "reserveSpace" means that even if an axis isn't shown, Flot
348 should reserve space for it - it is useful in combination with
349 labelWidth and labelHeight for aligning multi-axis charts.
350
351 "tickLength" is the length of the tick lines in pixels. By default, the
352 innermost axes will have ticks that extend all across the plot, while
353 any extra axes use small ticks. A value of null means use the default,
354 while a number means small ticks of that length - set it to 0 to hide
355 the lines completely.
356
357 If you set "alignTicksWithAxis" to the number of another axis, e.g.
358 alignTicksWithAxis: 1, Flot will ensure that the autogenerated ticks
359 of this axis are aligned with the ticks of the other axis. This may
360 improve the looks, e.g. if you have one y axis to the left and one to
361 the right, because the grid lines will then match the ticks in both
362 ends. The trade-off is that the forced ticks won't necessarily be at
363 natural places.
364
365
366 Multiple axes
367 =============
368
369 If you need more than one x axis or y axis, you need to specify for
370 each data series which axis they are to use, as described under the
371 format of the data series, e.g. { data: [...], yaxis: 2 } specifies
372 that a series should be plotted against the second y axis.
373
374 To actually configure that axis, you can't use the xaxis/yaxis options
375 directly - instead there are two arrays in the options:
376
377 xaxes: []
378 yaxes: []
379
380 Here's an example of configuring a single x axis and two y axes (we
381 can leave options of the first y axis empty as the defaults are fine):
382
383 {
384 xaxes: [ { position: "top" } ],
385 yaxes: [ { }, { position: "right", min: 20 } ]
386 }
387
388 The arrays get their default values from the xaxis/yaxis settings, so
389 say you want to have all y axes start at zero, you can simply specify
390 yaxis: { min: 0 } instead of adding a min parameter to all the axes.
391
392 Generally, the various interfaces in Flot dealing with data points
393 either accept an xaxis/yaxis parameter to specify which axis number to
394 use (starting from 1), or lets you specify the coordinate directly as
395 x2/x3/... or x2axis/x3axis/... instead of "x" or "xaxis".
396
397
311398 Time series data
312399 ================
313400
395482 %H: hours (left-padded with a zero)
396483 %M: minutes (left-padded with a zero)
397484 %S: seconds (left-padded with a zero)
398 %d: day of month (1-31)
399 %m: month (1-12)
485 %d: day of month (1-31), use %0d for zero-padding
486 %m: month (1-12), use %0m for zero-padding
400487 %y: year (four digits)
401488 %b: month name (customizable)
402489 %p: am/pm, additionally switches %h/%H to 12 hour instead of 24
403490 %P: AM/PM (uppercase version of %p)
491
492 Inserting a zero like %0m or %0d means that the specifier will be
493 left-padded with a zero if it's only single-digit. So %y-%0m-%0d
494 results in unambigious ISO timestamps like 2007-05-10 (for May 10th).
404495
405496 You can customize the month names with the "monthNames" option. For
406497 instance, for Danish you might specify:
452543
453544 points: {
454545 radius: number
546 symbol: "circle" or function
455547 }
456548
457549 bars: {
478570 specify whether and how lines, points and bars should be shown for
479571 each data series. In case you don't specify anything at all, Flot will
480572 default to showing lines (you can turn this off with
481 lines: { show: false}). You can specify the various types
573 lines: { show: false }). You can specify the various types
482574 independently of each other, and Flot will happily draw each of them
483575 in turn (this is probably only useful for lines and points), e.g.
484576
518610 horizontal and then a vertical line. Note that this transforms the
519611 data by adding extra points.
520612
613 For points, you can specify the radius and the symbol. The only
614 built-in symbol type is circles, for other types you can use a plugin
615 or define them yourself by specifying a callback:
616
617 function cross(ctx, x, y, radius, shadow) {
618 var size = radius * Math.sqrt(Math.PI) / 2;
619 ctx.moveTo(x - size, y - size);
620 ctx.lineTo(x + size, y + size);
621 ctx.moveTo(x - size, y + size);
622 ctx.lineTo(x + size, y - size);
623 }
624
625 The parameters are the drawing context, x and y coordinates of the
626 center of the point, a radius which corresponds to what the circle
627 would have used and whether the call is to draw a shadow (due to
628 limited canvas support, shadows are currently faked through extra
629 draws). It's good practice to ensure that the area covered by the
630 symbol is the same as for the circle with the given radius, this
631 ensures that all symbols have approximately the same visual weight.
632
521633 "shadowSize" is the default size of shadows in pixels. Set it to 0 to
522634 remove shadows.
523635
539651 aboveData: boolean
540652 color: color
541653 backgroundColor: color/gradient or null
542 tickColor: color
543654 labelMargin: number
655 axisMargin: number
544656 markings: array of markings or (fn: axes -> array of markings)
545657 borderWidth: number
546658 borderColor: color or null
659 minBorderMargin: number or null
547660 clickable: boolean
548661 hoverable: boolean
549662 autoHighlight: boolean
550663 mouseActiveRadius: number
551664 }
552665
553 The grid is the thing with the axes and a number of ticks. "color" is
554 the color of the grid itself whereas "backgroundColor" specifies the
555 background color inside the grid area. The default value of null means
666 The grid is the thing with the axes and a number of ticks. Many of the
667 things in the grid are configured under the individual axes, but not
668 all. "color" is the color of the grid itself whereas "backgroundColor"
669 specifies the background color inside the grid area, here null means
556670 that the background is transparent. You can also set a gradient, see
557671 the gradient documentation below.
558672
559673 You can turn off the whole grid including tick labels by setting
560 "show" to false. "aboveData" determines whether the grid is drawn on
674 "show" to false. "aboveData" determines whether the grid is drawn
561675 above the data or below (below is default).
562676
563 "tickColor" is the color of the ticks and "labelMargin" is the spacing
564 between tick labels and the grid. Note that you can style the tick
565 labels with CSS, e.g. to change the color. They have class "tickLabel".
677 "labelMargin" is the space in pixels between tick labels and axis
678 line, and "axisMargin" is the space in pixels between axes when there
679 are two next to each other. Note that you can style the tick labels
680 with CSS, e.g. to change the color. They have class "tickLabel".
681
566682 "borderWidth" is the width of the border around the plot. Set it to 0
567683 to disable the border. You can also set "borderColor" if you want the
568684 border to have a different color than the grid lines.
685 "minBorderMargin" controls the default minimum margin around the
686 border - it's used to make sure that points aren't accidentally
687 clipped by the canvas edge so by default the value is computed from
688 the point radius.
569689
570690 "markings" is used to draw simple lines and rectangular areas in the
571691 background of the plot. You can either specify an array of ranges on
572 the form { xaxis: { from, to }, yaxis: { from, to } } (secondary axis
573 coordinates with x2axis/y2axis) or with a function that returns such
574 an array given the axes for the plot in an object as the first
575 parameter.
692 the form { xaxis: { from, to }, yaxis: { from, to } } (with multiple
693 axes, you can specify coordinates for other axes instead, e.g. as
694 x2axis/x3axis/...) or with a function that returns such an array given
695 the axes for the plot in an object as the first parameter.
576696
577697 You can set the color of markings by specifying "color" in the ranges
578698 object. Here's an example array:
591711 would draw a line parallel to the x axis at y = 1. You can control the
592712 line width with "lineWidth" in the range object.
593713
594 An example function might look like this:
714 An example function that makes vertical stripes might look like this:
595715
596716 markings: function (axes) {
597717 var markings = [];
620740
621741 $("#placeholder").bind("plotclick", function (event, pos, item) {
622742 alert("You clicked at " + pos.x + ", " + pos.y);
623 // secondary axis coordinates if present are in pos.x2, pos.y2,
743 // axis coordinates for other axes, if present, are in pos.x2, pos.x3, ...
624744 // if you need global screen coordinates, they are pos.pageX, pos.pageY
625745
626746 if (item) {
756876 interactive things like a selection and point highlights. This
757877 is mostly useful for writing plugins. The redraw doesn't happen
758878 immediately, instead a timer is set to catch multiple successive
759 redraws (e.g. from a mousemove).
879 redraws (e.g. from a mousemove). You can get to the overlay by
880 setting up a drawOverlay hook.
760881
761882 - width()/height()
762883
774895 - pointOffset({ x: xpos, y: ypos })
775896
776897 Returns the calculated offset of the data point at (x, y) in data
777 space within the placeholder div. If you are working with dual axes, you
898 space within the placeholder div. If you are working with multiple axes, you
778899 can specify the x and y axis references, e.g.
779900
780 o = pointOffset({ x: xpos, y: ypos, xaxis: 2, yaxis: 2 })
901 o = pointOffset({ x: xpos, y: ypos, xaxis: 2, yaxis: 3 })
781902 // o.left and o.top now contains the offset within the div
782
903
904 - resize()
905
906 Tells Flot to resize the drawing canvas to the size of the
907 placeholder. You need to run setupGrid() and draw() afterwards as
908 canvas resizing is a destructive operation. This is used
909 internally by the resize plugin.
910
911 - shutdown()
912
913 Cleans up any event handlers Flot has currently registered. This
914 is used internally.
915
783916
784917 There are also some members that let you peek inside the internal
785918 workings of Flot which is useful in some cases. Note that if you change
805938
806939 - getAxes()
807940
808 Gets an object with the axes settings as { xaxis, yaxis, x2axis,
809 y2axis }.
941 Gets an object with the axes. The axes are returned as the
942 attributes of the object, so for instance getAxes().xaxis is the
943 x axis.
810944
811945 Various things are stuffed inside an axis object, e.g. you could
812946 use getAxes().xaxis.ticks to find out what the ticks are for the
813947 xaxis. Two other useful attributes are p2c and c2p, functions for
814948 transforming from data point space to the canvas plot space and
815949 back. Both returns values that are offset with the plot offset.
950 Check the Flot source code for the complete set of attributes (or
951 output an axis with console.log() and inspect it).
952
953 With multiple axes, the extra axes are returned as x2axis, x3axis,
954 etc., e.g. getAxes().y2axis is the second y axis. You can check
955 y2axis.used to see whether the axis is associated with any data
956 points and y2axis.show to see if it is currently shown.
816957
817958 - getPlaceholder()
818959
834975
835976 - getOptions()
836977
837 Gets the options for the plot, in a normalized format with default
838 values filled in.
978 Gets the options for the plot, normalized, with default values
979 filled in. You get a reference to actual values used by Flot, so
980 if you modify the values in here, Flot will use the new values.
981 If you change something, you probably have to call draw() or
982 setupGrid() or triggerRedrawOverlay() to see the change.
839983
840984
841985 Hooks
8641008 6. Setting up event handling for interactive features
8651009
8661010 7. Responding to events, if any
1011
1012 8. Shutdown: this mostly happens in case a plot is overwritten
8671013
8681014 Each hook is simply a function which is put in the appropriate array.
8691015 You can add them through the "hooks" option, and they are also available
9441090 doesn't check it or do any normalization on it afterwards.
9451091
9461092
1093 - drawSeries [phase 5]
1094
1095 function(plot, canvascontext, series)
1096
1097 Hook for custom drawing of a single series. Called just before the
1098 standard drawing routine has been called in the loop that draws
1099 each series.
1100
1101
9471102 - draw [phase 5]
9481103
9491104 function(plot, canvascontext)
9501105
9511106 Hook for drawing on the canvas. Called after the grid is drawn
952 (unless it's disabled) and the series have been plotted (in case
953 any points, lines or bars have been turned on). For examples of how
954 to draw things, look at the source code.
1107 (unless it's disabled or grid.aboveData is set) and the series have
1108 been plotted (in case any points, lines or bars have been turned
1109 on). For examples of how to draw things, look at the source code.
9551110
9561111
9571112 - bindEvents [phase 6]
9801135 order wrong. The hook only gets one event, though (either for the
9811136 overlay or for the static canvas).
9821137
1138 Note that custom plot events generated by Flot are not generated on
1139 eventHolder, but on the div placeholder supplied as the first
1140 argument to the plot call. You can get that with
1141 plot.getPlaceholder() - that's probably also the one you should use
1142 if you need to fire a custom event.
1143
9831144
9841145 - drawOverlay [phase 7]
9851146
9981159 crosshair plugin for an example.
9991160
10001161
1162 - shutdown [phase 8]
1163
1164 function (plot, eventHolder)
1165
1166 Run when plot.shutdown() is called, which usually only happens in
1167 case a plot is overwritten by a new plot. If you're writing a
1168 plugin that adds extra DOM elements or event handlers, you should
1169 add a callback to clean up after you. Take a look at the section in
1170 PLUGINS.txt for more info.
1171
10011172
10021173 Plugins
10031174 -------
10151186 Each plugin registers itself in the global array $.plot.plugins. When
10161187 you make a new plot object with $.plot, Flot goes through this array
10171188 calling the "init" function of each plugin and merging default options
1018 from its "option" attribute. The init function gets a reference to the
1019 plot object created and uses this to register hooks and add new public
1020 methods if needed.
1189 from the "option" attribute of the plugin. The init function gets a
1190 reference to the plot object created and uses this to register hooks
1191 and add new public methods if needed.
10211192
10221193 See the PLUGINS.txt file for details on how to write a plugin. As the
10231194 above description hints, it's actually pretty easy.
1195
1196
1197 Version number
1198 --------------
1199
1200 The version number of Flot is available in $.plot.version.
5353 libraries") for details.
5454
5555
56 Q: Flot doesn't work with [widget framework xyz]!
56 Q: Flot doesn't work with [insert name of Javascript UI framework]!
5757
58 A: The problem is most likely within the framework, or your use of the
59 framework.
60
61 The only non-standard thing used by Flot is the canvas tag; otherwise
62 it is simply a series of absolute positioned divs within the
58 A: The only non-standard thing used by Flot is the canvas tag;
59 otherwise it is simply a series of absolute positioned divs within the
6360 placeholder tag you put in. If this is not working, it's probably
6461 because the framework you're using is doing something weird with the
65 DOM. As a last resort, you might try replotting and see if it helps.
62 DOM, or you're using it the wrong way.
63
64 A common problem is that there's display:none on a container until the
65 user does something. Many tab widgets work this way, and there's
66 nothing wrong with it - you just can't call Flot inside a display:none
67 container as explained in the README so you need to hold off the Flot
68 call until the container is actually displayed (or use
69 visibility:hidden instead of display:none or move the container
70 off-screen).
6671
6772 If you find there's a specific thing we can do to Flot to help, feel
6873 free to submit a bug report. Otherwise, you're welcome to ask for help
69 on the mailing list, but please don't submit a bug report to Flot -
70 try the framework instead.
74 on the forum/mailing list, but please don't submit a bug report to
75 Flot.
+0
-15
Makefile less more
0 # Makefile for generating minified files
1
2 YUICOMPRESSOR_PATH=../yuicompressor-2.3.5.jar
3
4 # if you need another compressor path, just copy the above line to a
5 # file called Makefile.local, customize it and you're good to go
6 -include Makefile.local
7
8 .PHONY: all
9
10 # we cheat and process all .js files instead of listing them
11 all: $(patsubst %.js,%.min.js,$(filter-out %.min.js,$(wildcard *.js)))
12
13 %.min.js: %.js
14 java -jar $(YUICOMPRESSOR_PATH) $< -o $@
0 Flot 0.7
1 --------
2
3 API changes:
4
5 Multiple axes support. Code using dual axes should be changed from
6 using x2axis/y2axis in the options to using an array (although
7 backwards-compatibility hooks are in place). For instance,
8
9 {
10 xaxis: { ... }, x2axis: { ... },
11 yaxis: { ... }, y2axis: { ... }
12 }
13
14 becomes
15
16 {
17 xaxes: [ { ... }, { ... } ],
18 yaxes: [ { ... }, { ... } ]
19 }
20
21 Note that if you're just using one axis, continue to use the
22 xaxis/yaxis directly (it now sets the default settings for the
23 arrays). Plugins touching the axes must be ported to take the extra
24 axes into account, check the source to see some examples.
25
26 A related change is that the visibility of axes is now auto-detected.
27 So if you were relying on an axis to show up even without any data in
28 the chart, you now need to set the axis "show" option explicitly.
29
30 "tickColor" on the grid options is now deprecated in favour of a
31 corresponding option on the axes, so { grid: { tickColor: "#000" }}
32 becomes { xaxis: { tickColor: "#000"}, yaxis: { tickColor: "#000"} },
33 but if you just configure a base color Flot will now autogenerate a
34 tick color by adding transparency. Backwards-compatibility hooks are
35 in place.
36
37 Final note: now that IE 9 is coming out with canvas support, you may
38 want to adapt the excanvas include to skip loading it in IE 9 (the
39 examples have been adapted thanks to Ryley Breiddal). An alternative
40 to excanvas using Flash has also surfaced, if your graphs are slow in
41 IE, you may want to give it a spin:
42
43 http://code.google.com/p/flashcanvas/
44
45
46 Changes:
47
48 - Support for specifying a bottom for each point for line charts when
49 filling them, this means that an arbitrary bottom can be used
50 instead of just the x axis (based on patches patiently provided by
51 Roman V. Prikhodchenko).
52 - New fillbetween plugin that can compute a bottom for a series from
53 another series, useful for filling areas between lines (see new
54 example percentiles.html for a use case).
55 - More predictable handling of gaps for the stacking plugin, now all
56 undefined ranges are skipped.
57 - Stacking plugin can stack horizontal bar charts.
58 - Navigate plugin now redraws the plot while panning instead of only
59 after the fact (can be disabled by setting the pan.frameRate option
60 to null), raised by lastthemy (issue 235).
61 - Date formatter now accepts %0m and %0d to get a zero-padded month or
62 day (issue raised by Maximillian Dornseif).
63 - Revamped internals to support an unlimited number of axes, not just
64 dual (sponsored by Flight Data Services,
65 www.flightdataservices.com).
66 - New setting on axes, "tickLength", to control the size of ticks or
67 turn them off without turning off the labels.
68 - Axis labels are now put in container divs with classes, for instance
69 labels in the x axes can be reached via ".xAxis .tickLabel".
70 - Support for setting the color of an axis (sponsored by Flight Data
71 Services, www.flightdataservices.com).
72 - Tick color is now auto-generated as the base color with some
73 transparency (unless you override it).
74 - Support for aligning ticks in the axes with "alignTicksWithAxis" to
75 ensure that they appear next to each other rather than in between,
76 at the expense of possibly awkward tick steps (sponsored by Flight
77 Data Services, www.flightdataservices.com).
78 - Support for customizing the point type through a callback when
79 plotting points and new symbol plugin with some predefined point
80 types (sponsored by Utility Data Corporation).
81 - Resize plugin for automatically redrawing when the placeholder
82 changes size, e.g. on window resizes (sponsored by Novus Partners).
83 A resize() method has been added to plot object facilitate this.
84 - Support Infinity/-Infinity for plotting asymptotes by hacking it
85 into +/-Number.MAX_VALUE (reported by rabaea.mircea).
86 - Support for restricting navigate plugin to not pan/zoom an axis (based
87 on patch by kkaefer).
88 - Support for providing the drag cursor for the navigate plugin as an
89 option (based on patch by Kelly T. Moore).
90 - Options for controlling whether an axis is shown or not (suggestion
91 by Timo Tuominen) and whether to reserve space for it even if it
92 isn't shown.
93 - New attribute $.plot.version with the Flot version as a string.
94 - The version comment is now included in the minified jquery.flot.min.js.
95 - New options.grid.minBorderMargin for adjusting the minimum margin
96 provided around the border (based on patch by corani, issue 188).
97 - Refactor replot behaviour so Flot tries to reuse the existing
98 canvas, adding shutdown() methods to the plot (based on patch by
99 Ryley Breiddal, issue 269). This prevents a memory leak in Chrome
100 and hopefully makes replotting faster for those who are using $.plot
101 instead of .setData()/.draw(). Also update jQuery to 1.5.1 to
102 prevent IE leaks fixed in jQuery.
103 - New real-time line chart example.
104
105 - New hooks: drawSeries, shutdown
106
107 Bug fixes:
108
109 - Fixed problem with findNearbyItem and bars on top of each other
110 (reported by ragingchikn, issue 242).
111 - Fixed problem with ticks and the border (based on patch from
112 ultimatehustler69, issue 236).
113 - Fixed problem with plugins adding options to the series objects.
114 - Fixed a problem introduced in 0.6 with specifying a gradient with {
115 brightness: x, opacity: y }.
116 - Don't use $.browser.msie, check for getContext on the created canvas
117 element instead and try to use excanvas if it's not found (fixes IE
118 9 compatibility).
119 - highlight(s, index) was looking up the point in the original s.data
120 instead of in the computed datapoints array, which breaks with
121 plugins that modify the datapoints (such as the stacking plugin).
122 Issue 316 reported by curlypaul924.
123 - More robust handling of axis from data passed in from getData()
124 (problem reported by Morgan).
125 - Fixed problem with turning off bar outline (issue 253, fix by Jordi
126 Castells).
127 - Check the selection passed into setSelection in the selection
128 plugin, to guard against errors when synchronizing plots (fix by Lau
129 Bech Lauritzen).
130 - Fix bug in crosshair code with mouseout resetting the crosshair even
131 if it is locked (fix by Lau Bech Lauritzen and Banko Adam).
132 - Fix bug with points plotting using line width from lines rather than
133 points.
134 - Fix bug with passing non-array 0 data (for plugins that don't expect
135 arrays, patch by vpapp1).
136 - Fix errors in JSON in examples so they work with jQuery 1.4.2
137 (fix reported by honestbleeps, issue 357).
138 - Fix bug with tooltip in interacting.html, this makes the tooltip
139 much smoother (fix by bdkahn). Fix related bug inside highlighting
140 handler in Flot.
141 - Use closure trick to make inline colorhelpers plugin respect
142 jQuery.noConflict(true), renaming the global jQuery object (reported
143 by Nick Stielau).
144 - Listen for mouseleave events and fire a plothover event with empty
145 item when it occurs to drop highlights when the mouse leaves the
146 plot (reported by by outspirit).
147 - Fix bug with using aboveData with a background (reported by
148 amitayd).
149 - Fix possible excanvas leak (report and suggested fix by tom9729).
150 - Fix bug with backwards compatibility for shadowSize = 0 (report and
151 suggested fix by aspinak).
152 - Adapt examples to skip loading excanvas (fix by Ryley Breiddal).
153 - Fix bug that prevent a simple f(x) = -x transform from working
154 correctly (fix by Mike, issue 263).
155 - Fix bug in restoring cursor in navigate plugin (reported by Matteo
156 Gattanini, issue 395).
157 - Fix bug in picking items when transform/inverseTransform is in use
158 (reported by Ofri Raviv, and patches and analysis by Jan and Tom
159 Paton, issue 334 and 467).
160 - Fix problem with unaligned ticks and hover/click events caused by
161 padding on the placeholder by hardcoding the placeholder padding to
162 0 (reported by adityadineshsaxena, Matt Sommer, Daniel Atos and some
163 other people, issue 301).
164 - Update colorhelpers plugin to avoid dying when trying to parse an
165 invalid string (reported by cadavor, issue 483).
166
167
0168 Flot 0.6
1169 --------
2170
6174 passing selection: { mode: something }, you MUST include the file
7175 jquery.flot.selection.js after jquery.flot.js. This reduces the size
8176 of base Flot and makes it easier to customize the selection as well as
9 improving code clarity. The change is based on patch from andershol.
177 improving code clarity. The change is based on a patch from andershol.
10178
11179 2. In the global options specified in the $.plot command,
12180 "lines", "points", "bars" and "shadowSize" have been moved to a
00 Writing plugins
11 ---------------
22
3 To make a new plugin, create an init function and a set of options (if
4 needed), stuff it into an object and put it in the $.plot.plugins
5 array. For example:
3 All you need to do to make a new plugin is creating an init function
4 and a set of options (if needed), stuffing it into an object and
5 putting it in the $.plot.plugins array. For example:
66
7 function myCoolPluginInit(plot) { plot.coolstring = "Hello!" };
8 var myCoolOptions = { coolstuff: { show: true } }
9 $.plot.plugins.push({ init: myCoolPluginInit, options: myCoolOptions });
7 function myCoolPluginInit(plot) {
8 plot.coolstring = "Hello!";
9 };
1010
11 // now when $.plot is called, the returned object will have the
11 $.plot.plugins.push({ init: myCoolPluginInit, options: { ... } });
12
13 // if $.plot is called, it will return a plot object with the
1214 // attribute "coolstring"
1315
1416 Now, given that the plugin might run in many different places, it's
15 a good idea to avoid leaking names. We can avoid this by wrapping the
16 above lines in an anonymous function which we call immediately, like
17 a good idea to avoid leaking names. The usual trick here is wrap the
18 above lines in an anonymous function which is called immediately, like
1719 this: (function () { inner code ... })(). To make it even more robust
1820 in case $ is not bound to jQuery but some other Javascript library, we
1921 can write it as
2325 // ...
2426 })(jQuery);
2527
28 There's a complete example below, but you should also check out the
29 plugins bundled with Flot.
30
31
32 Complete example
33 ----------------
34
2635 Here is a simple debug plugin which alerts each of the series in the
2736 plot. It has a single option that control whether it is enabled and
2837 how much info to output:
7483 - Variables in the init function can be used to store plot-specific
7584 state between the hooks.
7685
86 The two last points are important because there may be multiple plots
87 on the same page, and you'd want to make sure they are not mixed up.
88
89
90 Shutting down a plugin
91 ----------------------
92
93 Each plot object has a shutdown hook which is run when plot.shutdown()
94 is called. This usually mostly happens in case another plot is made on
95 top of an existing one.
96
97 The purpose of the hook is to give you a chance to unbind any event
98 handlers you've registered and remove any extra DOM things you've
99 inserted.
100
101 The problem with event handlers is that you can have registered a
102 handler which is run in some point in the future, e.g. with
103 setTimeout(). Meanwhile, the plot may have been shutdown and removed,
104 but because your event handler is still referencing it, it can't be
105 garbage collected yet, and worse, if your handler eventually runs, it
106 may overwrite stuff on a completely different plot.
107
77108
78 Options guidelines
79 ==================
109 Some hints on the options
110 -------------------------
80111
81112 Plugins should always support appropriate options to enable/disable
82113 them because the plugin user may have several plots on the same page
83 where only one should use the plugin.
114 where only one should use the plugin. In most cases it's probably a
115 good idea if the plugin is turned off rather than on per default, just
116 like most of the powerful features in Flot.
84117
85 If the plugin needs series-specific options, you can put them in
86 "series" in the options object, e.g.
118 If the plugin needs options that are specific to each series, like the
119 points or lines options in core Flot, you can put them in "series" in
120 the options object, e.g.
87121
88122 var options = {
89123 series: {
94128 }
95129 }
96130
97 Then they will be copied by Flot into each series, providing the
98 defaults in case the plugin user doesn't specify any. Again, in most
99 cases it's probably a good idea if the plugin is turned off rather
100 than on per default, just like most of the powerful features in Flot.
131 Then they will be copied by Flot into each series, providing default
132 values in case none are specified.
101133
102134 Think hard and long about naming the options. These names are going to
103135 be public API, and code is going to depend on them if the plugin is
1515
1616 Just include the Javascript file after you've included jQuery.
1717
18 Note that you need to get a version of Excanvas (e.g. the one bundled
19 with Flot) which is canvas emulation on Internet Explorer. You can
18 Generally, all browsers that support the HTML5 canvas tag are
19 supported.
20
21 For support for Internet Explorer < 9, you can use Excanvas, a canvas
22 emulator; this is used in the examples bundled with Flot. You just
2023 include the excanvas script like this:
2124
22 <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.pack.js"></script><![endif]-->
25 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]-->
2326
2427 If it's not working on your development IE 6.0, check that it has
25 support for VML which excanvas is relying on. It appears that some
28 support for VML which Excanvas is relying on. It appears that some
2629 stripped down versions used for test environments on virtual machines
2730 lack the VML support.
28
29 Also note that you need at least jQuery 1.2.6 (but at least jQuery
30 1.3.2 is recommended for interactive charts because of performance
31 improvements in event handling).
31
32 You can also try using Flashcanvas (see
33 http://code.google.com/p/flashcanvas/), which uses Flash to do the
34 emulation. Although Flash can be a bit slower to load than VML, if
35 you've got a lot of points, the Flash version can be much faster
36 overall. Flot contains some wrapper code for activating Excanvas which
37 Flashcanvas is compatible with.
38
39 You need at least jQuery 1.2.6, but try at least 1.3.2 for interactive
40 charts because of performance improvements in event handling.
3241
3342
3443 Basic usage
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
4444 <input class="dataUpdate" type="button" value="Poll for data">
4545 </p>
4646
47 <script id="source" language="javascript" type="text/javascript">
47 <script type="text/javascript">
4848 $(function () {
4949 var options = {
5050 lines: { show: true },
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
1818 manipulation, e.g. for labels. For drawing custom shapes there is
1919 also direct access to the canvas.</p>
2020
21 <script id="source" language="javascript" type="text/javascript">
21 <script type="text/javascript">
2222 $(function () {
2323 // generate a dataset
2424 var d1 = [];
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
1818 plot function with the data. The axes are automatically
1919 scaled.</p>
2020
21 <script id="source" language="javascript" type="text/javascript">
21 <script type="text/javascript">
2222 $(function () {
2323 var d1 = [];
2424 for (var i = 0; i < 14; i += 0.5)
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9]]
33 }
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2]]
33 }
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5]]
33 }
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1]]
33 }
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
33 }
00 {
1 label: 'Europe (EU27)',
2 data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
1 "label": "Europe (EU27)",
2 "data": [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
33 }
00 {
1 label: 'Japan',
2 data: [[1999, -0.1], [2000, 2.9], [2001, 0.2], [2002, 0.3], [2003, 1.4], [2004, 2.7], [2005, 1.9], [2006, 2.0], [2007, 2.3], [2008, -0.7]]
1 "label": "Japan",
2 "data": [[1999, -0.1], [2000, 2.9], [2001, 0.2], [2002, 0.3], [2003, 1.4], [2004, 2.7], [2005, 1.9], [2006, 2.0], [2007, 2.3], [2008, -0.7]]
33 }
00 {
1 label: 'USA',
2 data: [[1999, 4.4], [2000, 3.7], [2001, 0.8], [2002, 1.6], [2003, 2.5], [2004, 3.6], [2005, 2.9], [2006, 2.8], [2007, 2.0], [2008, 1.1]]
1 "label": "USA",
2 "data": [[1999, 4.4], [2000, 3.7], [2001, 0.8], [2002, 1.6], [2003, 2.5], [2004, 3.6], [2005, 2.9], [2006, 2.8], [2007, 2.0], [2008, 1.1]]
33 }
+0
-39
examples/dual-axis.html less more
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 </head>
10 <body>
11 <h1>Flot Examples</h1>
12
13 <div id="placeholder" style="width:600px;height:300px;"></div>
14
15 <p>Dual axis support showing the raw oil price in US $/barrel of
16 crude oil (left axis) vs. the exchange rate from US $ to € (right
17 axis).</p>
18
19 <p>As illustrated, you can put in secondary y and x axes if you
20 need to. For each data series, simply specify the axis number.</p>
21
22 <script id="source" language="javascript" type="text/javascript">
23 $(function () {
24 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]];
25 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]];
26
27 $.plot($("#placeholder"),
28 [ { data: oilprices, label: "Oil price ($)" },
29 { data: exchangerates, label: "USD/EUR exchange rate", yaxis: 2 }],
30 {
31 xaxis: { mode: 'time' },
32 yaxis: { min: 0 },
33 y2axis: { tickFormatter: function (v, axis) { return v.toFixed(axis.tickDecimals) +"€" }},
34 legend: { position: 'sw' } });
35 });
36 </script>
37 </body>
38 </html>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
1616 combinations of these, in the same plot and even on the same data
1717 series.</p>
1818
19 <script id="source" language="javascript" type="text/javascript">
19 <script type="text/javascript">
2020 $(function () {
2121 var d1 = [];
2222 for (var i = 0; i < 14; i += 0.5)
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.image.js"></script>
2525 incomplete images). The plugin comes with a couple of helpers
2626 for doing that.</p>
2727
28 <script id="source" language="javascript" type="text/javascript">
28 <script type="text/javascript">
2929 $(function () {
3030 var data = [ [ ["hs-2004-27-a-large_web.jpg", -10, -10, 10, 10] ] ];
3131 var options = {
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
5 <link href="layout.css" rel="stylesheet" type="text/css">
96 </head>
107 <body>
118 <h1>Flot Examples</h1>
1613 <li><a href="basic.html">Basic example</a></li>
1714 <li><a href="graph-types.html">Different graph types</a></li>
1815 <li><a href="setting-options.html">Setting various options</a> and <a href="annotating.html">annotating a chart</a></li>
19 <li><a href="ajax.html">Updating graphs with AJAX</a></li>
16 <li><a href="ajax.html">Updating graphs with AJAX</a> and <a href="realtime.html">real-time updates</a></li>
2017 </ul>
2118
2219 <p>Being interactive:</p>
2320
2421 <ul>
2522 <li><a href="turning-series.html">Turning series on/off</a></li>
26 <li><a href="selection.html">Rectangular selection support and zooming</a> and <a href="zooming.html">zooming with overview</a></li> (both with selection plugin)
23 <li><a href="selection.html">Rectangular selection support and zooming</a> and <a href="zooming.html">zooming with overview</a> (both with selection plugin)</li>
2724 <li><a href="interacting.html">Interacting with the data points</a></li>
2825 <li><a href="navigate.html">Panning and zooming</a> (with navigation plugin)</li>
26 <li><a href="resize.html">Automatically redraw when window is resized</a> (with resize plugin)</li>
2927 </ul>
3028
31 <p>Some more esoteric features:</p>
29 <p>Various features:</p>
3230
3331 <ul>
32 <li><a href="symbols.html">Using other symbols than circles for points</a> (with symbol plugin)</li>
3433 <li><a href="time.html">Plotting time series</a> and <a href="visitors.html">visitors per day with zooming and weekends</a> (with selection plugin)</li>
35 <li><a href="dual-axis.html">Dual axis support</a></li>
34 <li><a href="multiple-axes.html">Multiple axes</a> and <a href="interacting-axes.html">interacting with the axes</a></li>
3635 <li><a href="thresholding.html">Thresholding the data</a> (with threshold plugin)</li>
3736 <li><a href="stacking.html">Stacked charts</a> (with stacking plugin)</li>
37 <li><a href="percentiles.html">Using filled areas to plot percentiles</a> (with fillbetween plugin)</li>
3838 <li><a href="tracking.html">Tracking curves with crosshair</a> (with crosshair plugin)</li>
3939 <li><a href="image.html">Plotting prerendered images</a> (with image plugin)</li>
40 <li><a href="pie.html">Pie charts</a> (with pie plugin)</li>
4041 </ul>
4142 </body>
4243 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 </head>
10 <body>
11 <h1>Flot Examples</h1>
12
13 <div id="placeholder" style="width:600px;height:300px;"></div>
14
15 <p>With multiple axes, you sometimes need to interact with them. A
16 simple way to do this is to draw the plot, deduce the axis
17 placements and insert a couple of divs on top to catch events.
18 Try clicking an axis.</p>
19
20 <p id="click"></p>
21
22 <script type="text/javascript">
23 $(function () {
24 function generate(start, end, fn) {
25 var res = [];
26 for (var i = 0; i <= 100; ++i) {
27 var x = start + i / 100 * (end - start);
28 res.push([x, fn(x)]);
29 }
30 return res;
31 }
32
33 var data = [
34 { data: generate(0, 10, function (x) { return Math.sqrt(x)}), xaxis: 1, yaxis:1 },
35 { data: generate(0, 10, function (x) { return Math.sin(x)}), xaxis: 1, yaxis:2 },
36 { data: generate(0, 10, function (x) { return Math.cos(x)}), xaxis: 1, yaxis:3 },
37 { data: generate(2, 10, function (x) { return Math.tan(x)}), xaxis: 2, yaxis: 4 }
38 ];
39
40 var plot = $.plot($("#placeholder"),
41 data,
42 {
43 xaxes: [
44 { position: 'bottom' },
45 { position: 'top'}
46 ],
47 yaxes: [
48 { position: 'left' },
49 { position: 'left' },
50 { position: 'right' },
51 { position: 'left' }
52 ]
53 });
54
55 // now for each axis, create a div
56
57 function getBoundingBoxForAxis(plot, axis) {
58 var left = axis.box.left, top = axis.box.top,
59 right = left + axis.box.width, bottom = top + axis.box.height;
60
61 // some ticks may stick out, enlarge the box to encompass all ticks
62 var cls = axis.direction + axis.n + 'Axis';
63 plot.getPlaceholder().find('.' + cls + ' .tickLabel').each(function () {
64 var pos = $(this).position();
65 left = Math.min(pos.left, left);
66 top = Math.min(pos.top, top);
67 right = Math.max(Math.round(pos.left) + $(this).outerWidth(), right);
68 bottom = Math.max(Math.round(pos.top) + $(this).outerHeight(), bottom);
69 });
70
71 return { left: left, top: top, width: right - left, height: bottom - top };
72 }
73
74 $.each(plot.getAxes(), function (i, axis) {
75 if (!axis.show)
76 return;
77
78 var box = getBoundingBoxForAxis(plot, axis);
79
80 $('<div class="axisTarget" style="position:absolute;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
81 .data('axis.direction', axis.direction)
82 .data('axis.n', axis.n)
83 .css({ backgroundColor: "#f00", opacity: 0, cursor: "pointer" })
84 .appendTo(plot.getPlaceholder())
85 .hover(
86 function () { $(this).css({ opacity: 0.10 }) },
87 function () { $(this).css({ opacity: 0 }) }
88 )
89 .click(function () {
90 $("#click").text("You clicked the " + axis.direction + axis.n + "axis!")
91 });
92 });
93 });
94 </script>
95 </body>
96 </html>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
2323
2424 <p><input id="enableTooltip" type="checkbox">Enable tooltip</p>
2525
26 <script id="source" language="javascript" type="text/javascript">
26 <script type="text/javascript">
2727 $(function () {
2828 var sin = [], cos = [];
2929 for (var i = 0; i < 14; i += 0.5) {
6161
6262 if ($("#enableTooltip:checked").length > 0) {
6363 if (item) {
64 if (previousPoint != item.datapoint) {
65 previousPoint = item.datapoint;
64 if (previousPoint != item.dataIndex) {
65 previousPoint = item.dataIndex;
6666
6767 $("#tooltip").remove();
6868 var x = item.datapoint[0].toFixed(2),
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 </head>
10 <body>
11 <h1>Flot Examples</h1>
12
13 <div id="placeholder" style="width:600px;height:300px;"></div>
14
15 <p>Multiple axis support showing the raw oil price in US $/barrel of
16 crude oil vs. the exchange rate from US $ to €.</p>
17
18 <p>As illustrated, you can put in multiple axes if you
19 need to. For each data series, simply specify the axis number.
20 In the options, you can then configure where you want the extra
21 axes to appear.</p>
22
23 <p>Position axis <button>left</button> or <button>right</button>.</p>
24
25 <script type="text/javascript">
26 $(function () {
27 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]];
28 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]];
29
30 function euroFormatter(v, axis) {
31 return v.toFixed(axis.tickDecimals) +"€";
32 }
33
34 function doPlot(position) {
35 $.plot($("#placeholder"),
36 [ { data: oilprices, label: "Oil price ($)" },
37 { data: exchangerates, label: "USD/EUR exchange rate", yaxis: 2 }],
38 {
39 xaxes: [ { mode: 'time' } ],
40 yaxes: [ { min: 0 },
41 {
42 // align if we are to the right
43 alignTicksWithAxis: position == "right" ? 1 : null,
44 position: position,
45 tickFormatter: euroFormatter
46 } ],
47 legend: { position: 'sw' }
48 });
49 }
50
51 doPlot("right");
52
53 $("button").click(function () {
54 doPlot($(this).text());
55 });
56 });
57 </script>
58 </body>
59 </html>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.navigate.js"></script>
10 <style>
10 <style type="text/css">
1111 #placeholder .button {
1212 position: absolute;
1313 cursor: pointer;
4040 top right in the plot.</p>
4141
4242
43 <script id="source" language="javascript" type="text/javascript">
43 <script type="text/javascript">
4444 $(function () {
4545 // generate data set from a parametric function with a fractal
4646 // look
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 <script language="javascript" type="text/javascript" src="../jquery.flot.fillbetween.js"></script>
10 </head>
11 <body>
12 <h1>Flot Examples</h1>
13
14 <div id="placeholder" style="width:600px;height:400px;"></div>
15
16 <p>Height in centimeters of individuals from the US (2003-2006) as function of
17 age in years (source: <a href="http://www.cdc.gov/nchs/data/nhsr/nhsr010.pdf">CDC</a>).
18 The 15%-85%, 25%-75% and 50% percentiles are indicated.</p>
19
20 <p>For each point of a filled curve, you can specify an arbitrary
21 bottom. As this example illustrates, this can be useful for
22 plotting percentiles. If you have the data sets available without
23 appropriate fill bottoms, you can use the fillbetween plugin to
24 compute the data point bottoms automatically.</p>
25
26 <script type="text/javascript">
27 $(function () {
28 var males = {'15%': [[2, 88.0], [3, 93.3], [4, 102.0], [5, 108.5], [6, 115.7], [7, 115.6], [8, 124.6], [9, 130.3], [10, 134.3], [11, 141.4], [12, 146.5], [13, 151.7], [14, 159.9], [15, 165.4], [16, 167.8], [17, 168.7], [18, 169.5], [19, 168.0]], '90%': [[2, 96.8], [3, 105.2], [4, 113.9], [5, 120.8], [6, 127.0], [7, 133.1], [8, 139.1], [9, 143.9], [10, 151.3], [11, 161.1], [12, 164.8], [13, 173.5], [14, 179.0], [15, 182.0], [16, 186.9], [17, 185.2], [18, 186.3], [19, 186.6]], '25%': [[2, 89.2], [3, 94.9], [4, 104.4], [5, 111.4], [6, 117.5], [7, 120.2], [8, 127.1], [9, 132.9], [10, 136.8], [11, 144.4], [12, 149.5], [13, 154.1], [14, 163.1], [15, 169.2], [16, 170.4], [17, 171.2], [18, 172.4], [19, 170.8]], '10%': [[2, 86.9], [3, 92.6], [4, 99.9], [5, 107.0], [6, 114.0], [7, 113.5], [8, 123.6], [9, 129.2], [10, 133.0], [11, 140.6], [12, 145.2], [13, 149.7], [14, 158.4], [15, 163.5], [16, 166.9], [17, 167.5], [18, 167.1], [19, 165.3]], 'mean': [[2, 91.9], [3, 98.5], [4, 107.1], [5, 114.4], [6, 120.6], [7, 124.7], [8, 131.1], [9, 136.8], [10, 142.3], [11, 150.0], [12, 154.7], [13, 161.9], [14, 168.7], [15, 173.6], [16, 175.9], [17, 176.6], [18, 176.8], [19, 176.7]], '75%': [[2, 94.5], [3, 102.1], [4, 110.8], [5, 117.9], [6, 124.0], [7, 129.3], [8, 134.6], [9, 141.4], [10, 147.0], [11, 156.1], [12, 160.3], [13, 168.3], [14, 174.7], [15, 178.0], [16, 180.2], [17, 181.7], [18, 181.3], [19, 182.5]], '85%': [[2, 96.2], [3, 103.8], [4, 111.8], [5, 119.6], [6, 125.6], [7, 131.5], [8, 138.0], [9, 143.3], [10, 149.3], [11, 159.8], [12, 162.5], [13, 171.3], [14, 177.5], [15, 180.2], [16, 183.8], [17, 183.4], [18, 183.5], [19, 185.5]], '50%': [[2, 91.9], [3, 98.2], [4, 106.8], [5, 114.6], [6, 120.8], [7, 125.2], [8, 130.3], [9, 137.1], [10, 141.5], [11, 149.4], [12, 153.9], [13, 162.2], [14, 169.0], [15, 174.8], [16, 176.0], [17, 176.8], [18, 176.4], [19, 177.4]]};
29 var females = {'15%': [[2, 84.8], [3, 93.7], [4, 100.6], [5, 105.8], [6, 113.3], [7, 119.3], [8, 124.3], [9, 131.4], [10, 136.9], [11, 143.8], [12, 149.4], [13, 151.2], [14, 152.3], [15, 155.9], [16, 154.7], [17, 157.0], [18, 156.1], [19, 155.4]], '90%': [[2, 95.6], [3, 104.1], [4, 111.9], [5, 119.6], [6, 127.6], [7, 133.1], [8, 138.7], [9, 147.1], [10, 152.8], [11, 161.3], [12, 166.6], [13, 167.9], [14, 169.3], [15, 170.1], [16, 172.4], [17, 169.2], [18, 171.1], [19, 172.4]], '25%': [[2, 87.2], [3, 95.9], [4, 101.9], [5, 107.4], [6, 114.8], [7, 121.4], [8, 126.8], [9, 133.4], [10, 138.6], [11, 146.2], [12, 152.0], [13, 153.8], [14, 155.7], [15, 158.4], [16, 157.0], [17, 158.5], [18, 158.4], [19, 158.1]], '10%': [[2, 84.0], [3, 91.9], [4, 99.2], [5, 105.2], [6, 112.7], [7, 118.0], [8, 123.3], [9, 130.2], [10, 135.0], [11, 141.1], [12, 148.3], [13, 150.0], [14, 150.7], [15, 154.3], [16, 153.6], [17, 155.6], [18, 154.7], [19, 153.1]], 'mean': [[2, 90.2], [3, 98.3], [4, 105.2], [5, 112.2], [6, 119.0], [7, 125.8], [8, 131.3], [9, 138.6], [10, 144.2], [11, 151.3], [12, 156.7], [13, 158.6], [14, 160.5], [15, 162.1], [16, 162.9], [17, 162.2], [18, 163.0], [19, 163.1]], '75%': [[2, 93.2], [3, 101.5], [4, 107.9], [5, 116.6], [6, 122.8], [7, 129.3], [8, 135.2], [9, 143.7], [10, 148.7], [11, 156.9], [12, 160.8], [13, 163.0], [14, 165.0], [15, 165.8], [16, 168.7], [17, 166.2], [18, 167.6], [19, 168.0]], '85%': [[2, 94.5], [3, 102.8], [4, 110.4], [5, 119.0], [6, 125.7], [7, 131.5], [8, 137.9], [9, 146.0], [10, 151.3], [11, 159.9], [12, 164.0], [13, 166.5], [14, 167.5], [15, 168.5], [16, 171.5], [17, 168.0], [18, 169.8], [19, 170.3]], '50%': [[2, 90.2], [3, 98.1], [4, 105.2], [5, 111.7], [6, 118.2], [7, 125.6], [8, 130.5], [9, 138.3], [10, 143.7], [11, 151.4], [12, 156.7], [13, 157.7], [14, 161.0], [15, 162.0], [16, 162.8], [17, 162.2], [18, 162.8], [19, 163.3]]};
30
31 var dataset = [
32 { label: 'Female mean', data: females['mean'], lines: { show: true }, color: "rgb(255,50,50)" },
33 { id: 'f15%', data: females['15%'], lines: { show: true, lineWidth: 0, fill: false }, color: "rgb(255,50,50)" },
34 { id: 'f25%', data: females['25%'], lines: { show: true, lineWidth: 0, fill: 0.2 }, color: "rgb(255,50,50)", fillBetween: 'f15%' },
35 { id: 'f50%', data: females['50%'], lines: { show: true, lineWidth: 0.5, fill: 0.4, shadowSize: 0 }, color: "rgb(255,50,50)", fillBetween: 'f25%' },
36 { id: 'f75%', data: females['75%'], lines: { show: true, lineWidth: 0, fill: 0.4 }, color: "rgb(255,50,50)", fillBetween: 'f50%' },
37 { id: 'f85%', data: females['85%'], lines: { show: true, lineWidth: 0, fill: 0.2 }, color: "rgb(255,50,50)", fillBetween: 'f75%' },
38
39 { label: 'Male mean', data: males['mean'], lines: { show: true }, color: "rgb(50,50,255)" },
40 { id: 'm15%', data: males['15%'], lines: { show: true, lineWidth: 0, fill: false }, color: "rgb(50,50,255)" },
41 { id: 'm25%', data: males['25%'], lines: { show: true, lineWidth: 0, fill: 0.2 }, color: "rgb(50,50,255)", fillBetween: 'm15%' },
42 { id: 'm50%', data: males['50%'], lines: { show: true, lineWidth: 0.5, fill: 0.4, shadowSize: 0 }, color: "rgb(50,50,255)", fillBetween: 'm25%' },
43 { id: 'm75%', data: males['75%'], lines: { show: true, lineWidth: 0, fill: 0.4 }, color: "rgb(50,50,255)", fillBetween: 'm50%' },
44 { id: 'm85%', data: males['85%'], lines: { show: true, lineWidth: 0, fill: 0.2 }, color: "rgb(50,50,255)", fillBetween: 'm75%' }
45 ]
46
47 $.plot($("#placeholder"), dataset, {
48 xaxis: { tickDecimals: 0 },
49 yaxis: { tickFormatter: function (v) { return v + " cm"; } },
50 legend: { position: 'se' }
51 });
52 });
53 </script>
54
55 </body>
56 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Pie Examples</title>
5 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
6 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
7 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.pie.js"></script>
9
10 <script type="text/javascript">
11 $(function () {
12 // data
13 /*var data = [
14 { label: "Series1", data: 10},
15 { label: "Series2", data: 30},
16 { label: "Series3", data: 90},
17 { label: "Series4", data: 70},
18 { label: "Series5", data: 80},
19 { label: "Series6", data: 110}
20 ];*/
21 /*var data = [
22 { label: "Series1", data: [[1,10]]},
23 { label: "Series2", data: [[1,30]]},
24 { label: "Series3", data: [[1,90]]},
25 { label: "Series4", data: [[1,70]]},
26 { label: "Series5", data: [[1,80]]},
27 { label: "Series6", data: [[1,0]]}
28 ];*/
29 var data = [];
30 var series = Math.floor(Math.random()*10)+1;
31 for( var i = 0; i<series; i++)
32 {
33 data[i] = { label: "Series"+(i+1), data: Math.floor(Math.random()*100)+1 }
34 }
35
36 // DEFAULT
37 $.plot($("#default"), data,
38 {
39 series: {
40 pie: {
41 show: true
42 }
43 }
44 });
45
46 // GRAPH 1
47 $.plot($("#graph1"), data,
48 {
49 series: {
50 pie: {
51 show: true
52 }
53 },
54 legend: {
55 show: false
56 }
57 });
58
59 // GRAPH 2
60 $.plot($("#graph2"), data,
61 {
62 series: {
63 pie: {
64 show: true,
65 radius: 1,
66 label: {
67 show: true,
68 radius: 1,
69 formatter: function(label, series){
70 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
71 },
72 background: { opacity: 0.8 }
73 }
74 }
75 },
76 legend: {
77 show: false
78 }
79 });
80
81 // GRAPH 3
82 $.plot($("#graph3"), data,
83 {
84 series: {
85 pie: {
86 show: true,
87 radius: 1,
88 label: {
89 show: true,
90 radius: 3/4,
91 formatter: function(label, series){
92 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
93 },
94 background: { opacity: 0.5 }
95 }
96 }
97 },
98 legend: {
99 show: false
100 }
101 });
102
103 // GRAPH 4
104 $.plot($("#graph4"), data,
105 {
106 series: {
107 pie: {
108 show: true,
109 radius: 1,
110 label: {
111 show: true,
112 radius: 3/4,
113 formatter: function(label, series){
114 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
115 },
116 background: {
117 opacity: 0.5,
118 color: '#000'
119 }
120 }
121 }
122 },
123 legend: {
124 show: false
125 }
126 });
127
128 // GRAPH 5
129 $.plot($("#graph5"), data,
130 {
131 series: {
132 pie: {
133 show: true,
134 radius: 3/4,
135 label: {
136 show: true,
137 radius: 3/4,
138 formatter: function(label, series){
139 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
140 },
141 background: {
142 opacity: 0.5,
143 color: '#000'
144 }
145 }
146 }
147 },
148 legend: {
149 show: false
150 }
151 });
152
153 // GRAPH 6
154 $.plot($("#graph6"), data,
155 {
156 series: {
157 pie: {
158 show: true,
159 radius: 1,
160 label: {
161 show: true,
162 radius: 2/3,
163 formatter: function(label, series){
164 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
165 },
166 threshold: 0.1
167 }
168 }
169 },
170 legend: {
171 show: false
172 }
173 });
174
175 // GRAPH 7
176 $.plot($("#graph7"), data,
177 {
178 series: {
179 pie: {
180 show: true,
181 combine: {
182 color: '#999',
183 threshold: 0.1
184 }
185 }
186 },
187 legend: {
188 show: false
189 }
190 });
191
192 // GRAPH 8
193 $.plot($("#graph8"), data,
194 {
195 series: {
196 pie: {
197 show: true,
198 radius:300,
199 label: {
200 show: true,
201 formatter: function(label, series){
202 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
203 },
204 threshold: 0.1
205 }
206 }
207 },
208 legend: {
209 show: false
210 }
211 });
212
213 // GRAPH 9
214 $.plot($("#graph9"), data,
215 {
216 series: {
217 pie: {
218 show: true,
219 radius: 1,
220 tilt: 0.5,
221 label: {
222 show: true,
223 radius: 1,
224 formatter: function(label, series){
225 return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
226 },
227 background: { opacity: 0.8 }
228 },
229 combine: {
230 color: '#999',
231 threshold: 0.1
232 }
233 }
234 },
235 legend: {
236 show: false
237 }
238 });
239
240 // DONUT
241 $.plot($("#donut"), data,
242 {
243 series: {
244 pie: {
245 innerRadius: 0.5,
246 show: true
247 }
248 }
249 });
250
251 // INTERACTIVE
252 $.plot($("#interactive"), data,
253 {
254 series: {
255 pie: {
256 show: true
257 }
258 },
259 grid: {
260 hoverable: true,
261 clickable: true
262 }
263 });
264 $("#interactive").bind("plothover", pieHover);
265 $("#interactive").bind("plotclick", pieClick);
266
267 });
268
269 function pieHover(event, pos, obj)
270 {
271 if (!obj)
272 return;
273 percent = parseFloat(obj.series.percent).toFixed(2);
274 $("#hover").html('<span style="font-weight: bold; color: '+obj.series.color+'">'+obj.series.label+' ('+percent+'%)</span>');
275 }
276
277 function pieClick(event, pos, obj)
278 {
279 if (!obj)
280 return;
281 percent = parseFloat(obj.series.percent).toFixed(2);
282 alert(''+obj.series.label+': '+percent+'%');
283 }
284 </script>
285 <style type="text/css">
286 * {
287 font-family: sans-serif;
288 }
289
290 body
291 {
292 padding: 0 1em 1em 1em;
293 }
294
295 div.graph
296 {
297 width: 400px;
298 height: 300px;
299 float: left;
300 border: 1px dashed gainsboro;
301 }
302
303 label
304 {
305 display: block;
306 margin-left: 400px;
307 padding-left: 1em;
308 }
309
310 h2
311 {
312 padding-top: 1em;
313 margin-bottom: 0;
314 clear: both;
315 color: #ccc;
316 }
317
318 code
319 {
320 display: block;
321 background-color: #eee;
322 border: 1px dashed #999;
323 padding: 0.5em;
324 margin: 0.5em;
325 color: #666;
326 font-size: 10pt;
327 }
328
329 code b
330 {
331 color: black;
332 }
333
334 ul
335 {
336 font-size: 10pt;
337 }
338
339 ul li
340 {
341 margin-bottom: 0.5em;
342 }
343
344 ul.options li
345 {
346 list-style: none;
347 margin-bottom: 1em;
348 }
349
350 ul li i
351 {
352 color: #999;
353 }
354 </style>
355 </head>
356 <body>
357 <h1>Flot Pie Examples</h1>
358
359 <h2>Default with Legend</h2>
360 <div id="default" class="graph"></div>
361 <label for="default">
362 Default pie graph with no options set.
363 <code>
364 $.plot($("#default"), data,<br/>
365 {<br/>
366 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
367 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
368 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true<br/>
369 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
370 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
371 });<br/>
372 </code>
373 </label>
374
375 <h2>Default without Legend</h2>
376 <div id="graph1" class="graph"></div>
377 <label for="graph1">
378 Default pie graph when legend is disabled. Since the labels would normally be outside the container, the graph is resized to fit.
379 <code>
380 $.plot($("#graph1"), data, <br/>
381 {<br/>
382 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
383 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
384 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true<br/>
385 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
386 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
387 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>legend: {<br/>
388 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
389 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</b><br/>
390 });<br/>
391 </code>
392 </label>
393
394 <h2>Graph2</h2>
395 <div id="graph2" class="graph"></div>
396 <label for="graph2">
397 Added a semi-transparent background to the labels and a custom labelFormatter function.
398 <code>
399 $.plot($("#graph2"), data, <br/>
400 {<br/>
401 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
402 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
403 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
404 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
405 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>label: {<br/>
406 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
407 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
408 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
409 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
410 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
411 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;background: { opacity: 0.8 }<br/>
412 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</b><br/>
413 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
414 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
415 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
416 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
417 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
418 });<br/>
419 </code>
420 </label>
421
422 <h2>Graph3</h2>
423 <div id="graph3" class="graph"></div>
424 <label for="graph3">
425 Slightly more transparent label backgrounds and adjusted the radius values to place them within the pie.
426 <code>
427 $.plot($("#graph3"), data, <br/>
428 {<br/>
429 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
430 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
431 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
432 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
433 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
434 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
435 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>radius: 3/4,</b><br/>
436 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
437 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
438 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
439 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>background: { opacity: 0.5 }</b><br/>
440 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
441 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
442 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
443 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
444 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
445 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
446 });<br/>
447 </code>
448 </label>
449
450 <h2>Graph4</h2>
451 <div id="graph4" class="graph"></div>
452 <label for="graph4">
453 Semi-transparent, black-colored label background.
454 <code>
455 $.plot($("#graph4"), data, <br/>
456 {<br/>
457 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
458 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
459 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
460 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
461 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
462 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
463 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 3/4,<br/>
464 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
465 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
466 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
467 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;background: { <br/>
468 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opacity: 0.5,<br/>
469 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>color: '#000'</b><br/>
470 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
471 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
472 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
473 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
474 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
475 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
476 });<br/>
477 </code>
478 </label>
479
480 <h2>Graph5</h2>
481 <div id="graph5" class="graph"></div>
482 <label for="graph5">
483 Semi-transparent, black-colored label background placed at pie edge.
484 <code>
485 $.plot($("#graph5"), data, <br/>
486 {<br/>
487 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
488 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
489 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
490 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>radius: 3/4,</b><br/>
491 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
492 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
493 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 3/4,<br/>
494 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
495 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
496 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
497 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;background: { <br/>
498 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opacity: 0.5,<br/>
499 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;color: '#000'<br/>
500 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
501 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
502 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
503 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
504 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
505 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
506 });<br/>
507 </code>
508 </label>
509
510 <h2>Graph6</h2>
511 <div id="graph6" class="graph"></div>
512 <label for="graph6">
513 Labels can be hidden if the slice is less than a given percentage of the pie (10% in this case).
514 <br><span style="color: red">Note: you may need to refresh the page to see this effect.</span>
515 <code>
516 $.plot($("#graph6"), data, <br/>
517 {<br/>
518 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
519 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
520 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
521 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>radius: 1,</b><br/>
522 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
523 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
524 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>radius: 2/3,</b><br/>
525 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
526 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
527 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
528 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>threshold: 0.1</b><br/>
529 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
530 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
531 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
532 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
533 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
534 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
535 });<br/>
536 </code>
537 </label>
538
539 <h2>Graph7</h2>
540 <div id="graph7" class="graph"></div>
541 <label for="graph7">
542 All slices less than a given percentage of the pie can be combined into a single, larger slice (10% in this case).
543 <br><span style="color: red">Note: you may need to refresh the page to see this effect.</span>
544 <code>
545 $.plot($("#graph7"), data, <br/>
546 {<br/>
547 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
548 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
549 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
550 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>combine: {<br/>
551 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;color: '#999',<br/>
552 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threshold: 0.1<br/>
553 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</b><br/>
554 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
555 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
556 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
557 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
558 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
559 });<br/>
560 </code>
561 </label>
562
563 <h2>Graph8</h2>
564 <div id="graph8" class="graph"></div>
565 <label for="graph8">
566 The radius can also be set to a specific size (even larger than the container itself).
567 <code>
568 $.plot($("#graph8"), data, <br/>
569 {<br/>
570 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
571 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
572 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
573 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>radius:300,</b><br/>
574 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
575 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
576 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
577 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
578 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
579 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threshold: 0.1<br/>
580 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
581 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
582 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
583 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
584 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
585 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
586 });<br/>
587 </code>
588 </label>
589
590 <h2>Graph9</h2>
591 <div id="graph9" class="graph" style="height: 250px;"></div>
592 <label for="graph9">
593 The pie can be tilted at an angle.
594 <code>
595 $.plot($("#graph9"), data, <br/>
596 {<br/>
597 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
598 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
599 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
600 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
601 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>tilt: 0.5,</b><br/>
602 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label: {<br/>
603 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true,<br/>
604 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;radius: 1,<br/>
605 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter: function(label, series){<br/>
606 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return '&lt;div style="font-size:8pt;text-align:center;padding:2px;color:white;"&gt;'+label+'&lt;br/&gt;'+Math.round(series.percent)+'%&lt;/div&gt;';<br/>
607 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
608 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;background: { opacity: 0.8 }<br/>
609 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
610 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;combine: {<br/>
611 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;color: '#999',<br/>
612 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threshold: 0.1<br/>
613 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
614 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
615 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
616 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legend: {<br/>
617 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: false<br/>
618 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
619 });<br/>
620 </code>
621 </label>
622
623 <h2>Donut</h2>
624 <div id="donut" class="graph"></div>
625 <label for="donut">
626 A donut hole can be added.
627 <code>
628 $.plot($("#donut"), data,<br/>
629 {<br/>
630 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
631 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
632 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>innerRadius: 0.5,</b><br/>
633 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true<br/>
634 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
635 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
636 });<br/>
637 </code>
638 </label>
639
640 <h2>Interactive</h2>
641 <div id="interactive" class="graph"></div>
642 <label for="interactive">
643 The pie can be made interactive with hover and click events.
644 <code>
645 $.plot($("#interactive"), data,<br/>
646 {<br/>
647 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;series: {<br/>
648 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pie: { <br/>
649 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show: true<br/>
650 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
651 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br/>
652 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>grid: {<br/>
653 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hoverable: true,<br/>
654 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clickable: true<br/>
655 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</b><br/>
656 });<br/>
657 <b>$("#interactive").bind("plothover", pieHover);<br/>
658 $("#interactive").bind("plotclick", pieClick);</b><br/>
659 </code>
660 <div id="hover"></div>
661 </label>
662
663 <h2>Pie Options</h2>
664 <ul class="options">
665 <li style="border-bottom: 1px dotted #ccc;"><b>option:</b> <i>default value</i> - Description of option</li>
666 <li><b>show:</b> <i>false</i> - Enable the plugin and draw as a pie.</li>
667 <li><b>radius:</b> <i>'auto'</i> - Sets the radius of the pie. If value is between 0 and 1 (inclusive) then it will use that as a percentage of the available space (size of the container), otherwise it will use the value as a direct pixel length. If set to 'auto', it will be set to 1 if the legend is enabled and 3/4 if not.</li>
668 <li><b>innerRadius:</b> <i>0</i> - Sets the radius of the donut hole. If value is between 0 and 1 (inclusive) then it will use that as a percentage of the radius, otherwise it will use the value as a direct pixel length.</li>
669 <li><b>startAngle:</b> <i>3/2</i> - Factor of PI used for the starting angle (in radians) It can range between 0 and 2 (where 0 and 2 have the same result).</li>
670 <li><b>tilt:</b> <i>1</i> - Percentage of tilt ranging from 0 and 1, where 1 has no change (fully vertical) and 0 is completely flat (fully horizontal -- in which case nothing actually gets drawn).</li>
671 <li><b>offset:</b> <ul>
672 <li><b>top:</b> <i>0</i> - Pixel distance to move the pie up and down (relative to the center).</li>
673 <li><b>left:</b> <i>'auto'</i> - Pixel distance to move the pie left and right (relative to the center).</li>
674 </ul>
675 <li><b>stroke:</b> <ul>
676 <li><b>color:</b> <i>'#FFF'</i> - Color of the border of each slice. Hexadecimal color definitions are prefered (other formats may or may not work).</li>
677 <li><b>width:</b> <i>1</i> - Pixel width of the border of each slice.</li>
678 </ul>
679 <li><b>label:</b> <ul>
680 <li><b>show:</b> <i>'auto'</i> - Enable/Disable the labels. This can be set to true, false, or 'auto'. When set to 'auto', it will be set to false if the legend is enabled and true if not.</li>
681 <li><b>radius:</b> <i>1</i> - Sets the radius at which to place the labels. If value is between 0 and 1 (inclusive) then it will use that as a percentage of the available space (size of the container), otherwise it will use the value as a direct pixel length.</li>
682 <li><b>threshold:</b> <i>0</i> - Hides the labels of any pie slice that is smaller than the specified percentage (ranging from 0 to 1) i.e. a value of '0.03' will hide all slices 3% or less of the total.</li>
683 <li><b>formatter:</b> <i>[function]</i> - This function specifies how the positioned labels should be formatted, and is applied after the legend's labelFormatter function. The labels can also still be styled using the class "pieLabel" (i.e. ".pieLabel" or "#graph1 .pieLabel").</li>
684 <li><b>radius:</b> <i>1</i> - Sets the radius at which to place the labels. If value is between 0 and 1 (inclusive) then it will use that as a percentage of the available space (size of the container), otherwise it will use the value as a direct pixel length.</li>
685 <li><b>background:</b> <ul>
686 <li><b>color:</b> <i>null</i> - Backgound color of the positioned labels. If null, the plugin will automatically use the color of the slice.</li>
687 <li><b>opacity:</b> <i>0</i> - Opacity of the background for the positioned labels. Acceptable values range from 0 to 1, where 0 is completely transparent and 1 is completely opaque.</li>
688 </ul>
689 </ul>
690 <li><b>combine:</b> <ul>
691 <li><b>threshold:</b> <i>0</i> - Combines all slices that are smaller than the specified percentage (ranging from 0 to 1) i.e. a value of '0.03' will combine all slices 3% or less into one slice).</li>
692 <li><b>color:</b> <i>null</i> - Backgound color of the positioned labels. If null, the plugin will automatically use the color of the first slice to be combined.</li>
693 <li><b>label:</b> <i>'Other'</i> - Label text for the combined slice.</li>
694 </ul>
695 <li><b>highlight:</b> <ul>
696 <li><b>opacity:</b> <i>0.5</i> - Opacity of the highlight overlay on top of the current pie slice. Currently this just uses a white overlay, but support for changing the color of the overlay will also be added at a later date.
697 </ul>
698 </ul>
699
700 <h2>Changes/Features</h2>
701 <ul>
702 <li style="list-style: none;"><i>v1.0 - November 20th, 2009 - Brian Medendorp</i></li>
703 <li>The pie plug-in is now part of the Flot repository! This should make it a lot easier to deal with.</li>
704 <li>Added a new option (innerRadius) to add a "donut hole" to the center of the pie, based on comtributions from Anthony Aragues. I was a little reluctant to add this feature because it doesn't work very well with the shadow created for the tilted pie, but figured it was worthwhile for non-tilted pies. Also, excanvas apparently doesn't support compositing, so it will fall back to using the stroke color to fill in the center (but I recommend setting the stroke color to the background color anyway).</li>
705 <li>Changed the lineJoin for the border of the pie slices to use the 'round' option. This should make the center of the pie look better, particularly when there are numerous thin slices.</li>
706 <li>Included a bug fix submitted by btburnett3 to display a slightly smaller slice in the event that the slice is 100% and being rendered with Internet Explorer. I haven't experienced this bug myself, but it doesn't seem to hurt anything so I've included it.</li>
707 <li>The tilt value is now used when calculating the maximum radius of the pie in relation to the height of the container. This should prevent the pie from being smaller than it needed to in some cases, as well as reducing the amount of extra white space generated above and below the pie.</li>
708 <li><b>Hover and Click functionality are now availabe!</b><ul>
709 <li>Thanks to btburnett3 for the original hover functionality and Anthony Aragues for the modification that makes it compatable with excanvas, this was a huge help!</li>
710 <li>Added a new option (highlight opacity) to modify the highlight created when mousing over a slice. Currently this just uses a white overlay, but an option to change the hightlight color will be added when the appropriate functionality becomes available.
711 <li>I had a major setback that required me to practically rebuild the hover/click events from scratch one piece at a time (I discovered that it only worked with a single pie on a page at a time), but the end result ended up being virtually identical to the original, so I'm not quite sure what exactly made it work.</li>
712 <li><span style="color: red;">Warning:</span> There are some minor issues with using this functionality in conjuction with some of the other more advanced features (tilt and donut). When using a donut hole, the inner portion still triggers the events even though that portion of the pie is no longer visible. When tilted, the interactive portions still use the original, untilted version of the pie when determining mouse position (this is because the isPointInPath function apparently doesn't work with transformations), however hover and click both work this way, so the appropriate slice is still highlighted when clicking, and it isn't as noticable of a problem.</li>
713 </ul></li>
714 <li>Included a bug fix submitted by Xavi Ivars to fix array issues when other javascript libraries are included in addition to jQuery</li>
715 <br/>
716 <li style="list-style: none;"><i>v0.4 - July 1st, 2009 - Brian Medendorp</i></li>
717 <li>Each series will now be shown in the legend, even if it's value is zero. The series will not get a positioned label because it will overlap with the other labels present and often makes them unreadable.</li>
718 <li>Data can now be passed in using the standard Flot method using an array of datapoints, the pie plugin will simply use the first y-value that it finds for each series in this case. The plugin uses this datastructure internally, but you can still use the old method of passing in a single numerical value for each series (the plugin will convert it as necessary). This should make it easier to transition from other types of graphs (such as a stacked bar graph) to a pie.</li>
719 <li>The pie can now be tilted at an angle with a new "tilt" option. Acceptable values range from 0-1, where 1 has no change (fully vertical) and 0 is completely flat (fully horizontal -- in which case nothing actually gets drawn). If the plugin determines that it will fit within the canvas, a drop shadow will be drawn under the tilted pie (this also requires a tilt value of 0.8 or less).</li>
720 <br/>
721 <li style="list-style: none;"><i>v0.3.2 - June 25th, 2009 - Brian Medendorp</i></li>
722 <li>Fixed a bug that was causing the pie to be shifted too far left or right when the legend is showing in some cases.</li>
723 <br/>
724 <li style="list-style: none;"><i>v0.3.1 - June 24th, 2009 - Brian Medendorp</i></li>
725 <li>Fixed a bug that was causing nothing to be drawn and generating a javascript error if any of the data values were set to zero.</li>
726 <br/>
727 <li style="list-style: none;"><i>v0.3 - June 23rd, 2009 - Brian Medendorp</i></li>
728 <li>The legend now works without any modifications! Because of changes made to flot and the plugin system (thanks Ole Laursen!) I was able to simplify a number of things and am now able to use the legend without the direct access hack that was required in the previous version.</li>
729 <br/>
730 <li style="list-style: none;"><i>v0.2 - June 22nd, 2009 - Brian Medendorp</i></li>
731 <li>The legend now works but only if you make the necessary changes to jquery.flot.js. Because of this, I changed the default values for pie.radius and pie.label.show to new 'auto' settings that change the default behavior of the size and labels depending on whether the legend functionality is available or not.</li>
732 <br/>
733 <li style="list-style: none;"><i>v0.1 - June 18th, 2009 - Brian Medendorp</i></li>
734 <li>Rewrote the entire pie code into a flot plugin (since that is now an option), so it should be much easier to use and the code is cleaned up a bit. However, the (standard flot) legend is no longer available because the only way to prevent the grid lines from being displayed also prevents the legend from being displayed. Hopefully this can be fixed at a later date.</li>
735 <li>Restructured and combined some of the options. It should be much easier to deal with now.</li>
736 <li>Added the ability to change the starting point of the pie (still defaults to the top).</li>
737 <li>Modified the default options to show the labels to compensate for the lack of a legend.</li>
738 <li>Modified this page to use a random dataset. <span style="color: red">Note: you may need to refresh the page to see the effects of some of the examples.</span></li>
739 <br/>
740 <li style="list-style: none;"><i>May 21st, 2009 - Brian Medendorp</i></li>
741 <li>Merged original pie modifications by Sergey Nosenko into the latest SVN version <i>(as of May 15th, 2009)</i> so that it will work with ie8.</li>
742 <li>Pie graph will now be centered in the canvas unless moved because of the legend or manually via the options. Additionally it prevents the pie from being moved beyond the edge of the canvas.</li>
743 <li>Modified the code related to the labelFormatter option to apply flot's legend labelFormatter first. This is so that the labels will be consistent, but still provide extra formatting for the positioned labels (such as adding the percentage value).</li>
744 <li>Positioned labels now have their backgrounds applied as a seperate element (much like the legend background) so that the opacity value can be set independently from the label itself (foreground). Additionally, the background color defaults to that of the matching slice.</li>
745 <li>As long as the labelOffset and radiusLimit are not set to hard values, the pie will be shrunk if the labels will extend outside the edge of the canvas</li>
746 <li>Added new options "radiusLimitFactor" and "radiusLimit" which limits how large the (visual) radius of the pie is in relation to the full radius (as calculated from the canvas dimensions) or a hard-pixel value (respectively). This allows for pushing the labels "outside" the pie.</li>
747 <li>Added a new option "labelHidePercent" that does not show the positioned labels of slices smaller than the specified percentage. This is to help prevent a bunch of overlapping labels from small slices.</li>
748 <li>Added a new option "sliceCombinePercent" that combines all slices smaller than the specified percentage into one larger slice. This is to help make the pie more attractive when there are a number of tiny slices. The options "sliceCombineColor" and "sliceCombineLabel" have also been added to change the color and name of the new slice if desired.</li>
749 <li>Tested in Firefox (3.0.10, 3.5b4), Internet Explorer (6.0.2900, 7.0.5730, 8.0.6001), Chrome (1.0.154), Opera (9.64), and Safari (3.1.1, 4 beta 5528.16).
750 </ul>
751
752
753 </body>
754 </html>
755
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 </head>
10 <body>
11 <h1>Flot Examples</h1>
12
13 <div id="placeholder" style="width:600px;height:300px;"></div>
14
15 <p>You can update a chart periodically to get a real-time effect
16 by using a timer to insert the new data in the plot and redraw it.</p>
17
18 <p>Time between updates: <input id="updateInterval" type="text" value="" style="text-align: right; width:5em"> milliseconds</p>
19
20 <script type="text/javascript">
21 $(function () {
22 // we use an inline data source in the example, usually data would
23 // be fetched from a server
24 var data = [], totalPoints = 300;
25 function getRandomData() {
26 if (data.length > 0)
27 data = data.slice(1);
28
29 // do a random walk
30 while (data.length < totalPoints) {
31 var prev = data.length > 0 ? data[data.length - 1] : 50;
32 var y = prev + Math.random() * 10 - 5;
33 if (y < 0)
34 y = 0;
35 if (y > 100)
36 y = 100;
37 data.push(y);
38 }
39
40 // zip the generated y values with the x values
41 var res = [];
42 for (var i = 0; i < data.length; ++i)
43 res.push([i, data[i]])
44 return res;
45 }
46
47 // setup control widget
48 var updateInterval = 30;
49 $("#updateInterval").val(updateInterval).change(function () {
50 var v = $(this).val();
51 if (v && !isNaN(+v)) {
52 updateInterval = +v;
53 if (updateInterval < 1)
54 updateInterval = 1;
55 if (updateInterval > 2000)
56 updateInterval = 2000;
57 $(this).val("" + updateInterval);
58 }
59 });
60
61 // setup plot
62 var options = {
63 series: { shadowSize: 0 }, // drawing is faster without shadows
64 yaxis: { min: 0, max: 100 },
65 xaxis: { show: false }
66 };
67 var plot = $.plot($("#placeholder"), [ getRandomData() ], options);
68
69 function update() {
70 plot.setData([ getRandomData() ]);
71 // since the axes don't change, we don't need to call plot.setupGrid()
72 plot.draw();
73
74 setTimeout(update, updateInterval);
75 }
76
77 update();
78 });
79 </script>
80
81 </body>
82 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 <script language="javascript" type="text/javascript" src="../jquery.flot.resize.js"></script>
10 <style type="text/css">
11 html, body {
12 height: 100%; /* make the percentage height on placeholder work */
13 }
14 .message {
15 padding-left: 50px;
16 font-size: smaller;
17 }
18 </style>
19 </head>
20 <body>
21 <h1>Flot Examples</h1>
22
23 <div id="placeholder" style="width:80%;height:40%;"></div>
24
25 <p class="message"></p>
26
27 <p>Sometimes it makes more sense to just let the plot take up the
28 available space. In that case, we need to redraw the plot each
29 time the placeholder changes its size. If you include the resize
30 plugin, this is handled automatically.</p>
31
32 <p>Try resizing the window.</p>
33
34
35 <script type="text/javascript">
36 $(function () {
37 var d1 = [];
38 for (var i = 0; i < 14; i += 0.5)
39 d1.push([i, Math.sin(i)]);
40
41 var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
42 var d3 = [[0, 12], [7, 12], null, [7, 2.5], [12, 2.5]];
43
44 var placeholder = $("#placeholder");
45
46 var plot = $.plot(placeholder, [d1, d2, d3]);
47
48 // the plugin includes a jQuery plugin for adding resize events to
49 // any element, let's just add a callback so we can display the
50 // placeholder size
51 placeholder.resize(function () {
52 $(".message").text("Placeholder is now "
53 + $(this).width() + "x" + $(this).height()
54 + " pixels");
55 });
56 });
57 </script>
58
59 </body>
60 </html>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
3434 in the "plotselected" event triggered. Enable the checkbox
3535 below and select a region again.</p>
3636
37 <p><input id="zoom" type="checkbox">Zoom to selection.</input></p>
37 <p><label><input id="zoom" type="checkbox" />Zoom to selection.</label></p>
3838
39 <script id="source" language="javascript" type="text/javascript">
39 <script type="text/javascript">
4040 $(function () {
4141 var data = [
4242 {
104104 });
105105
106106 $("#setSelection").click(function () {
107 plot.setSelection({ x1: 1994, x2: 1995 });
107 plot.setSelection({ xaxis: { from: 1994, to: 1995 } });
108108 });
109109 });
110110 </script>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
1313 <div id="placeholder" style="width:600px;height:300px"></div>
1414
1515 <p>There are plenty of options you can set to control the precise
16 looks of your plot. You can control the axes, the legend, the
17 default graph type, the look of grid, etc.</p>
16 looks of your plot. You can control the ticks on the axes, the
17 legend, the graph type, etc. The idea is that Flot goes to great
18 lengths to provide sensible defaults so that you don't have to
19 customize much for a good result.</p>
1820
19 <p>The idea is that Flot goes to great lengths to provide <b>sensible
20 defaults</b> which you can then customize as needed for your
21 particular application. If you've found a use case where the
22 defaults can be improved, please don't hesitate to give your
23 feedback.</p>
24
25 <script id="source" language="javascript" type="text/javascript">
21 <script type="text/javascript">
2622 $(function () {
2723 var d1 = [];
2824 for (var i = 0; i < Math.PI * 2; i += 0.25)
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.stack.js"></script>
4949 $.plot($("#placeholder"), [ d1, d2, d3 ], {
5050 series: {
5151 stack: stack,
52 lines: { show: lines, steps: steps },
52 lines: { show: lines, fill: true, steps: steps },
5353 bars: { show: bars, barWidth: 0.6 }
5454 }
5555 });
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
7 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
8 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
9 <script language="javascript" type="text/javascript" src="../jquery.flot.symbol.js"></script>
10 </head>
11 <body>
12 <h1>Flot Examples</h1>
13
14 <div id="placeholder" style="width:600px;height:300px"></div>
15
16 <p>Various point types. Circles are built-in. For other
17 point types, you can define a little callback function to draw the
18 symbol; some common ones are available in the symbol plugin.</p>
19
20 <script type="text/javascript">
21 $(function () {
22 function generate(offset, amplitude) {
23 var res = [];
24 var start = 0, end = 10;
25 for (var i = 0; i <= 50; ++i) {
26 var x = start + i / 50 * (end - start);
27 res.push([x, amplitude * Math.sin(x + offset)]);
28 }
29 return res;
30 }
31
32 var data = [
33 { data: generate(2, 1.8), points: { symbol: "circle" } },
34 { data: generate(3, 1.5), points: { symbol: "square" } },
35 { data: generate(4, 0.9), points: { symbol: "diamond" } },
36 { data: generate(6, 1.4), points: { symbol: "triangle" } },
37 { data: generate(7, 1.1), points: { symbol: "cross" } }
38 ];
39
40 $.plot($("#placeholder"), data, {
41 series: { points: { show: true, radius: 3 } },
42 grid: { hoverable: true }
43 });
44 });
45 </script>
46
47 </body>
48 </html>
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.threshold.js"></script>
2424 <input type="button" value="Threshold at -2.5">
2525 </p>
2626
27 <script id="source" language="javascript" type="text/javascript">
27 <script type="text/javascript">
2828 $(function () {
2929 var d1 = [];
3030 for (var i = 0; i <= 60; i += 1)
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
4747 $.plot($("#placeholder"), [d], {
4848 xaxis: {
4949 mode: "time",
50 min: (new Date("1990/01/01")).getTime(),
51 max: (new Date("2000/01/01")).getTime()
50 min: (new Date(1990, 1, 1)).getTime(),
51 max: (new Date(2000, 1, 1)).getTime()
5252 }
5353 });
5454 });
5858 xaxis: {
5959 mode: "time",
6060 minTickSize: [1, "month"],
61 min: (new Date("1999/01/01")).getTime(),
62 max: (new Date("2000/01/01")).getTime()
61 min: (new Date(1999, 1, 1)).getTime(),
62 max: (new Date(2000, 1, 1)).getTime()
6363 }
6464 });
6565 });
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.crosshair.js"></script>
2222
2323 <p id="hoverdata"></p>
2424
25 <script id="source" language="javascript" type="text/javascript">
25 <script type="text/javascript">
2626 var plot;
2727 $(function () {
2828 var sin = [], cos = [];
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 </head>
2121
2222 <p id="choices">Show:</p>
2323
24 <script id="source" language="javascript" type="text/javascript">
24 <script type="text/javascript">
2525 $(function () {
2626 var datasets = {
2727 "usa": {
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
4949 }
5050
5151 var options = {
52 xaxis: { mode: "time" },
52 xaxis: { mode: "time", tickLength: 5 },
5353 selection: { mode: "x" },
5454 grid: { markings: weekendAreas }
5555 };
22 <head>
33 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
44 <title>Flot Examples</title>
5 <link href="layout.css" rel="stylesheet" type="text/css"></link>
6 <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
5 <link href="layout.css" rel="stylesheet" type="text/css">
6 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
77 <script language="javascript" type="text/javascript" src="../jquery.js"></script>
88 <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
99 <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
1515 <div id="placeholder" style="width:500px;height:300px"></div>
1616 </div>
1717
18 <div id="miniature" style="float:left;margin-left:20px;margin-top:50px">
18 <div id="miniature" style="float:left;margin-left:20px">
1919 <div id="overview" style="width:166px;height:100px"></div>
2020
2121 <p id="overviewLegend" style="margin-left:10px"></p>
2222 </div>
2323
24 <p style="clear:left"> The selection support makes
25 pretty advanced zooming schemes possible. With a few lines of code,
26 the small overview plot to the right has been connected to the large
27 plot. Try selecting a rectangle on either of them.</p>
24 <p style="clear:left">The selection support makes it easy to
25 construct flexible zooming schemes. With a few lines of code, the
26 small overview plot to the right has been connected to the large
27 plot. Try selecting a rectangle on either of them.</p>
2828
2929 <script id="source">
3030 $(function () {
00 /* Plugin for jQuery for working with colors.
11 *
2 * Version 1.0.
2 * Version 1.1.
33 *
44 * Inspiration from jQuery color animation plugin by John Resig.
55 *
1212 * console.log(c.r, c.g, c.b, c.a);
1313 * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
1414 *
15 * Note that .scale() and .add() work in-place instead of returning
16 * new objects.
15 * Note that .scale() and .add() return the same modified object
16 * instead of making a new one.
17 *
18 * V. 1.1: Fix error handling so e.g. parsing an empty string does
19 * produce a color rather than just crashing.
1720 */
1821
19 (function() {
20 jQuery.color = {};
22 (function($) {
23 $.color = {};
2124
2225 // construct color object with some convenient chainable helpers
23 jQuery.color.make = function (r, g, b, a) {
26 $.color.make = function (r, g, b, a) {
2427 var o = {};
2528 o.r = r || 0;
2629 o.g = g || 0;
6063 };
6164
6265 o.clone = function () {
63 return jQuery.color.make(o.r, o.b, o.g, o.a);
66 return $.color.make(o.r, o.b, o.g, o.a);
6467 };
6568
6669 return o.normalize();
6871
6972 // extract CSS color property from element, going up in the DOM
7073 // if it's "transparent"
71 jQuery.color.extract = function (elem, css) {
74 $.color.extract = function (elem, css) {
7275 var c;
7376 do {
7477 c = elem.css(css).toLowerCase();
7780 if (c != '' && c != 'transparent')
7881 break;
7982 elem = elem.parent();
80 } while (!jQuery.nodeName(elem.get(0), "body"));
83 } while (!$.nodeName(elem.get(0), "body"));
8184
8285 // catch Safari's way of signalling transparent
8386 if (c == "rgba(0, 0, 0, 0)")
8487 c = "transparent";
8588
86 return jQuery.color.parse(c);
89 return $.color.parse(c);
8790 }
8891
8992 // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"),
90 // returns color object
91 jQuery.color.parse = function (str) {
92 var res, m = jQuery.color.make;
93 // returns color object, if parsing failed, you get black (0, 0,
94 // 0) out
95 $.color.parse = function (str) {
96 var res, m = $.color.make;
9397
9498 // Look for rgb(num,num,num)
9599 if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))
116120 return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16));
117121
118122 // Otherwise, we're most likely dealing with a named color
119 var name = jQuery.trim(str).toLowerCase();
123 var name = $.trim(str).toLowerCase();
120124 if (name == "transparent")
121125 return m(255, 255, 255, 0);
122126 else {
123 res = lookupColors[name];
127 // default to black
128 res = lookupColors[name] || [0, 0, 0];
124129 return m(res[0], res[1], res[2]);
125130 }
126131 }
169174 silver:[192,192,192],
170175 white:[255,255,255],
171176 yellow:[255,255,0]
172 };
173 })();
177 };
178 })(jQuery);
00 /*
1 Flot plugin for showing a crosshair, thin lines, when the mouse hovers
1 Flot plugin for showing crosshairs, thin lines, when the mouse hovers
22 over the plot.
33
44 crosshair: {
1818 - setCrosshair(pos)
1919
2020 Set the position of the crosshair. Note that this is cleared if
21 the user moves the mouse. "pos" should be on the form { x: xpos,
22 y: ypos } (or x2 and y2 if you're using the secondary axes), which
23 is coincidentally the same format as what you get from a "plothover"
24 event. If "pos" is null, the crosshair is cleared.
21 the user moves the mouse. "pos" is in coordinates of the plot and
22 should be on the form { x: xpos, y: ypos } (you can use x2/x3/...
23 if you're using multiple axes), which is coincidentally the same
24 format as what you get from a "plothover" event. If "pos" is null,
25 the crosshair is cleared.
2526
2627 - clearCrosshair()
2728
6869 if (!pos)
6970 crosshair.x = -1;
7071 else {
71 var axes = plot.getAxes();
72
73 crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
74 crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
72 var o = plot.p2c(pos);
73 crosshair.x = Math.max(0, Math.min(o.left, plot.width()));
74 crosshair.y = Math.max(0, Math.min(o.top, plot.height()));
7575 }
7676
7777 plot.triggerRedrawOverlay();
8989 crosshair.locked = false;
9090 }
9191
92 function onMouseOut(e) {
93 if (crosshair.locked)
94 return;
95
96 if (crosshair.x != -1) {
97 crosshair.x = -1;
98 plot.triggerRedrawOverlay();
99 }
100 }
101
102 function onMouseMove(e) {
103 if (crosshair.locked)
104 return;
105
106 if (plot.getSelection && plot.getSelection()) {
107 crosshair.x = -1; // hide the crosshair while selecting
108 return;
109 }
110
111 var offset = plot.offset();
112 crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
113 crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
114 plot.triggerRedrawOverlay();
115 }
116
92117 plot.hooks.bindEvents.push(function (plot, eventHolder) {
93118 if (!plot.getOptions().crosshair.mode)
94119 return;
95120
96 eventHolder.mouseout(function () {
97 if (crosshair.x != -1) {
98 crosshair.x = -1;
99 plot.triggerRedrawOverlay();
100 }
101 });
102
103 eventHolder.mousemove(function (e) {
104 if (plot.getSelection && plot.getSelection()) {
105 crosshair.x = -1; // hide the crosshair while selecting
106 return;
107 }
108
109 if (crosshair.locked)
110 return;
111
112 var offset = plot.offset();
113 crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
114 crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
115 plot.triggerRedrawOverlay();
116 });
121 eventHolder.mouseout(onMouseOut);
122 eventHolder.mousemove(onMouseMove);
117123 });
118124
119125 plot.hooks.drawOverlay.push(function (plot, ctx) {
144150 }
145151 ctx.restore();
146152 });
153
154 plot.hooks.shutdown.push(function (plot, eventHolder) {
155 eventHolder.unbind("mouseout", onMouseOut);
156 eventHolder.unbind("mousemove", onMouseMove);
157 });
147158 }
148159
149160 $.plot.plugins.push({
0 /*
1 Flot plugin for computing bottoms for filled line and bar charts.
2
3 The case: you've got two series that you want to fill the area
4 between. In Flot terms, you need to use one as the fill bottom of the
5 other. You can specify the bottom of each data point as the third
6 coordinate manually, or you can use this plugin to compute it for you.
7
8 In order to name the other series, you need to give it an id, like this
9
10 var dataset = [
11 { data: [ ... ], id: "foo" } , // use default bottom
12 { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
13 ];
14
15 $.plot($("#placeholder"), dataset, { line: { show: true, fill: true }});
16
17 As a convenience, if the id given is a number that doesn't appear as
18 an id in the series, it is interpreted as the index in the array
19 instead (so fillBetween: 0 can also mean the first series).
20
21 Internally, the plugin modifies the datapoints in each series. For
22 line series, extra data points might be inserted through
23 interpolation. Note that at points where the bottom line is not
24 defined (due to a null point or start/end of line), the current line
25 will show a gap too. The algorithm comes from the jquery.flot.stack.js
26 plugin, possibly some code could be shared.
27 */
28
29 (function ($) {
30 var options = {
31 series: { fillBetween: null } // or number
32 };
33
34 function init(plot) {
35 function findBottomSeries(s, allseries) {
36 var i;
37 for (i = 0; i < allseries.length; ++i) {
38 if (allseries[i].id == s.fillBetween)
39 return allseries[i];
40 }
41
42 if (typeof s.fillBetween == "number") {
43 i = s.fillBetween;
44
45 if (i < 0 || i >= allseries.length)
46 return null;
47
48 return allseries[i];
49 }
50
51 return null;
52 }
53
54 function computeFillBottoms(plot, s, datapoints) {
55 if (s.fillBetween == null)
56 return;
57
58 var other = findBottomSeries(s, plot.getData());
59 if (!other)
60 return;
61
62 var ps = datapoints.pointsize,
63 points = datapoints.points,
64 otherps = other.datapoints.pointsize,
65 otherpoints = other.datapoints.points,
66 newpoints = [],
67 px, py, intery, qx, qy, bottom,
68 withlines = s.lines.show,
69 withbottom = ps > 2 && datapoints.format[2].y,
70 withsteps = withlines && s.lines.steps,
71 fromgap = true,
72 i = 0, j = 0, l;
73
74 while (true) {
75 if (i >= points.length)
76 break;
77
78 l = newpoints.length;
79
80 if (points[i] == null) {
81 // copy gaps
82 for (m = 0; m < ps; ++m)
83 newpoints.push(points[i + m]);
84 i += ps;
85 }
86 else if (j >= otherpoints.length) {
87 // for lines, we can't use the rest of the points
88 if (!withlines) {
89 for (m = 0; m < ps; ++m)
90 newpoints.push(points[i + m]);
91 }
92 i += ps;
93 }
94 else if (otherpoints[j] == null) {
95 // oops, got a gap
96 for (m = 0; m < ps; ++m)
97 newpoints.push(null);
98 fromgap = true;
99 j += otherps;
100 }
101 else {
102 // cases where we actually got two points
103 px = points[i];
104 py = points[i + 1];
105 qx = otherpoints[j];
106 qy = otherpoints[j + 1];
107 bottom = 0;
108
109 if (px == qx) {
110 for (m = 0; m < ps; ++m)
111 newpoints.push(points[i + m]);
112
113 //newpoints[l + 1] += qy;
114 bottom = qy;
115
116 i += ps;
117 j += otherps;
118 }
119 else if (px > qx) {
120 // we got past point below, might need to
121 // insert interpolated extra point
122 if (withlines && i > 0 && points[i - ps] != null) {
123 intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
124 newpoints.push(qx);
125 newpoints.push(intery)
126 for (m = 2; m < ps; ++m)
127 newpoints.push(points[i + m]);
128 bottom = qy;
129 }
130
131 j += otherps;
132 }
133 else { // px < qx
134 if (fromgap && withlines) {
135 // if we come from a gap, we just skip this point
136 i += ps;
137 continue;
138 }
139
140 for (m = 0; m < ps; ++m)
141 newpoints.push(points[i + m]);
142
143 // we might be able to interpolate a point below,
144 // this can give us a better y
145 if (withlines && j > 0 && otherpoints[j - otherps] != null)
146 bottom = qy + (otherpoints[j - otherps + 1] - qy) * (px - qx) / (otherpoints[j - otherps] - qx);
147
148 //newpoints[l + 1] += bottom;
149
150 i += ps;
151 }
152
153 fromgap = false;
154
155 if (l != newpoints.length && withbottom)
156 newpoints[l + 2] = bottom;
157 }
158
159 // maintain the line steps invariant
160 if (withsteps && l != newpoints.length && l > 0
161 && newpoints[l] != null
162 && newpoints[l] != newpoints[l - ps]
163 && newpoints[l + 1] != newpoints[l - ps + 1]) {
164 for (m = 0; m < ps; ++m)
165 newpoints[l + ps + m] = newpoints[l + m];
166 newpoints[l + 1] = newpoints[l - ps + 1];
167 }
168 }
169
170 datapoints.points = newpoints;
171 }
172
173 plot.hooks.processDatapoints.push(computeFillBottoms);
174 }
175
176 $.plot.plugins.push({
177 init: init,
178 options: options,
179 name: 'fillbetween',
180 version: '1.0'
181 });
182 })(jQuery);
111111 });
112112 }
113113
114 function draw(plot, ctx) {
114 function drawSeries(plot, ctx, series) {
115115 var plotOffset = plot.getPlotOffset();
116116
117 $.each(plot.getData(), function (i, series) {
118 var points = series.datapoints.points,
119 ps = series.datapoints.pointsize;
120
121 for (var i = 0; i < points.length; i += ps) {
122 var img = points[i],
123 x1 = points[i + 1], y1 = points[i + 2],
124 x2 = points[i + 3], y2 = points[i + 4],
125 xaxis = series.xaxis, yaxis = series.yaxis,
126 tmp;
127
128 // actually we should check img.complete, but it
129 // appears to be a somewhat unreliable indicator in
130 // IE6 (false even after load event)
131 if (!img || img.width <= 0 || img.height <= 0)
132 continue;
133
134 if (x1 > x2) {
135 tmp = x2;
136 x2 = x1;
137 x1 = tmp;
138 }
139 if (y1 > y2) {
140 tmp = y2;
141 y2 = y1;
142 y1 = tmp;
143 }
144
145 // if the anchor is at the center of the pixel, expand the
146 // image by 1/2 pixel in each direction
147 if (series.images.anchor == "center") {
148 tmp = 0.5 * (x2-x1) / (img.width - 1);
149 x1 -= tmp;
150 x2 += tmp;
151 tmp = 0.5 * (y2-y1) / (img.height - 1);
152 y1 -= tmp;
153 y2 += tmp;
154 }
155
156 // clip
157 if (x1 == x2 || y1 == y2 ||
158 x1 >= xaxis.max || x2 <= xaxis.min ||
159 y1 >= yaxis.max || y2 <= yaxis.min)
160 continue;
161
162 var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
163 if (x1 < xaxis.min) {
164 sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
165 x1 = xaxis.min;
166 }
167
168 if (x2 > xaxis.max) {
169 sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
170 x2 = xaxis.max;
171 }
172
173 if (y1 < yaxis.min) {
174 sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
175 y1 = yaxis.min;
176 }
177
178 if (y2 > yaxis.max) {
179 sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
180 y2 = yaxis.max;
181 }
182
183 x1 = xaxis.p2c(x1);
184 x2 = xaxis.p2c(x2);
185 y1 = yaxis.p2c(y1);
186 y2 = yaxis.p2c(y2);
187
188 // the transformation may have swapped us
189 if (x1 > x2) {
190 tmp = x2;
191 x2 = x1;
192 x1 = tmp;
193 }
194 if (y1 > y2) {
195 tmp = y2;
196 y2 = y1;
197 y1 = tmp;
198 }
199
200 tmp = ctx.globalAlpha;
201 ctx.globalAlpha *= series.images.alpha;
202 ctx.drawImage(img,
203 sx1, sy1, sx2 - sx1, sy2 - sy1,
204 x1 + plotOffset.left, y1 + plotOffset.top,
205 x2 - x1, y2 - y1);
206 ctx.globalAlpha = tmp;
207 }
208 });
117 if (!series.images || !series.images.show)
118 return;
119
120 var points = series.datapoints.points,
121 ps = series.datapoints.pointsize;
122
123 for (var i = 0; i < points.length; i += ps) {
124 var img = points[i],
125 x1 = points[i + 1], y1 = points[i + 2],
126 x2 = points[i + 3], y2 = points[i + 4],
127 xaxis = series.xaxis, yaxis = series.yaxis,
128 tmp;
129
130 // actually we should check img.complete, but it
131 // appears to be a somewhat unreliable indicator in
132 // IE6 (false even after load event)
133 if (!img || img.width <= 0 || img.height <= 0)
134 continue;
135
136 if (x1 > x2) {
137 tmp = x2;
138 x2 = x1;
139 x1 = tmp;
140 }
141 if (y1 > y2) {
142 tmp = y2;
143 y2 = y1;
144 y1 = tmp;
145 }
146
147 // if the anchor is at the center of the pixel, expand the
148 // image by 1/2 pixel in each direction
149 if (series.images.anchor == "center") {
150 tmp = 0.5 * (x2-x1) / (img.width - 1);
151 x1 -= tmp;
152 x2 += tmp;
153 tmp = 0.5 * (y2-y1) / (img.height - 1);
154 y1 -= tmp;
155 y2 += tmp;
156 }
157
158 // clip
159 if (x1 == x2 || y1 == y2 ||
160 x1 >= xaxis.max || x2 <= xaxis.min ||
161 y1 >= yaxis.max || y2 <= yaxis.min)
162 continue;
163
164 var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
165 if (x1 < xaxis.min) {
166 sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
167 x1 = xaxis.min;
168 }
169
170 if (x2 > xaxis.max) {
171 sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
172 x2 = xaxis.max;
173 }
174
175 if (y1 < yaxis.min) {
176 sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
177 y1 = yaxis.min;
178 }
179
180 if (y2 > yaxis.max) {
181 sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
182 y2 = yaxis.max;
183 }
184
185 x1 = xaxis.p2c(x1);
186 x2 = xaxis.p2c(x2);
187 y1 = yaxis.p2c(y1);
188 y2 = yaxis.p2c(y2);
189
190 // the transformation may have swapped us
191 if (x1 > x2) {
192 tmp = x2;
193 x2 = x1;
194 x1 = tmp;
195 }
196 if (y1 > y2) {
197 tmp = y2;
198 y2 = y1;
199 y1 = tmp;
200 }
201
202 tmp = ctx.globalAlpha;
203 ctx.globalAlpha *= series.images.alpha;
204 ctx.drawImage(img,
205 sx1, sy1, sx2 - sx1, sy2 - sy1,
206 x1 + plotOffset.left, y1 + plotOffset.top,
207 x2 - x1, y2 - y1);
208 ctx.globalAlpha = tmp;
209 }
209210 }
210211
211212 function processRawData(plot, series, data, datapoints) {
224225
225226 function init(plot) {
226227 plot.hooks.processRawData.push(processRawData);
227 plot.hooks.draw.push(draw);
228 plot.hooks.drawSeries.push(drawSeries);
228229 }
229230
230231 $.plot.plugins.push({
0 /* Javascript plotting library for jQuery, v. 0.6.
0 /*! Javascript plotting library for jQuery, v. 0.7.
11 *
22 * Released under the MIT license by IOLA, December 2007.
33 *
88
99 /* Plugin for jQuery for working with colors.
1010 *
11 * Version 1.0.
11 * Version 1.1.
1212 *
1313 * Inspiration from jQuery color animation plugin by John Resig.
1414 *
2121 * console.log(c.r, c.g, c.b, c.a);
2222 * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
2323 *
24 * Note that .scale() and .add() work in-place instead of returning
25 * new objects.
24 * Note that .scale() and .add() return the same modified object
25 * instead of making a new one.
26 *
27 * V. 1.1: Fix error handling so e.g. parsing an empty string does
28 * produce a color rather than just crashing.
2629 */
27 (function(){jQuery.color={};jQuery.color.make=function(E,D,B,C){var F={};F.r=E||0;F.g=D||0;F.b=B||0;F.a=C!=null?C:1;F.add=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]+=H}return F.normalize()};F.scale=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]*=H}return F.normalize()};F.toString=function(){if(F.a>=1){return"rgb("+[F.r,F.g,F.b].join(",")+")"}else{return"rgba("+[F.r,F.g,F.b,F.a].join(",")+")"}};F.normalize=function(){function G(I,J,H){return J<I?I:(J>H?H:J)}F.r=G(0,parseInt(F.r),255);F.g=G(0,parseInt(F.g),255);F.b=G(0,parseInt(F.b),255);F.a=G(0,F.a,1);return F};F.clone=function(){return jQuery.color.make(F.r,F.b,F.g,F.a)};return F.normalize()};jQuery.color.extract=function(C,B){var D;do{D=C.css(B).toLowerCase();if(D!=""&&D!="transparent"){break}C=C.parent()}while(!jQuery.nodeName(C.get(0),"body"));if(D=="rgba(0, 0, 0, 0)"){D="transparent"}return jQuery.color.parse(D)};jQuery.color.parse=function(E){var D,B=jQuery.color.make;if(D=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10))}if(D=/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(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10),parseFloat(D[4]))}if(D=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55)}if(D=/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(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55,parseFloat(D[4]))}if(D=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(E)){return B(parseInt(D[1],16),parseInt(D[2],16),parseInt(D[3],16))}if(D=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(E)){return B(parseInt(D[1]+D[1],16),parseInt(D[2]+D[2],16),parseInt(D[3]+D[3],16))}var C=jQuery.trim(E).toLowerCase();if(C=="transparent"){return B(255,255,255,0)}else{D=A[C];return B(D[0],D[1],D[2])}};var A={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]}})();
30 (function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return"rgb("+[G.r,G.g,G.b].join(",")+")"}else{return"rgba("+[G.r,G.g,G.b,G.a].join(",")+")"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=""&&E!="transparent"){break}D=D.parent()}while(!B.nodeName(D.get(0),"body"));if(E=="rgba(0, 0, 0, 0)"){E="transparent"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/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(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/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(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D=="transparent"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={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);
2831
2932 // the actual Flot code
3033 (function($) {
5053 backgroundOpacity: 0.85 // set to 0 to avoid background
5154 },
5255 xaxis: {
56 show: null, // null = auto-detect, true = always, false = never
57 position: "bottom", // or "top"
5358 mode: null, // null or "time"
59 color: null, // base color, labels, ticks
60 tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
5461 transform: null, // null or f: number -> number to transform axis
5562 inverseTransform: null, // if transform is set, this should be the inverse function
5663 min: null, // min. value to show, null means set automatically
6067 tickFormatter: null, // fn: number -> string
6168 labelWidth: null, // size of tick labels in pixels
6269 labelHeight: null,
70 reserveSpace: null, // whether to reserve space even if axis isn't shown
71 tickLength: null, // size in pixels of ticks, or "full" for whole line
72 alignTicksWithAxis: null, // axis number or null for no sync
6373
6474 // mode specific options
6575 tickDecimals: null, // no. of decimals, null means auto
7080 twelveHourClock: false // 12 or 24 time in time mode
7181 },
7282 yaxis: {
73 autoscaleMargin: 0.02
83 autoscaleMargin: 0.02,
84 position: "left" // or "right"
7485 },
75 x2axis: {
76 autoscaleMargin: null
77 },
78 y2axis: {
79 autoscaleMargin: 0.02
80 },
86 xaxes: [],
87 yaxes: [],
8188 series: {
8289 points: {
8390 show: false,
8491 radius: 3,
8592 lineWidth: 2, // in pixels
8693 fill: true,
87 fillColor: "#ffffff"
94 fillColor: "#ffffff",
95 symbol: "circle" // or callback
8896 },
8997 lines: {
9098 // we don't put in show: false so we can see
101109 fill: true,
102110 fillColor: null,
103111 align: "left", // or "center"
104 horizontal: false // when horizontal, left is now top
112 horizontal: false
105113 },
106114 shadowSize: 3
107115 },
110118 aboveData: false,
111119 color: "#545454", // primary color used for outline and labels
112120 backgroundColor: null, // null for transparent, else color
113 tickColor: "rgba(0,0,0,0.15)", // color used for the ticks
121 borderColor: null, // set if different from the grid color
122 tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
114123 labelMargin: 5, // in pixels
124 axisMargin: 8, // in pixels
115125 borderWidth: 2, // in pixels
116 borderColor: null, // set if different from the grid color
126 minBorderMargin: null, // in pixels, null means taken from points radius
117127 markings: null, // array of ranges or fn: axes -> array of ranges
118128 markingsColor: "#f4f4f4",
119129 markingsLineWidth: 2,
129139 overlay = null, // canvas for interactive stuff on top of plot
130140 eventHolder = null, // jQuery object that events should be bound to
131141 ctx = null, octx = null,
132 axes = { xaxis: {}, yaxis: {}, x2axis: {}, y2axis: {} },
142 xaxes = [], yaxes = [],
133143 plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
134144 canvasWidth = 0, canvasHeight = 0,
135145 plotWidth = 0, plotHeight = 0,
137147 processOptions: [],
138148 processRawData: [],
139149 processDatapoints: [],
150 drawSeries: [],
140151 draw: [],
141152 bindEvents: [],
142 drawOverlay: []
153 drawOverlay: [],
154 shutdown: []
143155 },
144156 plot = this;
145157
158170 o.top += plotOffset.top;
159171 return o;
160172 };
161 plot.getData = function() { return series; };
162 plot.getAxes = function() { return axes; };
163 plot.getOptions = function() { return options; };
173 plot.getData = function () { return series; };
174 plot.getAxes = function () {
175 var res = {}, i;
176 $.each(xaxes.concat(yaxes), function (_, axis) {
177 if (axis)
178 res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
179 });
180 return res;
181 };
182 plot.getXAxes = function () { return xaxes; };
183 plot.getYAxes = function () { return yaxes; };
184 plot.c2p = canvasToAxisCoords;
185 plot.p2c = axisToCanvasCoords;
186 plot.getOptions = function () { return options; };
164187 plot.highlight = highlight;
165188 plot.unhighlight = unhighlight;
166189 plot.triggerRedrawOverlay = triggerRedrawOverlay;
167190 plot.pointOffset = function(point) {
168 return { left: parseInt(axisSpecToRealAxis(point, "xaxis").p2c(+point.x) + plotOffset.left),
169 top: parseInt(axisSpecToRealAxis(point, "yaxis").p2c(+point.y) + plotOffset.top) };
191 return {
192 left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left),
193 top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top)
194 };
170195 };
171
196 plot.shutdown = shutdown;
197 plot.resize = function () {
198 getCanvasDimensions();
199 resizeCanvas(canvas);
200 resizeCanvas(overlay);
201 };
172202
173203 // public attributes
174204 plot.hooks = hooks;
176206 // initialize
177207 initPlugins(plot);
178208 parseOptions(options_);
179 constructCanvas();
209 setupCanvases();
180210 setData(data_);
181211 setupGrid();
182212 draw();
199229 }
200230
201231 function parseOptions(opts) {
232 var i;
233
202234 $.extend(true, options, opts);
235
236 if (options.xaxis.color == null)
237 options.xaxis.color = options.grid.color;
238 if (options.yaxis.color == null)
239 options.yaxis.color = options.grid.color;
240
241 if (options.xaxis.tickColor == null) // backwards-compatibility
242 options.xaxis.tickColor = options.grid.tickColor;
243 if (options.yaxis.tickColor == null) // backwards-compatibility
244 options.yaxis.tickColor = options.grid.tickColor;
245
203246 if (options.grid.borderColor == null)
204247 options.grid.borderColor = options.grid.color;
248 if (options.grid.tickColor == null)
249 options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
250
251 // fill in defaults in axes, copy at least always the
252 // first as the rest of the code assumes it'll be there
253 for (i = 0; i < Math.max(1, options.xaxes.length); ++i)
254 options.xaxes[i] = $.extend(true, {}, options.xaxis, options.xaxes[i]);
255 for (i = 0; i < Math.max(1, options.yaxes.length); ++i)
256 options.yaxes[i] = $.extend(true, {}, options.yaxis, options.yaxes[i]);
257
205258 // backwards compatibility, to be removed in future
206259 if (options.xaxis.noTicks && options.xaxis.ticks == null)
207260 options.xaxis.ticks = options.xaxis.noTicks;
208261 if (options.yaxis.noTicks && options.yaxis.ticks == null)
209262 options.yaxis.ticks = options.yaxis.noTicks;
263 if (options.x2axis) {
264 options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
265 options.xaxes[1].position = "top";
266 }
267 if (options.y2axis) {
268 options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
269 options.yaxes[1].position = "right";
270 }
210271 if (options.grid.coloredAreas)
211272 options.grid.markings = options.grid.coloredAreas;
212273 if (options.grid.coloredAreasColor)
217278 $.extend(true, options.series.points, options.points);
218279 if (options.bars)
219280 $.extend(true, options.series.bars, options.bars);
220 if (options.shadowSize)
281 if (options.shadowSize != null)
221282 options.series.shadowSize = options.shadowSize;
222283
284 // save options on axes for future reference
285 for (i = 0; i < options.xaxes.length; ++i)
286 getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
287 for (i = 0; i < options.yaxes.length; ++i)
288 getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
289
290 // add hooks from options
223291 for (var n in hooks)
224292 if (options.hooks[n] && options.hooks[n].length)
225293 hooks[n] = hooks[n].concat(options.hooks[n]);
238306 for (var i = 0; i < d.length; ++i) {
239307 var s = $.extend(true, {}, options.series);
240308
241 if (d[i].data) {
309 if (d[i].data != null) {
242310 s.data = d[i].data; // move the data instead of deep-copy
243311 delete d[i].data;
244312
254322 return res;
255323 }
256324
257 function axisSpecToRealAxis(obj, attr) {
258 var a = obj[attr];
259 if (!a || a == 1)
260 return axes[attr];
261 if (typeof a == "number")
262 return axes[attr.charAt(0) + a + attr.slice(1)];
263 return a; // assume it's OK
325 function axisNumber(obj, coord) {
326 var a = obj[coord + "axis"];
327 if (typeof a == "object") // if we got a real axis, extract number
328 a = a.n;
329 if (typeof a != "number")
330 a = 1; // default to first axis
331 return a;
332 }
333
334 function allAxes() {
335 // return flat array without annoying null entries
336 return $.grep(xaxes.concat(yaxes), function (a) { return a; });
264337 }
265338
339 function canvasToAxisCoords(pos) {
340 // return an object with x/y corresponding to all used axes
341 var res = {}, i, axis;
342 for (i = 0; i < xaxes.length; ++i) {
343 axis = xaxes[i];
344 if (axis && axis.used)
345 res["x" + axis.n] = axis.c2p(pos.left);
346 }
347
348 for (i = 0; i < yaxes.length; ++i) {
349 axis = yaxes[i];
350 if (axis && axis.used)
351 res["y" + axis.n] = axis.c2p(pos.top);
352 }
353
354 if (res.x1 !== undefined)
355 res.x = res.x1;
356 if (res.y1 !== undefined)
357 res.y = res.y1;
358
359 return res;
360 }
361
362 function axisToCanvasCoords(pos) {
363 // get canvas coords from the first pair of x/y found in pos
364 var res = {}, i, axis, key;
365
366 for (i = 0; i < xaxes.length; ++i) {
367 axis = xaxes[i];
368 if (axis && axis.used) {
369 key = "x" + axis.n;
370 if (pos[key] == null && axis.n == 1)
371 key = "x";
372
373 if (pos[key] != null) {
374 res.left = axis.p2c(pos[key]);
375 break;
376 }
377 }
378 }
379
380 for (i = 0; i < yaxes.length; ++i) {
381 axis = yaxes[i];
382 if (axis && axis.used) {
383 key = "y" + axis.n;
384 if (pos[key] == null && axis.n == 1)
385 key = "y";
386
387 if (pos[key] != null) {
388 res.top = axis.p2c(pos[key]);
389 break;
390 }
391 }
392 }
393
394 return res;
395 }
396
397 function getOrCreateAxis(axes, number) {
398 if (!axes[number - 1])
399 axes[number - 1] = {
400 n: number, // save the number for future reference
401 direction: axes == xaxes ? "x" : "y",
402 options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
403 };
404
405 return axes[number - 1];
406 }
407
266408 function fillInSeriesOptions() {
267409 var i;
268410
329471 if (s.lines.show == null) {
330472 var v, show = true;
331473 for (v in s)
332 if (s[v].show) {
474 if (s[v] && s[v].show) {
333475 show = false;
334476 break;
335477 }
338480 }
339481
340482 // setup axes
341 s.xaxis = axisSpecToRealAxis(s, "xaxis");
342 s.yaxis = axisSpecToRealAxis(s, "yaxis");
483 s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
484 s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
343485 }
344486 }
345487
346488 function processData() {
347489 var topSentry = Number.POSITIVE_INFINITY,
348490 bottomSentry = Number.NEGATIVE_INFINITY,
491 fakeInfinity = Number.MAX_VALUE,
349492 i, j, k, m, length,
350493 s, points, ps, x, y, axis, val, f, p;
351494
352 for (axis in axes) {
353 axes[axis].datamin = topSentry;
354 axes[axis].datamax = bottomSentry;
355 axes[axis].used = false;
356 }
357
358495 function updateAxis(axis, min, max) {
359 if (min < axis.datamin)
496 if (min < axis.datamin && min != -fakeInfinity)
360497 axis.datamin = min;
361 if (max > axis.datamax)
498 if (max > axis.datamax && max != fakeInfinity)
362499 axis.datamax = max;
363500 }
364501
502 $.each(allAxes(), function (_, axis) {
503 // init axis
504 axis.datamin = topSentry;
505 axis.datamax = bottomSentry;
506 axis.used = false;
507 });
508
365509 for (i = 0; i < series.length; ++i) {
366510 s = series[i];
367511 s.datapoints = { points: [] };
381525 format.push({ x: true, number: true, required: true });
382526 format.push({ y: true, number: true, required: true });
383527
384 if (s.bars.show)
528 if (s.bars.show || (s.lines.show && s.lines.fill)) {
385529 format.push({ y: true, number: true, required: false, defaultValue: 0 });
530 if (s.bars.horizontal) {
531 delete format[format.length - 1].y;
532 format[format.length - 1].x = true;
533 }
534 }
386535
387536 s.datapoints.format = format;
388537 }
390539 if (s.datapoints.pointsize != null)
391540 continue; // already filled in
392541
393 if (s.datapoints.pointsize == null)
394 s.datapoints.pointsize = format.length;
542 s.datapoints.pointsize = format.length;
395543
396544 ps = s.datapoints.pointsize;
397545 points = s.datapoints.points;
413561 val = +val; // convert to number
414562 if (isNaN(val))
415563 val = null;
564 else if (val == Infinity)
565 val = fakeInfinity;
566 else if (val == -Infinity)
567 val = -fakeInfinity;
416568 }
417569
418570 if (val == null) {
487639 for (m = 0; m < ps; ++m) {
488640 val = points[j + m];
489641 f = format[m];
490 if (!f)
642 if (!f || val == fakeInfinity || val == -fakeInfinity)
491643 continue;
492644
493645 if (f.x) {
522674 updateAxis(s.yaxis, ymin, ymax);
523675 }
524676
525 for (axis in axes) {
526 if (axes[axis].datamin == topSentry)
527 axes[axis].datamin = null;
528 if (axes[axis].datamax == bottomSentry)
529 axes[axis].datamax = null;
530 }
531 }
532
533 function constructCanvas() {
534 function makeCanvas(width, height) {
535 var c = document.createElement('canvas');
536 c.width = width;
537 c.height = height;
538 if ($.browser.msie) // excanvas hack
539 c = window.G_vmlCanvasManager.initElement(c);
540 return c;
541 }
542
677 $.each(allAxes(), function (_, axis) {
678 if (axis.datamin == topSentry)
679 axis.datamin = null;
680 if (axis.datamax == bottomSentry)
681 axis.datamax = null;
682 });
683 }
684
685 function makeCanvas(skipPositioning, cls) {
686 var c = document.createElement('canvas');
687 c.className = cls;
688 c.width = canvasWidth;
689 c.height = canvasHeight;
690
691 if (!skipPositioning)
692 $(c).css({ position: 'absolute', left: 0, top: 0 });
693
694 $(c).appendTo(placeholder);
695
696 if (!c.getContext) // excanvas hack
697 c = window.G_vmlCanvasManager.initElement(c);
698
699 // used for resetting in case we get replotted
700 c.getContext("2d").save();
701
702 return c;
703 }
704
705 function getCanvasDimensions() {
543706 canvasWidth = placeholder.width();
544707 canvasHeight = placeholder.height();
545 placeholder.html(""); // clear placeholder
546 if (placeholder.css("position") == 'static')
547 placeholder.css("position", "relative"); // for positioning labels and overlay
548
708
549709 if (canvasWidth <= 0 || canvasHeight <= 0)
550710 throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
551
552 if ($.browser.msie) // excanvas hack
553 window.G_vmlCanvasManager.init_(document); // make sure everything is setup
554
555 // the canvas
556 canvas = $(makeCanvas(canvasWidth, canvasHeight)).appendTo(placeholder).get(0);
711 }
712
713 function resizeCanvas(c) {
714 // resizing should reset the state (excanvas seems to be
715 // buggy though)
716 if (c.width != canvasWidth)
717 c.width = canvasWidth;
718
719 if (c.height != canvasHeight)
720 c.height = canvasHeight;
721
722 // so try to get back to the initial state (even if it's
723 // gone now, this should be safe according to the spec)
724 var cctx = c.getContext("2d");
725 cctx.restore();
726
727 // and save again
728 cctx.save();
729 }
730
731 function setupCanvases() {
732 var reused,
733 existingCanvas = placeholder.children("canvas.base"),
734 existingOverlay = placeholder.children("canvas.overlay");
735
736 if (existingCanvas.length == 0 || existingOverlay == 0) {
737 // init everything
738
739 placeholder.html(""); // make sure placeholder is clear
740
741 placeholder.css({ padding: 0 }); // padding messes up the positioning
742
743 if (placeholder.css("position") == 'static')
744 placeholder.css("position", "relative"); // for positioning labels and overlay
745
746 getCanvasDimensions();
747
748 canvas = makeCanvas(true, "base");
749 overlay = makeCanvas(false, "overlay"); // overlay canvas for interactive features
750
751 reused = false;
752 }
753 else {
754 // reuse existing elements
755
756 canvas = existingCanvas.get(0);
757 overlay = existingOverlay.get(0);
758
759 reused = true;
760 }
761
557762 ctx = canvas.getContext("2d");
558
559 // overlay canvas for interactive features
560 overlay = $(makeCanvas(canvasWidth, canvasHeight)).css({ position: 'absolute', left: 0, top: 0 }).appendTo(placeholder).get(0);
561763 octx = overlay.getContext("2d");
562 octx.stroke();
563 }
564
565 function bindEvents() {
764
566765 // we include the canvas in the event holder too, because IE 7
567766 // sometimes has trouble with the stacking order
568767 eventHolder = $([overlay, canvas]);
569768
769 if (reused) {
770 // run shutdown in the old plot object
771 placeholder.data("plot").shutdown();
772
773 // reset reused canvases
774 plot.resize();
775
776 // make sure overlay pixels are cleared (canvas is cleared when we redraw)
777 octx.clearRect(0, 0, canvasWidth, canvasHeight);
778
779 // then whack any remaining obvious garbage left
780 eventHolder.unbind();
781 placeholder.children().not([canvas, overlay]).remove();
782 }
783
784 // save in case we get replotted
785 placeholder.data("plot", plot);
786 }
787
788 function bindEvents() {
570789 // bind events
571 if (options.grid.hoverable)
790 if (options.grid.hoverable) {
572791 eventHolder.mousemove(onMouseMove);
792 eventHolder.mouseleave(onMouseLeave);
793 }
573794
574795 if (options.grid.clickable)
575796 eventHolder.click(onClick);
577798 executeHooks(hooks.bindEvents, [eventHolder]);
578799 }
579800
801 function shutdown() {
802 if (redrawTimeout)
803 clearTimeout(redrawTimeout);
804
805 eventHolder.unbind("mousemove", onMouseMove);
806 eventHolder.unbind("mouseleave", onMouseLeave);
807 eventHolder.unbind("click", onClick);
808
809 executeHooks(hooks.shutdown, [eventHolder]);
810 }
811
812 function setTransformationHelpers(axis) {
813 // set helper functions on the axis, assumes plot area
814 // has been computed already
815
816 function identity(x) { return x; }
817
818 var s, m, t = axis.options.transform || identity,
819 it = axis.options.inverseTransform;
820
821 // precompute how much the axis is scaling a point
822 // in canvas space
823 if (axis.direction == "x") {
824 s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
825 m = Math.min(t(axis.max), t(axis.min));
826 }
827 else {
828 s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
829 s = -s;
830 m = Math.max(t(axis.max), t(axis.min));
831 }
832
833 // data point to canvas coordinate
834 if (t == identity) // slight optimization
835 axis.p2c = function (p) { return (p - m) * s; };
836 else
837 axis.p2c = function (p) { return (t(p) - m) * s; };
838 // canvas coordinate to data point
839 if (!it)
840 axis.c2p = function (c) { return m + c / s; };
841 else
842 axis.c2p = function (c) { return it(m + c / s); };
843 }
844
845 function measureTickLabels(axis) {
846 var opts = axis.options, i, ticks = axis.ticks || [], labels = [],
847 l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;
848
849 function makeDummyDiv(labels, width) {
850 return $('<div style="position:absolute;top:-10000px;' + width + 'font-size:smaller">' +
851 '<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis">'
852 + labels.join("") + '</div></div>')
853 .appendTo(placeholder);
854 }
855
856 if (axis.direction == "x") {
857 // to avoid measuring the widths of the labels (it's slow), we
858 // construct fixed-size boxes and put the labels inside
859 // them, we don't need the exact figures and the
860 // fixed-size box content is easy to center
861 if (w == null)
862 w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));
863
864 // measure x label heights
865 if (h == null) {
866 labels = [];
867 for (i = 0; i < ticks.length; ++i) {
868 l = ticks[i].label;
869 if (l)
870 labels.push('<div class="tickLabel" style="float:left;width:' + w + 'px">' + l + '</div>');
871 }
872
873 if (labels.length > 0) {
874 // stick them all in the same div and measure
875 // collective height
876 labels.push('<div style="clear:left"></div>');
877 dummyDiv = makeDummyDiv(labels, "width:10000px;");
878 h = dummyDiv.height();
879 dummyDiv.remove();
880 }
881 }
882 }
883 else if (w == null || h == null) {
884 // calculate y label dimensions
885 for (i = 0; i < ticks.length; ++i) {
886 l = ticks[i].label;
887 if (l)
888 labels.push('<div class="tickLabel">' + l + '</div>');
889 }
890
891 if (labels.length > 0) {
892 dummyDiv = makeDummyDiv(labels, "");
893 if (w == null)
894 w = dummyDiv.children().width();
895 if (h == null)
896 h = dummyDiv.find("div.tickLabel").height();
897 dummyDiv.remove();
898 }
899 }
900
901 if (w == null)
902 w = 0;
903 if (h == null)
904 h = 0;
905
906 axis.labelWidth = w;
907 axis.labelHeight = h;
908 }
909
910 function allocateAxisBoxFirstPhase(axis) {
911 // find the bounding box of the axis by looking at label
912 // widths/heights and ticks, make room by diminishing the
913 // plotOffset
914
915 var lw = axis.labelWidth,
916 lh = axis.labelHeight,
917 pos = axis.options.position,
918 tickLength = axis.options.tickLength,
919 axismargin = options.grid.axisMargin,
920 padding = options.grid.labelMargin,
921 all = axis.direction == "x" ? xaxes : yaxes,
922 index;
923
924 // determine axis margin
925 var samePosition = $.grep(all, function (a) {
926 return a && a.options.position == pos && a.reserveSpace;
927 });
928 if ($.inArray(axis, samePosition) == samePosition.length - 1)
929 axismargin = 0; // outermost
930
931 // determine tick length - if we're innermost, we can use "full"
932 if (tickLength == null)
933 tickLength = "full";
934
935 var sameDirection = $.grep(all, function (a) {
936 return a && a.reserveSpace;
937 });
938
939 var innermost = $.inArray(axis, sameDirection) == 0;
940 if (!innermost && tickLength == "full")
941 tickLength = 5;
942
943 if (!isNaN(+tickLength))
944 padding += +tickLength;
945
946 // compute box
947 if (axis.direction == "x") {
948 lh += padding;
949
950 if (pos == "bottom") {
951 plotOffset.bottom += lh + axismargin;
952 axis.box = { top: canvasHeight - plotOffset.bottom, height: lh };
953 }
954 else {
955 axis.box = { top: plotOffset.top + axismargin, height: lh };
956 plotOffset.top += lh + axismargin;
957 }
958 }
959 else {
960 lw += padding;
961
962 if (pos == "left") {
963 axis.box = { left: plotOffset.left + axismargin, width: lw };
964 plotOffset.left += lw + axismargin;
965 }
966 else {
967 plotOffset.right += lw + axismargin;
968 axis.box = { left: canvasWidth - plotOffset.right, width: lw };
969 }
970 }
971
972 // save for future reference
973 axis.position = pos;
974 axis.tickLength = tickLength;
975 axis.box.padding = padding;
976 axis.innermost = innermost;
977 }
978
979 function allocateAxisBoxSecondPhase(axis) {
980 // set remaining bounding box coordinates
981 if (axis.direction == "x") {
982 axis.box.left = plotOffset.left;
983 axis.box.width = plotWidth;
984 }
985 else {
986 axis.box.top = plotOffset.top;
987 axis.box.height = plotHeight;
988 }
989 }
990
580991 function setupGrid() {
581 function setTransformationHelpers(axis, o) {
582 function identity(x) { return x; }
583
584 var s, m, t = o.transform || identity,
585 it = o.inverseTransform;
586
587 // add transformation helpers
588 if (axis == axes.xaxis || axis == axes.x2axis) {
589 // precompute how much the axis is scaling a point
590 // in canvas space
591 s = axis.scale = plotWidth / (t(axis.max) - t(axis.min));
592 m = t(axis.min);
593
594 // data point to canvas coordinate
595 if (t == identity) // slight optimization
596 axis.p2c = function (p) { return (p - m) * s; };
597 else
598 axis.p2c = function (p) { return (t(p) - m) * s; };
599 // canvas coordinate to data point
600 if (!it)
601 axis.c2p = function (c) { return m + c / s; };
602 else
603 axis.c2p = function (c) { return it(m + c / s); };
604 }
605 else {
606 s = axis.scale = plotHeight / (t(axis.max) - t(axis.min));
607 m = t(axis.max);
608
609 if (t == identity)
610 axis.p2c = function (p) { return (m - p) * s; };
611 else
612 axis.p2c = function (p) { return (m - t(p)) * s; };
613 if (!it)
614 axis.c2p = function (c) { return m - c / s; };
615 else
616 axis.c2p = function (c) { return it(m - c / s); };
617 }
618 }
619
620 function measureLabels(axis, axisOptions) {
621 var i, labels = [], l;
622
623 axis.labelWidth = axisOptions.labelWidth;
624 axis.labelHeight = axisOptions.labelHeight;
625
626 if (axis == axes.xaxis || axis == axes.x2axis) {
627 // to avoid measuring the widths of the labels, we
628 // construct fixed-size boxes and put the labels inside
629 // them, we don't need the exact figures and the
630 // fixed-size box content is easy to center
631 if (axis.labelWidth == null)
632 axis.labelWidth = canvasWidth / (axis.ticks.length > 0 ? axis.ticks.length : 1);
633
634 // measure x label heights
635 if (axis.labelHeight == null) {
636 labels = [];
637 for (i = 0; i < axis.ticks.length; ++i) {
638 l = axis.ticks[i].label;
639 if (l)
640 labels.push('<div class="tickLabel" style="float:left;width:' + axis.labelWidth + 'px">' + l + '</div>');
641 }
642
643 if (labels.length > 0) {
644 var dummyDiv = $('<div style="position:absolute;top:-10000px;width:10000px;font-size:smaller">'
645 + labels.join("") + '<div style="clear:left"></div></div>').appendTo(placeholder);
646 axis.labelHeight = dummyDiv.height();
647 dummyDiv.remove();
648 }
649 }
650 }
651 else if (axis.labelWidth == null || axis.labelHeight == null) {
652 // calculate y label dimensions
653 for (i = 0; i < axis.ticks.length; ++i) {
654 l = axis.ticks[i].label;
655 if (l)
656 labels.push('<div class="tickLabel">' + l + '</div>');
657 }
658
659 if (labels.length > 0) {
660 var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">'
661 + labels.join("") + '</div>').appendTo(placeholder);
662 if (axis.labelWidth == null)
663 axis.labelWidth = dummyDiv.width();
664 if (axis.labelHeight == null)
665 axis.labelHeight = dummyDiv.find("div").height();
666 dummyDiv.remove();
667 }
668
669 }
670
671 if (axis.labelWidth == null)
672 axis.labelWidth = 0;
673 if (axis.labelHeight == null)
674 axis.labelHeight = 0;
675 }
676
677 function setGridSpacing() {
678 // get the most space needed around the grid for things
679 // that may stick out
680 var maxOutset = options.grid.borderWidth;
681 for (i = 0; i < series.length; ++i)
682 maxOutset = Math.max(maxOutset, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
683
684 plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = maxOutset;
685
686 var margin = options.grid.labelMargin + options.grid.borderWidth;
687
688 if (axes.xaxis.labelHeight > 0)
689 plotOffset.bottom = Math.max(maxOutset, axes.xaxis.labelHeight + margin);
690 if (axes.yaxis.labelWidth > 0)
691 plotOffset.left = Math.max(maxOutset, axes.yaxis.labelWidth + margin);
692 if (axes.x2axis.labelHeight > 0)
693 plotOffset.top = Math.max(maxOutset, axes.x2axis.labelHeight + margin);
694 if (axes.y2axis.labelWidth > 0)
695 plotOffset.right = Math.max(maxOutset, axes.y2axis.labelWidth + margin);
696
697 plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
698 plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
699 }
700
701 var axis;
702 for (axis in axes)
703 setRange(axes[axis], options[axis]);
704
992 var i, axes = allAxes();
993
994 // first calculate the plot and axis box dimensions
995
996 $.each(axes, function (_, axis) {
997 axis.show = axis.options.show;
998 if (axis.show == null)
999 axis.show = axis.used; // by default an axis is visible if it's got data
1000
1001 axis.reserveSpace = axis.show || axis.options.reserveSpace;
1002
1003 setRange(axis);
1004 });
1005
1006 allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
1007
1008 plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;
7051009 if (options.grid.show) {
706 for (axis in axes) {
707 prepareTickGeneration(axes[axis], options[axis]);
708 setTicks(axes[axis], options[axis]);
709 measureLabels(axes[axis], options[axis]);
710 }
711
712 setGridSpacing();
713 }
714 else {
715 plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;
716 plotWidth = canvasWidth;
717 plotHeight = canvasHeight;
718 }
719
720 for (axis in axes)
721 setTransformationHelpers(axes[axis], options[axis]);
722
723 if (options.grid.show)
724 insertLabels();
1010 $.each(allocatedAxes, function (_, axis) {
1011 // make the ticks
1012 setupTickGeneration(axis);
1013 setTicks(axis);
1014 snapRangeToTicks(axis, axis.ticks);
1015
1016 // find labelWidth/Height for axis
1017 measureTickLabels(axis);
1018 });
1019
1020 // with all dimensions in house, we can compute the
1021 // axis boxes, start from the outside (reverse order)
1022 for (i = allocatedAxes.length - 1; i >= 0; --i)
1023 allocateAxisBoxFirstPhase(allocatedAxes[i]);
1024
1025 // make sure we've got enough space for things that
1026 // might stick out
1027 var minMargin = options.grid.minBorderMargin;
1028 if (minMargin == null) {
1029 minMargin = 0;
1030 for (i = 0; i < series.length; ++i)
1031 minMargin = Math.max(minMargin, series[i].points.radius + series[i].points.lineWidth/2);
1032 }
1033
1034 for (var a in plotOffset) {
1035 plotOffset[a] += options.grid.borderWidth;
1036 plotOffset[a] = Math.max(minMargin, plotOffset[a]);
1037 }
1038 }
1039
1040 plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
1041 plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
1042
1043 // now we got the proper plotWidth/Height, we can compute the scaling
1044 $.each(axes, function (_, axis) {
1045 setTransformationHelpers(axis);
1046 });
1047
1048 if (options.grid.show) {
1049 $.each(allocatedAxes, function (_, axis) {
1050 allocateAxisBoxSecondPhase(axis);
1051 });
1052
1053 insertAxisLabels();
1054 }
7251055
7261056 insertLegend();
7271057 }
7281058
729 function setRange(axis, axisOptions) {
730 var min = +(axisOptions.min != null ? axisOptions.min : axis.datamin),
731 max = +(axisOptions.max != null ? axisOptions.max : axis.datamax),
1059 function setRange(axis) {
1060 var opts = axis.options,
1061 min = +(opts.min != null ? opts.min : axis.datamin),
1062 max = +(opts.max != null ? opts.max : axis.datamax),
7321063 delta = max - min;
7331064
7341065 if (delta == 0.0) {
7351066 // degenerate case
7361067 var widen = max == 0 ? 1 : 0.01;
7371068
738 if (axisOptions.min == null)
1069 if (opts.min == null)
7391070 min -= widen;
740 // alway widen max if we couldn't widen min to ensure we
1071 // always widen max if we couldn't widen min to ensure we
7411072 // don't fall into min == max which doesn't work
742 if (axisOptions.max == null || axisOptions.min != null)
1073 if (opts.max == null || opts.min != null)
7431074 max += widen;
7441075 }
7451076 else {
7461077 // consider autoscaling
747 var margin = axisOptions.autoscaleMargin;
1078 var margin = opts.autoscaleMargin;
7481079 if (margin != null) {
749 if (axisOptions.min == null) {
1080 if (opts.min == null) {
7501081 min -= delta * margin;
7511082 // make sure we don't go below zero if all values
7521083 // are positive
7531084 if (min < 0 && axis.datamin != null && axis.datamin >= 0)
7541085 min = 0;
7551086 }
756 if (axisOptions.max == null) {
1087 if (opts.max == null) {
7571088 max += delta * margin;
7581089 if (max > 0 && axis.datamax != null && axis.datamax <= 0)
7591090 max = 0;
7641095 axis.max = max;
7651096 }
7661097
767 function prepareTickGeneration(axis, axisOptions) {
1098 function setupTickGeneration(axis) {
1099 var opts = axis.options;
1100
7681101 // estimate number of ticks
7691102 var noTicks;
770 if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0)
771 noTicks = axisOptions.ticks;
772 else if (axis == axes.xaxis || axis == axes.x2axis)
773 // heuristic based on the model a*sqrt(x) fitted to
774 // some reasonable data points
775 noTicks = 0.3 * Math.sqrt(canvasWidth);
1103 if (typeof opts.ticks == "number" && opts.ticks > 0)
1104 noTicks = opts.ticks;
7761105 else
777 noTicks = 0.3 * Math.sqrt(canvasHeight);
778
1106 // heuristic based on the model a*sqrt(x) fitted to
1107 // some data points that seemed reasonable
1108 noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? canvasWidth : canvasHeight);
1109
7791110 var delta = (axis.max - axis.min) / noTicks,
7801111 size, generator, unit, formatter, i, magn, norm;
7811112
782 if (axisOptions.mode == "time") {
1113 if (opts.mode == "time") {
7831114 // pretty handling of time
7841115
7851116 // map of app. size of time units in milliseconds
8091140 ];
8101141
8111142 var minSize = 0;
812 if (axisOptions.minTickSize != null) {
813 if (typeof axisOptions.tickSize == "number")
814 minSize = axisOptions.tickSize;
1143 if (opts.minTickSize != null) {
1144 if (typeof opts.tickSize == "number")
1145 minSize = opts.tickSize;
8151146 else
816 minSize = axisOptions.minTickSize[0] * timeUnitSize[axisOptions.minTickSize[1]];
817 }
818
819 for (i = 0; i < spec.length - 1; ++i)
1147 minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
1148 }
1149
1150 for (var i = 0; i < spec.length - 1; ++i)
8201151 if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]
8211152 + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
8221153 && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)
8401171 size *= magn;
8411172 }
8421173
843 if (axisOptions.tickSize) {
844 size = axisOptions.tickSize[0];
845 unit = axisOptions.tickSize[1];
846 }
1174 axis.tickSize = opts.tickSize || [size, unit];
8471175
8481176 generator = function(axis) {
8491177 var ticks = [],
8811209 do {
8821210 prev = v;
8831211 v = d.getTime();
884 ticks.push({ v: v, label: axis.tickFormatter(v, axis) });
1212 ticks.push(v);
8851213 if (unit == "month") {
8861214 if (tickSize < 1) {
8871215 // a bit complicated - we'll divide the month
9121240 var d = new Date(v);
9131241
9141242 // first check global format
915 if (axisOptions.timeformat != null)
916 return $.plot.formatDate(d, axisOptions.timeformat, axisOptions.monthNames);
1243 if (opts.timeformat != null)
1244 return $.plot.formatDate(d, opts.timeformat, opts.monthNames);
9171245
9181246 var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
9191247 var span = axis.max - axis.min;
920 var suffix = (axisOptions.twelveHourClock) ? " %p" : "";
1248 var suffix = (opts.twelveHourClock) ? " %p" : "";
9211249
9221250 if (t < timeUnitSize.minute)
9231251 fmt = "%h:%M:%S" + suffix;
9381266 else
9391267 fmt = "%y";
9401268
941 return $.plot.formatDate(d, fmt, axisOptions.monthNames);
1269 return $.plot.formatDate(d, fmt, opts.monthNames);
9421270 };
9431271 }
9441272 else {
9451273 // pretty rounding of base-10 numbers
946 var maxDec = axisOptions.tickDecimals;
1274 var maxDec = opts.tickDecimals;
9471275 var dec = -Math.floor(Math.log(delta) / Math.LN10);
9481276 if (maxDec != null && dec > maxDec)
9491277 dec = maxDec;
9681296
9691297 size *= magn;
9701298
971 if (axisOptions.minTickSize != null && size < axisOptions.minTickSize)
972 size = axisOptions.minTickSize;
973
974 if (axisOptions.tickSize != null)
975 size = axisOptions.tickSize;
976
977 axis.tickDecimals = Math.max(0, (maxDec != null) ? maxDec : dec);
1299 if (opts.minTickSize != null && size < opts.minTickSize)
1300 size = opts.minTickSize;
1301
1302 axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
1303 axis.tickSize = opts.tickSize || size;
9781304
9791305 generator = function (axis) {
9801306 var ticks = [];
9851311 do {
9861312 prev = v;
9871313 v = start + i * axis.tickSize;
988 ticks.push({ v: v, label: axis.tickFormatter(v, axis) });
1314 ticks.push(v);
9891315 ++i;
9901316 } while (v < axis.max && v != prev);
9911317 return ticks;
9961322 };
9971323 }
9981324
999 axis.tickSize = unit ? [size, unit] : size;
1325 if (opts.alignTicksWithAxis != null) {
1326 var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
1327 if (otherAxis && otherAxis.used && otherAxis != axis) {
1328 // consider snapping min/max to outermost nice ticks
1329 var niceTicks = generator(axis);
1330 if (niceTicks.length > 0) {
1331 if (opts.min == null)
1332 axis.min = Math.min(axis.min, niceTicks[0]);
1333 if (opts.max == null && niceTicks.length > 1)
1334 axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
1335 }
1336
1337 generator = function (axis) {
1338 // copy ticks, scaled to this axis
1339 var ticks = [], v, i;
1340 for (i = 0; i < otherAxis.ticks.length; ++i) {
1341 v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
1342 v = axis.min + v * (axis.max - axis.min);
1343 ticks.push(v);
1344 }
1345 return ticks;
1346 };
1347
1348 // we might need an extra decimal since forced
1349 // ticks don't necessarily fit naturally
1350 if (axis.mode != "time" && opts.tickDecimals == null) {
1351 var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),
1352 ts = generator(axis);
1353
1354 // only proceed if the tick interval rounded
1355 // with an extra decimal doesn't give us a
1356 // zero at end
1357 if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
1358 axis.tickDecimals = extraDec;
1359 }
1360 }
1361 }
1362
10001363 axis.tickGenerator = generator;
1001 if ($.isFunction(axisOptions.tickFormatter))
1002 axis.tickFormatter = function (v, axis) { return "" + axisOptions.tickFormatter(v, axis); };
1364 if ($.isFunction(opts.tickFormatter))
1365 axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
10031366 else
10041367 axis.tickFormatter = formatter;
10051368 }
10061369
1007 function setTicks(axis, axisOptions) {
1370 function setTicks(axis) {
1371 var oticks = axis.options.ticks, ticks = [];
1372 if (oticks == null || (typeof oticks == "number" && oticks > 0))
1373 ticks = axis.tickGenerator(axis);
1374 else if (oticks) {
1375 if ($.isFunction(oticks))
1376 // generate the ticks
1377 ticks = oticks({ min: axis.min, max: axis.max });
1378 else
1379 ticks = oticks;
1380 }
1381
1382 // clean up/labelify the supplied ticks, copy them over
1383 var i, v;
10081384 axis.ticks = [];
1009
1010 if (!axis.used)
1011 return;
1012
1013 if (axisOptions.ticks == null)
1014 axis.ticks = axis.tickGenerator(axis);
1015 else if (typeof axisOptions.ticks == "number") {
1016 if (axisOptions.ticks > 0)
1017 axis.ticks = axis.tickGenerator(axis);
1018 }
1019 else if (axisOptions.ticks) {
1020 var ticks = axisOptions.ticks;
1021
1022 if ($.isFunction(ticks))
1023 // generate the ticks
1024 ticks = ticks({ min: axis.min, max: axis.max });
1025
1026 // clean up the user-supplied ticks, copy them over
1027 var i, v;
1028 for (i = 0; i < ticks.length; ++i) {
1029 var label = null;
1030 var t = ticks[i];
1031 if (typeof t == "object") {
1032 v = t[0];
1033 if (t.length > 1)
1034 label = t[1];
1035 }
1036 else
1037 v = t;
1038 if (label == null)
1039 label = axis.tickFormatter(v, axis);
1040 axis.ticks[i] = { v: v, label: label };
1041 }
1042 }
1043
1044 if (axisOptions.autoscaleMargin != null && axis.ticks.length > 0) {
1385 for (i = 0; i < ticks.length; ++i) {
1386 var label = null;
1387 var t = ticks[i];
1388 if (typeof t == "object") {
1389 v = +t[0];
1390 if (t.length > 1)
1391 label = t[1];
1392 }
1393 else
1394 v = +t;
1395 if (label == null)
1396 label = axis.tickFormatter(v, axis);
1397 if (!isNaN(v))
1398 axis.ticks.push({ v: v, label: label });
1399 }
1400 }
1401
1402 function snapRangeToTicks(axis, ticks) {
1403 if (axis.options.autoscaleMargin && ticks.length > 0) {
10451404 // snap to ticks
1046 if (axisOptions.min == null)
1047 axis.min = Math.min(axis.min, axis.ticks[0].v);
1048 if (axisOptions.max == null && axis.ticks.length > 1)
1049 axis.max = Math.max(axis.max, axis.ticks[axis.ticks.length - 1].v);
1405 if (axis.options.min == null)
1406 axis.min = Math.min(axis.min, ticks[0].v);
1407 if (axis.options.max == null && ticks.length > 1)
1408 axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
10501409 }
10511410 }
10521411
10541413 ctx.clearRect(0, 0, canvasWidth, canvasHeight);
10551414
10561415 var grid = options.grid;
1416
1417 // draw background, if any
1418 if (grid.show && grid.backgroundColor)
1419 drawBackground();
10571420
10581421 if (grid.show && !grid.aboveData)
10591422 drawGrid();
10601423
1061 for (var i = 0; i < series.length; ++i)
1424 for (var i = 0; i < series.length; ++i) {
1425 executeHooks(hooks.drawSeries, [ctx, series[i]]);
10621426 drawSeries(series[i]);
1427 }
10631428
10641429 executeHooks(hooks.draw, [ctx]);
10651430
10681433 }
10691434
10701435 function extractRange(ranges, coord) {
1071 var firstAxis = coord + "axis",
1072 secondaryAxis = coord + "2axis",
1073 axis, from, to, reverse;
1074
1075 if (ranges[firstAxis]) {
1076 axis = axes[firstAxis];
1077 from = ranges[firstAxis].from;
1078 to = ranges[firstAxis].to;
1079 }
1080 else if (ranges[secondaryAxis]) {
1081 axis = axes[secondaryAxis];
1082 from = ranges[secondaryAxis].from;
1083 to = ranges[secondaryAxis].to;
1084 }
1085 else {
1086 // backwards-compat stuff - to be removed in future
1087 axis = axes[firstAxis];
1436 var axis, from, to, key, axes = allAxes();
1437
1438 for (i = 0; i < axes.length; ++i) {
1439 axis = axes[i];
1440 if (axis.direction == coord) {
1441 key = coord + axis.n + "axis";
1442 if (!ranges[key] && axis.n == 1)
1443 key = coord + "axis"; // support x1axis as xaxis
1444 if (ranges[key]) {
1445 from = ranges[key].from;
1446 to = ranges[key].to;
1447 break;
1448 }
1449 }
1450 }
1451
1452 // backwards-compat stuff - to be removed in future
1453 if (!ranges[key]) {
1454 axis = coord == "x" ? xaxes[0] : yaxes[0];
10881455 from = ranges[coord + "1"];
10891456 to = ranges[coord + "2"];
10901457 }
10911458
10921459 // auto-reverse as an added bonus
1093 if (from != null && to != null && from > to)
1094 return { from: to, to: from, axis: axis };
1460 if (from != null && to != null && from > to) {
1461 var tmp = from;
1462 from = to;
1463 to = tmp;
1464 }
10951465
10961466 return { from: from, to: to, axis: axis };
10971467 }
10981468
1469 function drawBackground() {
1470 ctx.save();
1471 ctx.translate(plotOffset.left, plotOffset.top);
1472
1473 ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
1474 ctx.fillRect(0, 0, plotWidth, plotHeight);
1475 ctx.restore();
1476 }
1477
10991478 function drawGrid() {
11001479 var i;
11011480
11021481 ctx.save();
11031482 ctx.translate(plotOffset.left, plotOffset.top);
1104
1105 // draw background, if any
1106 if (options.grid.backgroundColor) {
1107 ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
1108 ctx.fillRect(0, 0, plotWidth, plotHeight);
1109 }
11101483
11111484 // draw markings
11121485 var markings = options.grid.markings;
11131486 if (markings) {
1114 if ($.isFunction(markings))
1115 // xmin etc. are backwards-compatible, to be removed in future
1116 markings = markings({ xmin: axes.xaxis.min, xmax: axes.xaxis.max, ymin: axes.yaxis.min, ymax: axes.yaxis.max, xaxis: axes.xaxis, yaxis: axes.yaxis, x2axis: axes.x2axis, y2axis: axes.y2axis });
1487 if ($.isFunction(markings)) {
1488 var axes = plot.getAxes();
1489 // xmin etc. is backwards compatibility, to be
1490 // removed in the future
1491 axes.xmin = axes.xaxis.min;
1492 axes.xmax = axes.xaxis.max;
1493 axes.ymin = axes.yaxis.min;
1494 axes.ymax = axes.yaxis.max;
1495
1496 markings = markings(axes);
1497 }
11171498
11181499 for (i = 0; i < markings.length; ++i) {
11191500 var m = markings[i],
11541535 ctx.beginPath();
11551536 ctx.strokeStyle = m.color || options.grid.markingsColor;
11561537 ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
1157 //ctx.moveTo(Math.floor(xrange.from), yrange.from);
1158 //ctx.lineTo(Math.floor(xrange.to), yrange.to);
11591538 ctx.moveTo(xrange.from, yrange.from);
11601539 ctx.lineTo(xrange.to, yrange.to);
11611540 ctx.stroke();
11701549 }
11711550 }
11721551
1173 // draw the inner grid
1174 ctx.lineWidth = 1;
1175 ctx.strokeStyle = options.grid.tickColor;
1176 ctx.beginPath();
1177 var v, axis = axes.xaxis;
1178 for (i = 0; i < axis.ticks.length; ++i) {
1179 v = axis.ticks[i].v;
1180 if (v <= axis.min || v >= axes.xaxis.max)
1181 continue; // skip those lying on the axes
1182
1183 ctx.moveTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, 0);
1184 ctx.lineTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, plotHeight);
1185 }
1186
1187 axis = axes.yaxis;
1188 for (i = 0; i < axis.ticks.length; ++i) {
1189 v = axis.ticks[i].v;
1190 if (v <= axis.min || v >= axis.max)
1191 continue;
1192
1193 ctx.moveTo(0, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
1194 ctx.lineTo(plotWidth, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
1195 }
1196
1197 axis = axes.x2axis;
1198 for (i = 0; i < axis.ticks.length; ++i) {
1199 v = axis.ticks[i].v;
1200 if (v <= axis.min || v >= axis.max)
1201 continue;
1202
1203 ctx.moveTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, -5);
1204 ctx.lineTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, 5);
1205 }
1206
1207 axis = axes.y2axis;
1208 for (i = 0; i < axis.ticks.length; ++i) {
1209 v = axis.ticks[i].v;
1210 if (v <= axis.min || v >= axis.max)
1211 continue;
1212
1213 ctx.moveTo(plotWidth-5, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
1214 ctx.lineTo(plotWidth+5, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
1215 }
1216
1217 ctx.stroke();
1218
1219 if (options.grid.borderWidth) {
1220 // draw border
1221 var bw = options.grid.borderWidth;
1552 // draw the ticks
1553 var axes = allAxes(), bw = options.grid.borderWidth;
1554
1555 for (var j = 0; j < axes.length; ++j) {
1556 var axis = axes[j], box = axis.box,
1557 t = axis.tickLength, x, y, xoff, yoff;
1558 if (!axis.show || axis.ticks.length == 0)
1559 continue
1560
1561 ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();
1562 ctx.lineWidth = 1;
1563
1564 // find the edges
1565 if (axis.direction == "x") {
1566 x = 0;
1567 if (t == "full")
1568 y = (axis.position == "top" ? 0 : plotHeight);
1569 else
1570 y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
1571 }
1572 else {
1573 y = 0;
1574 if (t == "full")
1575 x = (axis.position == "left" ? 0 : plotWidth);
1576 else
1577 x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
1578 }
1579
1580 // draw tick bar
1581 if (!axis.innermost) {
1582 ctx.beginPath();
1583 xoff = yoff = 0;
1584 if (axis.direction == "x")
1585 xoff = plotWidth;
1586 else
1587 yoff = plotHeight;
1588
1589 if (ctx.lineWidth == 1) {
1590 x = Math.floor(x) + 0.5;
1591 y = Math.floor(y) + 0.5;
1592 }
1593
1594 ctx.moveTo(x, y);
1595 ctx.lineTo(x + xoff, y + yoff);
1596 ctx.stroke();
1597 }
1598
1599 // draw ticks
1600 ctx.beginPath();
1601 for (i = 0; i < axis.ticks.length; ++i) {
1602 var v = axis.ticks[i].v;
1603
1604 xoff = yoff = 0;
1605
1606 if (v < axis.min || v > axis.max
1607 // skip those lying on the axes if we got a border
1608 || (t == "full" && bw > 0
1609 && (v == axis.min || v == axis.max)))
1610 continue;
1611
1612 if (axis.direction == "x") {
1613 x = axis.p2c(v);
1614 yoff = t == "full" ? -plotHeight : t;
1615
1616 if (axis.position == "top")
1617 yoff = -yoff;
1618 }
1619 else {
1620 y = axis.p2c(v);
1621 xoff = t == "full" ? -plotWidth : t;
1622
1623 if (axis.position == "left")
1624 xoff = -xoff;
1625 }
1626
1627 if (ctx.lineWidth == 1) {
1628 if (axis.direction == "x")
1629 x = Math.floor(x) + 0.5;
1630 else
1631 y = Math.floor(y) + 0.5;
1632 }
1633
1634 ctx.moveTo(x, y);
1635 ctx.lineTo(x + xoff, y + yoff);
1636 }
1637
1638 ctx.stroke();
1639 }
1640
1641
1642 // draw border
1643 if (bw) {
12221644 ctx.lineWidth = bw;
12231645 ctx.strokeStyle = options.grid.borderColor;
12241646 ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
12271649 ctx.restore();
12281650 }
12291651
1230 function insertLabels() {
1652 function insertAxisLabels() {
12311653 placeholder.find(".tickLabels").remove();
12321654
1233 var html = ['<div class="tickLabels" style="font-size:smaller;color:' + options.grid.color + '">'];
1234
1235 function addLabels(axis, labelGenerator) {
1655 var html = ['<div class="tickLabels" style="font-size:smaller">'];
1656
1657 var axes = allAxes();
1658 for (var j = 0; j < axes.length; ++j) {
1659 var axis = axes[j], box = axis.box;
1660 if (!axis.show)
1661 continue;
1662 //debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
1663 html.push('<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis" style="color:' + axis.options.color + '">');
12361664 for (var i = 0; i < axis.ticks.length; ++i) {
12371665 var tick = axis.ticks[i];
12381666 if (!tick.label || tick.v < axis.min || tick.v > axis.max)
12391667 continue;
1240 html.push(labelGenerator(tick, axis));
1241 }
1242 }
1243
1244 var margin = options.grid.labelMargin + options.grid.borderWidth;
1245
1246 addLabels(axes.xaxis, function (tick, axis) {
1247 return '<div style="position:absolute;top:' + (plotOffset.top + plotHeight + margin) + 'px;left:' + Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2) + 'px;width:' + axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
1248 });
1249
1250
1251 addLabels(axes.yaxis, function (tick, axis) {
1252 return '<div style="position:absolute;top:' + Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2) + 'px;right:' + (plotOffset.right + plotWidth + margin) + 'px;width:' + axis.labelWidth + 'px;text-align:right" class="tickLabel">' + tick.label + "</div>";
1253 });
1254
1255 addLabels(axes.x2axis, function (tick, axis) {
1256 return '<div style="position:absolute;bottom:' + (plotOffset.bottom + plotHeight + margin) + 'px;left:' + Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2) + 'px;width:' + axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
1257 });
1258
1259 addLabels(axes.y2axis, function (tick, axis) {
1260 return '<div style="position:absolute;top:' + Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2) + 'px;left:' + (plotOffset.left + plotWidth + margin) +'px;width:' + axis.labelWidth + 'px;text-align:left" class="tickLabel">' + tick.label + "</div>";
1261 });
1668
1669 var pos = {}, align;
1670
1671 if (axis.direction == "x") {
1672 align = "center";
1673 pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);
1674 if (axis.position == "bottom")
1675 pos.top = box.top + box.padding;
1676 else
1677 pos.bottom = canvasHeight - (box.top + box.height - box.padding);
1678 }
1679 else {
1680 pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);
1681 if (axis.position == "left") {
1682 pos.right = canvasWidth - (box.left + box.width - box.padding)
1683 align = "right";
1684 }
1685 else {
1686 pos.left = box.left + box.padding;
1687 align = "left";
1688 }
1689 }
1690
1691 pos.width = axis.labelWidth;
1692
1693 var style = ["position:absolute", "text-align:" + align ];
1694 for (var a in pos)
1695 style.push(a + ":" + pos[a] + "px")
1696
1697 html.push('<div class="tickLabel" style="' + style.join(';') + '">' + tick.label + '</div>');
1698 }
1699 html.push('</div>');
1700 }
12621701
12631702 html.push('</div>');
1264
1703
12651704 placeholder.append(html.join(""));
12661705 }
12671706
13591798 var points = datapoints.points,
13601799 ps = datapoints.pointsize,
13611800 bottom = Math.min(Math.max(0, axisy.min), axisy.max),
1362 top, lastX = 0, areaOpen = false;
1363
1364 for (var i = ps; i < points.length; i += ps) {
1365 var x1 = points[i - ps], y1 = points[i - ps + 1],
1366 x2 = points[i], y2 = points[i + 1];
1367
1368 if (areaOpen && x1 != null && x2 == null) {
1369 // close area
1370 ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
1371 ctx.fill();
1372 areaOpen = false;
1373 continue;
1801 i = 0, top, areaOpen = false,
1802 ypos = 1, segmentStart = 0, segmentEnd = 0;
1803
1804 // we process each segment in two turns, first forward
1805 // direction to sketch out top, then once we hit the
1806 // end we go backwards to sketch the bottom
1807 while (true) {
1808 if (ps > 0 && i > points.length + ps)
1809 break;
1810
1811 i += ps; // ps is negative if going backwards
1812
1813 var x1 = points[i - ps],
1814 y1 = points[i - ps + ypos],
1815 x2 = points[i], y2 = points[i + ypos];
1816
1817 if (areaOpen) {
1818 if (ps > 0 && x1 != null && x2 == null) {
1819 // at turning point
1820 segmentEnd = i;
1821 ps = -ps;
1822 ypos = 2;
1823 continue;
1824 }
1825
1826 if (ps < 0 && i == segmentStart + ps) {
1827 // done with the reverse sweep
1828 ctx.fill();
1829 areaOpen = false;
1830 ps = -ps;
1831 ypos = 1;
1832 i = segmentStart = segmentEnd + ps;
1833 continue;
1834 }
13741835 }
13751836
13761837 if (x1 == null || x2 == null)
14171878 if (y1 >= axisy.max && y2 >= axisy.max) {
14181879 ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
14191880 ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
1420 lastX = x2;
14211881 continue;
14221882 }
14231883 else if (y1 <= axisy.min && y2 <= axisy.min) {
14241884 ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
14251885 ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
1426 lastX = x2;
14271886 continue;
14281887 }
14291888
14301889 // else it's a bit more complicated, there might
1431 // be two rectangles and two triangles we need to fill
1432 // in; to find these keep track of the current x values
1890 // be a flat maxed out rectangle first, then a
1891 // triangular cutout or reverse; to find these
1892 // keep track of the current x values
14331893 var x1old = x1, x2old = x2;
14341894
1435 // and clip the y values, without shortcutting
1895 // clip the y values, without shortcutting, we
1896 // go through all cases in turn
14361897
14371898 // clip with ymin
14381899 if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
14541915 y2 = axisy.max;
14551916 }
14561917
1457
14581918 // if the x value was changed we got a rectangle
14591919 // to fill
14601920 if (x1 != x1old) {
1461 if (y1 <= axisy.min)
1462 top = axisy.min;
1463 else
1464 top = axisy.max;
1465
1466 ctx.lineTo(axisx.p2c(x1old), axisy.p2c(top));
1467 ctx.lineTo(axisx.p2c(x1), axisy.p2c(top));
1468 }
1469
1470 // fill the triangles
1921 ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
1922 // it goes to (x1, y1), but we fill that below
1923 }
1924
1925 // fill triangular section, this sometimes result
1926 // in redundant points if (x1, y1) hasn't changed
1927 // from previous line to, but we just ignore that
14711928 ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
14721929 ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
14731930
14741931 // fill the other rectangle if it's there
14751932 if (x2 != x2old) {
1476 if (y2 <= axisy.min)
1477 top = axisy.min;
1478 else
1479 top = axisy.max;
1480
1481 ctx.lineTo(axisx.p2c(x2), axisy.p2c(top));
1482 ctx.lineTo(axisx.p2c(x2old), axisy.p2c(top));
1483 }
1484
1485 lastX = Math.max(x2, x2old);
1486 }
1487
1488 if (areaOpen) {
1489 ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
1490 ctx.fill();
1491 }
1492 }
1493
1933 ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
1934 ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
1935 }
1936 }
1937 }
1938
14941939 ctx.save();
14951940 ctx.translate(plotOffset.left, plotOffset.top);
14961941 ctx.lineJoin = "round";
15231968 }
15241969
15251970 function drawSeriesPoints(series) {
1526 function plotPoints(datapoints, radius, fillStyle, offset, circumference, axisx, axisy) {
1971 function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
15271972 var points = datapoints.points, ps = datapoints.pointsize;
1528
1973
15291974 for (var i = 0; i < points.length; i += ps) {
15301975 var x = points[i], y = points[i + 1];
15311976 if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
15321977 continue;
15331978
15341979 ctx.beginPath();
1535 ctx.arc(axisx.p2c(x), axisy.p2c(y) + offset, radius, 0, circumference, false);
1980 x = axisx.p2c(x);
1981 y = axisy.p2c(y) + offset;
1982 if (symbol == "circle")
1983 ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
1984 else
1985 symbol(ctx, x, y, radius, shadow);
1986 ctx.closePath();
1987
15361988 if (fillStyle) {
15371989 ctx.fillStyle = fillStyle;
15381990 ctx.fill();
15441996 ctx.save();
15451997 ctx.translate(plotOffset.left, plotOffset.top);
15461998
1547 var lw = series.lines.lineWidth,
1999 var lw = series.points.lineWidth,
15482000 sw = series.shadowSize,
1549 radius = series.points.radius;
2001 radius = series.points.radius,
2002 symbol = series.points.symbol;
15502003 if (lw > 0 && sw > 0) {
15512004 // draw shadow in two steps
15522005 var w = sw / 2;
15532006 ctx.lineWidth = w;
15542007 ctx.strokeStyle = "rgba(0,0,0,0.1)";
1555 plotPoints(series.datapoints, radius, null, w + w/2, Math.PI,
1556 series.xaxis, series.yaxis);
2008 plotPoints(series.datapoints, radius, null, w + w/2, true,
2009 series.xaxis, series.yaxis, symbol);
15572010
15582011 ctx.strokeStyle = "rgba(0,0,0,0.2)";
1559 plotPoints(series.datapoints, radius, null, w/2, Math.PI,
1560 series.xaxis, series.yaxis);
2012 plotPoints(series.datapoints, radius, null, w/2, true,
2013 series.xaxis, series.yaxis, symbol);
15612014 }
15622015
15632016 ctx.lineWidth = lw;
15642017 ctx.strokeStyle = series.color;
15652018 plotPoints(series.datapoints, radius,
1566 getFillStyle(series.points, series.color), 0, 2 * Math.PI,
1567 series.xaxis, series.yaxis);
2019 getFillStyle(series.points, series.color), 0, false,
2020 series.xaxis, series.yaxis, symbol);
15682021 ctx.restore();
15692022 }
15702023
1571 function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal) {
2024 function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
15722025 var left, right, bottom, top,
15732026 drawLeft, drawRight, drawTop, drawBottom,
15742027 tmp;
15752028
2029 // in horizontal mode, we start the bar from the left
2030 // instead of from the bottom so it appears to be
2031 // horizontal rather than vertical
15762032 if (horizontal) {
15772033 drawBottom = drawRight = drawTop = true;
15782034 drawLeft = false;
16502106 }
16512107
16522108 // draw outline
1653 if (drawLeft || drawRight || drawTop || drawBottom) {
2109 if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
16542110 c.beginPath();
16552111
16562112 // FIXME: inline moveTo is buggy with excanvas
16822138 for (var i = 0; i < points.length; i += ps) {
16832139 if (points[i] == null)
16842140 continue;
1685 drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal);
2141 drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
16862142 }
16872143 }
16882144
17202176
17212177 var fragments = [], rowStarted = false,
17222178 lf = options.legend.labelFormatter, s, label;
1723 for (i = 0; i < series.length; ++i) {
2179 for (var i = 0; i < series.length; ++i) {
17242180 s = series[i];
17252181 label = s.label;
17262182 if (!label)
17962252 smallestDistance = maxDistance * maxDistance + 1,
17972253 item = null, foundPoint = false, i, j;
17982254
1799 for (i = 0; i < series.length; ++i) {
2255 for (i = series.length - 1; i >= 0; --i) {
18002256 if (!seriesFilter(series[i]))
18012257 continue;
18022258
18102266 maxx = maxDistance / axisx.scale,
18112267 maxy = maxDistance / axisy.scale;
18122268
2269 // with inverse transforms, we can't use the maxx/maxy
2270 // optimization, sadly
2271 if (axisx.options.inverseTransform)
2272 maxx = Number.MAX_VALUE;
2273 if (axisy.options.inverseTransform)
2274 maxy = Number.MAX_VALUE;
2275
18132276 if (s.lines.show || s.points.show) {
18142277 for (j = 0; j < points.length; j += ps) {
18152278 var x = points[j], y = points[j + 1];
18302293
18312294 // use <= to ensure last point takes precedence
18322295 // (last generally means on top of)
1833 if (dist <= smallestDistance) {
2296 if (dist < smallestDistance) {
18342297 smallestDistance = dist;
18352298 item = [i, j / ps];
18362299 }
18762339 triggerClickHoverEvent("plothover", e,
18772340 function (s) { return s["hoverable"] != false; });
18782341 }
1879
2342
2343 function onMouseLeave(e) {
2344 if (options.grid.hoverable)
2345 triggerClickHoverEvent("plothover", e,
2346 function (s) { return false; });
2347 }
2348
18802349 function onClick(e) {
18812350 triggerClickHoverEvent("plotclick", e,
18822351 function (s) { return s["clickable"] != false; });
18862355 // so we share their code)
18872356 function triggerClickHoverEvent(eventname, event, seriesFilter) {
18882357 var offset = eventHolder.offset(),
1889 pos = { pageX: event.pageX, pageY: event.pageY },
18902358 canvasX = event.pageX - offset.left - plotOffset.left,
1891 canvasY = event.pageY - offset.top - plotOffset.top;
1892
1893 if (axes.xaxis.used)
1894 pos.x = axes.xaxis.c2p(canvasX);
1895 if (axes.yaxis.used)
1896 pos.y = axes.yaxis.c2p(canvasY);
1897 if (axes.x2axis.used)
1898 pos.x2 = axes.x2axis.c2p(canvasX);
1899 if (axes.y2axis.used)
1900 pos.y2 = axes.y2axis.c2p(canvasY);
2359 canvasY = event.pageY - offset.top - plotOffset.top,
2360 pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
2361
2362 pos.pageX = event.pageX;
2363 pos.pageY = event.pageY;
19012364
19022365 var item = findNearbyItem(canvasX, canvasY, seriesFilter);
19032366
19122375 for (var i = 0; i < highlights.length; ++i) {
19132376 var h = highlights[i];
19142377 if (h.auto == eventname &&
1915 !(item && h.series == item.series && h.point == item.datapoint))
2378 !(item && h.series == item.series &&
2379 h.point[0] == item.datapoint[0] &&
2380 h.point[1] == item.datapoint[1]))
19162381 unhighlight(h.series, h.point);
19172382 }
19182383
19542419 if (typeof s == "number")
19552420 s = series[s];
19562421
1957 if (typeof point == "number")
1958 point = s.data[point];
2422 if (typeof point == "number") {
2423 var ps = s.datapoints.pointsize;
2424 point = s.datapoints.points.slice(ps * point, ps * (point + 1));
2425 }
19592426
19602427 var i = indexOfHighlight(s, point);
19612428 if (i == -1) {
20072474 var pointRadius = series.points.radius + series.points.lineWidth / 2;
20082475 octx.lineWidth = pointRadius;
20092476 octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();
2010 var radius = 1.5 * pointRadius;
2477 var radius = 1.5 * pointRadius,
2478 x = axisx.p2c(x),
2479 y = axisy.p2c(y);
2480
20112481 octx.beginPath();
2012 octx.arc(axisx.p2c(x), axisy.p2c(y), radius, 0, 2 * Math.PI, false);
2482 if (series.points.symbol == "circle")
2483 octx.arc(x, y, radius, 0, 2 * Math.PI, false);
2484 else
2485 series.points.symbol(octx, x, y, radius, false);
2486 octx.closePath();
20132487 octx.stroke();
20142488 }
20152489
20192493 var fillStyle = $.color.parse(series.color).scale('a', 0.5).toString();
20202494 var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
20212495 drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
2022 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal);
2496 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
20232497 }
20242498
20252499 function getColorOrGradient(spec, bottom, top, defaultColor) {
20342508 for (var i = 0, l = spec.colors.length; i < l; ++i) {
20352509 var c = spec.colors[i];
20362510 if (typeof c != "string") {
2037 c = $.color.parse(defaultColor).scale('rgb', c.brightness);
2038 c.a *= c.opacity;
2039 c = c.toString();
2511 var co = $.color.parse(defaultColor);
2512 if (c.brightness != null)
2513 co = co.scale('rgb', c.brightness)
2514 if (c.opacity != null)
2515 co.a *= c.opacity;
2516 c = co.toString();
20402517 }
20412518 gradient.addColorStop(i / (l - 1), c);
20422519 }
20472524 }
20482525
20492526 $.plot = function(placeholder, data, options) {
2527 //var t0 = new Date();
20502528 var plot = new Plot($(placeholder), data, options, $.plot.plugins);
2051 /*var t0 = new Date();
2052 var t1 = new Date();
2053 var tstr = "time used (msecs): " + (t1.getTime() - t0.getTime())
2054 if (window.console)
2055 console.log(tstr);
2056 else
2057 alert(tstr);*/
2529 //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
20582530 return plot;
20592531 };
20602532
2533 $.plot.version = "0.7";
2534
20612535 $.plot.plugins = [];
20622536
20632537 // returns a string with the date d formatted according to fmt
20682542 };
20692543
20702544 var r = [];
2071 var escape = false;
2545 var escape = false, padNext = false;
20722546 var hours = d.getUTCHours();
20732547 var isAM = hours < 12;
20742548 if (monthNames == null)
20962570 case 'b': c = "" + monthNames[d.getUTCMonth()]; break;
20972571 case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
20982572 case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
2573 case '0': c = ""; padNext = true; break;
2574 }
2575 if (c && padNext) {
2576 c = leftPad(c);
2577 padNext = false;
20992578 }
21002579 r.push(c);
2101 escape = false;
2580 if (!padNext)
2581 escape = false;
21022582 }
21032583 else {
21042584 if (c == "%")
66 controls. It also fires a "plotpan" and "plotzoom" event when
77 something happens, useful for synchronizing plots.
88
9 Example usage:
10
11 plot = $.plot(...);
12
13 // zoom default amount in on the pixel (100, 200)
14 plot.zoom({ center: { left: 10, top: 20 } });
15
16 // zoom out again
17 plot.zoomOut({ center: { left: 10, top: 20 } });
18
19 // pan 100 pixels to the left and 20 down
20 plot.pan({ left: -100, top: 20 })
21
22
239 Options:
2410
2511 zoom: {
3016
3117 pan: {
3218 interactive: false
19 cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer"
20 frameRate: 20
3321 }
3422
3523 xaxis, yaxis, x2axis, y2axis: {
36 zoomRange: null // or [number, number] (min range, max range)
37 panRange: null // or [number, number] (min, max)
24 zoomRange: null // or [number, number] (min range, max range) or false
25 panRange: null // or [number, number] (min, max) or false
3826 }
3927
40 "interactive" enables the built-in drag/click behaviour. "amount" is
41 the amount to zoom the viewport relative to the current range, so 1 is
42 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out).
28 "interactive" enables the built-in drag/click behaviour. If you enable
29 interactive for pan, then you'll have a basic plot that supports
30 moving around; the same for zoom.
31
32 "amount" specifies the default amount to zoom in (so 1.5 = 150%)
33 relative to the current viewport.
34
35 "cursor" is a standard CSS mouse cursor string used for visual
36 feedback to the user when dragging.
37
38 "frameRate" specifies the maximum number of times per second the plot
39 will update itself while the user is panning around on it (set to null
40 to disable intermediate pans, the plot will then not update until the
41 mouse button is released).
4342
4443 "zoomRange" is the interval in which zooming can happen, e.g. with
4544 zoomRange: [1, 100] the zoom will never scale the axis so that the
4645 difference between min and max is smaller than 1 or larger than 100.
47 You can set either of them to null to ignore.
46 You can set either end to null to ignore, e.g. [1, null]. If you set
47 zoomRange to false, zooming on that axis will be disabled.
4848
4949 "panRange" confines the panning to stay within a range, e.g. with
5050 panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
51 other. Either can be null.
51 other. Either can be null, e.g. [-10, null]. If you set
52 panRange to false, panning on that axis will be disabled.
53
54 Example API usage:
55
56 plot = $.plot(...);
57
58 // zoom default amount in on the pixel (10, 20)
59 plot.zoom({ center: { left: 10, top: 20 } });
60
61 // zoom out again
62 plot.zoomOut({ center: { left: 10, top: 20 } });
63
64 // zoom 200% in on the pixel (10, 20)
65 plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
66
67 // pan 100 pixels to the left and 20 down
68 plot.pan({ left: -100, top: 20 })
69
70 Here, "center" specifies where the center of the zooming should
71 happen. Note that this is defined in pixel space, not the space of the
72 data points (you can use the p2c helpers on the axes in Flot to help
73 you convert between these).
74
75 "amount" is the amount to zoom the viewport relative to the current
76 range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is
77 70% (zoom out). You can set the default in the options.
78
5279 */
5380
5481
91118 amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
92119 },
93120 pan: {
94 interactive: false
121 interactive: false,
122 cursor: "move",
123 frameRate: 20
95124 }
96125 };
97126
98127 function init(plot) {
128 function onZoomClick(e, zoomOut) {
129 var c = plot.offset();
130 c.left = e.pageX - c.left;
131 c.top = e.pageY - c.top;
132 if (zoomOut)
133 plot.zoomOut({ center: c });
134 else
135 plot.zoom({ center: c });
136 }
137
138 function onMouseWheel(e, delta) {
139 onZoomClick(e, delta < 0);
140 return false;
141 }
142
143 var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
144 panTimeout = null;
145
146 function onDragStart(e) {
147 if (e.which != 1) // only accept left-click
148 return false;
149 var c = plot.getPlaceholder().css('cursor');
150 if (c)
151 prevCursor = c;
152 plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
153 prevPageX = e.pageX;
154 prevPageY = e.pageY;
155 }
156
157 function onDrag(e) {
158 var frameRate = plot.getOptions().pan.frameRate;
159 if (panTimeout || !frameRate)
160 return;
161
162 panTimeout = setTimeout(function () {
163 plot.pan({ left: prevPageX - e.pageX,
164 top: prevPageY - e.pageY });
165 prevPageX = e.pageX;
166 prevPageY = e.pageY;
167
168 panTimeout = null;
169 }, 1 / frameRate * 1000);
170 }
171
172 function onDragEnd(e) {
173 if (panTimeout) {
174 clearTimeout(panTimeout);
175 panTimeout = null;
176 }
177
178 plot.getPlaceholder().css('cursor', prevCursor);
179 plot.pan({ left: prevPageX - e.pageX,
180 top: prevPageY - e.pageY });
181 }
182
99183 function bindEvents(plot, eventHolder) {
100184 var o = plot.getOptions();
101185 if (o.zoom.interactive) {
102 function clickHandler(e, zoomOut) {
103 var c = plot.offset();
104 c.left = e.pageX - c.left;
105 c.top = e.pageY - c.top;
106 if (zoomOut)
107 plot.zoomOut({ center: c });
108 else
109 plot.zoom({ center: c });
110 }
111
112 eventHolder[o.zoom.trigger](clickHandler);
113
114 eventHolder.mousewheel(function (e, delta) {
115 clickHandler(e, delta < 0);
116 return false;
117 });
186 eventHolder[o.zoom.trigger](onZoomClick);
187 eventHolder.mousewheel(onMouseWheel);
118188 }
189
119190 if (o.pan.interactive) {
120 var prevCursor = 'default', pageX = 0, pageY = 0;
121
122 eventHolder.bind("dragstart", { distance: 10 }, function (e) {
123 if (e.which != 1) // only accept left-click
124 return false;
125 eventHolderCursor = eventHolder.css('cursor');
126 eventHolder.css('cursor', 'move');
127 pageX = e.pageX;
128 pageY = e.pageY;
129 });
130 eventHolder.bind("drag", function (e) {
131 // unused at the moment, but we need it here to
132 // trigger the dragstart/dragend events
133 });
134 eventHolder.bind("dragend", function (e) {
135 eventHolder.css('cursor', prevCursor);
136 plot.pan({ left: pageX - e.pageX,
137 top: pageY - e.pageY });
138 });
191 eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
192 eventHolder.bind("drag", onDrag);
193 eventHolder.bind("dragend", onDragEnd);
139194 }
140195 }
141196
154209 if (!args)
155210 args = {};
156211
157 var axes = plot.getAxes(),
158 options = plot.getOptions(),
159 c = args.center,
160 amount = args.amount ? args.amount : options.zoom.amount,
212 var c = args.center,
213 amount = args.amount || plot.getOptions().zoom.amount,
161214 w = plot.width(), h = plot.height();
162215
163216 if (!c)
164217 c = { left: w / 2, top: h / 2 };
165218
166219 var xf = c.left / w,
167 x1 = c.left - xf * w / amount,
168 x2 = c.left + (1 - xf) * w / amount,
169220 yf = c.top / h,
170 y1 = c.top - yf * h / amount,
171 y2 = c.top + (1 - yf) * h / amount;
172
173 function scaleAxis(min, max, name) {
174 var axis = axes[name],
175 axisOptions = options[name];
176
177 if (!axis.used)
221 minmax = {
222 x: {
223 min: c.left - xf * w / amount,
224 max: c.left + (1 - xf) * w / amount
225 },
226 y: {
227 min: c.top - yf * h / amount,
228 max: c.top + (1 - yf) * h / amount
229 }
230 };
231
232 $.each(plot.getAxes(), function(_, axis) {
233 var opts = axis.options,
234 min = minmax[axis.direction].min,
235 max = minmax[axis.direction].max,
236 zr = opts.zoomRange;
237
238 if (zr === false) // no zooming on this axis
178239 return;
179240
180241 min = axis.c2p(min);
181242 max = axis.c2p(max);
182 if (max < min) { // make sure min < max
183 var tmp = min
243 if (min > max) {
244 // make sure min < max
245 var tmp = min;
184246 min = max;
185247 max = tmp;
186248 }
187249
188 var range = max - min, zr = axisOptions.zoomRange;
250 var range = max - min;
189251 if (zr &&
190252 ((zr[0] != null && range < zr[0]) ||
191253 (zr[1] != null && range > zr[1])))
192254 return;
193255
194 axisOptions.min = min;
195 axisOptions.max = max;
196 }
197
198 scaleAxis(x1, x2, 'xaxis');
199 scaleAxis(x1, x2, 'x2axis');
200 scaleAxis(y1, y2, 'yaxis');
201 scaleAxis(y1, y2, 'y2axis');
256 opts.min = min;
257 opts.max = max;
258 });
202259
203260 plot.setupGrid();
204261 plot.draw();
208265 }
209266
210267 plot.pan = function (args) {
211 var l = +args.left, t = +args.top,
212 axes = plot.getAxes(), options = plot.getOptions();
213
214 if (isNaN(l))
215 l = 0;
216 if (isNaN(t))
217 t = 0;
218
219 function panAxis(delta, name) {
220 var axis = axes[name],
221 axisOptions = options[name],
222 min, max;
268 var delta = {
269 x: +args.left,
270 y: +args.top
271 };
272
273 if (isNaN(delta.x))
274 delta.x = 0;
275 if (isNaN(delta.y))
276 delta.y = 0;
277
278 $.each(plot.getAxes(), function (_, axis) {
279 var opts = axis.options,
280 min, max, d = delta[axis.direction];
281
282 min = axis.c2p(axis.p2c(axis.min) + d),
283 max = axis.c2p(axis.p2c(axis.max) + d);
284
285 var pr = opts.panRange;
286 if (pr === false) // no panning on this axis
287 return;
223288
224 if (!axis.used)
225 return;
226
227 min = axis.c2p(axis.p2c(axis.min) + delta),
228 max = axis.c2p(axis.p2c(axis.max) + delta);
229
230 var pr = axisOptions.panRange;
231289 if (pr) {
232290 // check whether we hit the wall
233291 if (pr[0] != null && pr[0] > min) {
234 delta = pr[0] - min;
235 min += delta;
236 max += delta;
292 d = pr[0] - min;
293 min += d;
294 max += d;
237295 }
238296
239297 if (pr[1] != null && pr[1] < max) {
240 delta = pr[1] - max;
241 min += delta;
242 max += delta;
298 d = pr[1] - max;
299 min += d;
300 max += d;
243301 }
244302 }
245303
246 axisOptions.min = min;
247 axisOptions.max = max;
248 }
249
250 panAxis(l, 'xaxis');
251 panAxis(l, 'x2axis');
252 panAxis(t, 'yaxis');
253 panAxis(t, 'y2axis');
304 opts.min = min;
305 opts.max = max;
306 });
254307
255308 plot.setupGrid();
256309 plot.draw();
258311 if (!args.preventEvent)
259312 plot.getPlaceholder().trigger("plotpan", [ plot ]);
260313 }
314
315 function shutdown(plot, eventHolder) {
316 eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
317 eventHolder.unbind("mousewheel", onMouseWheel);
318 eventHolder.unbind("dragstart", onDragStart);
319 eventHolder.unbind("drag", onDrag);
320 eventHolder.unbind("dragend", onDragEnd);
321 if (panTimeout)
322 clearTimeout(panTimeout);
323 }
261324
262325 plot.hooks.bindEvents.push(bindEvents);
326 plot.hooks.shutdown.push(shutdown);
263327 }
264328
265329 $.plot.plugins.push({
266330 init: init,
267331 options: options,
268332 name: 'navigate',
269 version: '1.1'
333 version: '1.3'
270334 });
271335 })(jQuery);
0 /*
1 Flot plugin for rendering pie charts. The plugin assumes the data is
2 coming is as a single data value for each series, and each of those
3 values is a positive value or zero (negative numbers don't make
4 any sense and will cause strange effects). The data values do
5 NOT need to be passed in as percentage values because it
6 internally calculates the total and percentages.
7
8 * Created by Brian Medendorp, June 2009
9 * Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
10
11 * Changes:
12 2009-10-22: lineJoin set to round
13 2009-10-23: IE full circle fix, donut
14 2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
15 2009-11-17: Added IE hover capability submitted by Anthony Aragues
16 2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
17
18
19 Available options are:
20 series: {
21 pie: {
22 show: true/false
23 radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
24 innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
25 startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
26 tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
27 offset: {
28 top: integer value to move the pie up or down
29 left: integer value to move the pie left or right, or 'auto'
30 },
31 stroke: {
32 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
33 width: integer pixel width of the stroke
34 },
35 label: {
36 show: true/false, or 'auto'
37 formatter: a user-defined function that modifies the text/style of the label text
38 radius: 0-1 for percentage of fullsize, or a specified pixel length
39 background: {
40 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
41 opacity: 0-1
42 },
43 threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
44 },
45 combine: {
46 threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
47 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
48 label: any text value of what the combined slice should be labeled
49 }
50 highlight: {
51 opacity: 0-1
52 }
53 }
54 }
55
56 More detail and specific examples can be found in the included HTML file.
57
58 */
59
60 (function ($)
61 {
62 function init(plot) // this is the "body" of the plugin
63 {
64 var canvas = null;
65 var target = null;
66 var maxRadius = null;
67 var centerLeft = null;
68 var centerTop = null;
69 var total = 0;
70 var redraw = true;
71 var redrawAttempts = 10;
72 var shrink = 0.95;
73 var legendWidth = 0;
74 var processed = false;
75 var raw = false;
76
77 // interactive variables
78 var highlights = [];
79
80 // add hook to determine if pie plugin in enabled, and then perform necessary operations
81 plot.hooks.processOptions.push(checkPieEnabled);
82 plot.hooks.bindEvents.push(bindEvents);
83
84 // check to see if the pie plugin is enabled
85 function checkPieEnabled(plot, options)
86 {
87 if (options.series.pie.show)
88 {
89 //disable grid
90 options.grid.show = false;
91
92 // set labels.show
93 if (options.series.pie.label.show=='auto')
94 if (options.legend.show)
95 options.series.pie.label.show = false;
96 else
97 options.series.pie.label.show = true;
98
99 // set radius
100 if (options.series.pie.radius=='auto')
101 if (options.series.pie.label.show)
102 options.series.pie.radius = 3/4;
103 else
104 options.series.pie.radius = 1;
105
106 // ensure sane tilt
107 if (options.series.pie.tilt>1)
108 options.series.pie.tilt=1;
109 if (options.series.pie.tilt<0)
110 options.series.pie.tilt=0;
111
112 // add processData hook to do transformations on the data
113 plot.hooks.processDatapoints.push(processDatapoints);
114 plot.hooks.drawOverlay.push(drawOverlay);
115
116 // add draw hook
117 plot.hooks.draw.push(draw);
118 }
119 }
120
121 // bind hoverable events
122 function bindEvents(plot, eventHolder)
123 {
124 var options = plot.getOptions();
125
126 if (options.series.pie.show && options.grid.hoverable)
127 eventHolder.unbind('mousemove').mousemove(onMouseMove);
128
129 if (options.series.pie.show && options.grid.clickable)
130 eventHolder.unbind('click').click(onClick);
131 }
132
133
134 // debugging function that prints out an object
135 function alertObject(obj)
136 {
137 var msg = '';
138 function traverse(obj, depth)
139 {
140 if (!depth)
141 depth = 0;
142 for (var i = 0; i < obj.length; ++i)
143 {
144 for (var j=0; j<depth; j++)
145 msg += '\t';
146
147 if( typeof obj[i] == "object")
148 { // its an object
149 msg += ''+i+':\n';
150 traverse(obj[i], depth+1);
151 }
152 else
153 { // its a value
154 msg += ''+i+': '+obj[i]+'\n';
155 }
156 }
157 }
158 traverse(obj);
159 alert(msg);
160 }
161
162 function calcTotal(data)
163 {
164 for (var i = 0; i < data.length; ++i)
165 {
166 var item = parseFloat(data[i].data[0][1]);
167 if (item)
168 total += item;
169 }
170 }
171
172 function processDatapoints(plot, series, data, datapoints)
173 {
174 if (!processed)
175 {
176 processed = true;
177
178 canvas = plot.getCanvas();
179 target = $(canvas).parent();
180 options = plot.getOptions();
181
182 plot.setData(combine(plot.getData()));
183 }
184 }
185
186 function setupPie()
187 {
188 legendWidth = target.children().filter('.legend').children().width();
189
190 // calculate maximum radius and center point
191 maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
192 centerTop = (canvas.height/2)+options.series.pie.offset.top;
193 centerLeft = (canvas.width/2);
194
195 if (options.series.pie.offset.left=='auto')
196 if (options.legend.position.match('w'))
197 centerLeft += legendWidth/2;
198 else
199 centerLeft -= legendWidth/2;
200 else
201 centerLeft += options.series.pie.offset.left;
202
203 if (centerLeft<maxRadius)
204 centerLeft = maxRadius;
205 else if (centerLeft>canvas.width-maxRadius)
206 centerLeft = canvas.width-maxRadius;
207 }
208
209 function fixData(data)
210 {
211 for (var i = 0; i < data.length; ++i)
212 {
213 if (typeof(data[i].data)=='number')
214 data[i].data = [[1,data[i].data]];
215 else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
216 {
217 if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
218 data[i].label = data[i].data.label; // fix weirdness coming from flot
219 data[i].data = [[1,0]];
220
221 }
222 }
223 return data;
224 }
225
226 function combine(data)
227 {
228 data = fixData(data);
229 calcTotal(data);
230 var combined = 0;
231 var numCombined = 0;
232 var color = options.series.pie.combine.color;
233
234 var newdata = [];
235 for (var i = 0; i < data.length; ++i)
236 {
237 // make sure its a number
238 data[i].data[0][1] = parseFloat(data[i].data[0][1]);
239 if (!data[i].data[0][1])
240 data[i].data[0][1] = 0;
241
242 if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
243 {
244 combined += data[i].data[0][1];
245 numCombined++;
246 if (!color)
247 color = data[i].color;
248 }
249 else
250 {
251 newdata.push({
252 data: [[1,data[i].data[0][1]]],
253 color: data[i].color,
254 label: data[i].label,
255 angle: (data[i].data[0][1]*(Math.PI*2))/total,
256 percent: (data[i].data[0][1]/total*100)
257 });
258 }
259 }
260 if (numCombined>0)
261 newdata.push({
262 data: [[1,combined]],
263 color: color,
264 label: options.series.pie.combine.label,
265 angle: (combined*(Math.PI*2))/total,
266 percent: (combined/total*100)
267 });
268 return newdata;
269 }
270
271 function draw(plot, newCtx)
272 {
273 if (!target) return; // if no series were passed
274 ctx = newCtx;
275
276 setupPie();
277 var slices = plot.getData();
278
279 var attempts = 0;
280 while (redraw && attempts<redrawAttempts)
281 {
282 redraw = false;
283 if (attempts>0)
284 maxRadius *= shrink;
285 attempts += 1;
286 clear();
287 if (options.series.pie.tilt<=0.8)
288 drawShadow();
289 drawPie();
290 }
291 if (attempts >= redrawAttempts) {
292 clear();
293 target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
294 }
295
296 if ( plot.setSeries && plot.insertLegend )
297 {
298 plot.setSeries(slices);
299 plot.insertLegend();
300 }
301
302 // we're actually done at this point, just defining internal functions at this point
303
304 function clear()
305 {
306 ctx.clearRect(0,0,canvas.width,canvas.height);
307 target.children().filter('.pieLabel, .pieLabelBackground').remove();
308 }
309
310 function drawShadow()
311 {
312 var shadowLeft = 5;
313 var shadowTop = 15;
314 var edge = 10;
315 var alpha = 0.02;
316
317 // set radius
318 if (options.series.pie.radius>1)
319 var radius = options.series.pie.radius;
320 else
321 var radius = maxRadius * options.series.pie.radius;
322
323 if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
324 return; // shadow would be outside canvas, so don't draw it
325
326 ctx.save();
327 ctx.translate(shadowLeft,shadowTop);
328 ctx.globalAlpha = alpha;
329 ctx.fillStyle = '#000';
330
331 // center and rotate to starting position
332 ctx.translate(centerLeft,centerTop);
333 ctx.scale(1, options.series.pie.tilt);
334
335 //radius -= edge;
336 for (var i=1; i<=edge; i++)
337 {
338 ctx.beginPath();
339 ctx.arc(0,0,radius,0,Math.PI*2,false);
340 ctx.fill();
341 radius -= i;
342 }
343
344 ctx.restore();
345 }
346
347 function drawPie()
348 {
349 startAngle = Math.PI*options.series.pie.startAngle;
350
351 // set radius
352 if (options.series.pie.radius>1)
353 var radius = options.series.pie.radius;
354 else
355 var radius = maxRadius * options.series.pie.radius;
356
357 // center and rotate to starting position
358 ctx.save();
359 ctx.translate(centerLeft,centerTop);
360 ctx.scale(1, options.series.pie.tilt);
361 //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
362
363 // draw slices
364 ctx.save();
365 var currentAngle = startAngle;
366 for (var i = 0; i < slices.length; ++i)
367 {
368 slices[i].startAngle = currentAngle;
369 drawSlice(slices[i].angle, slices[i].color, true);
370 }
371 ctx.restore();
372
373 // draw slice outlines
374 ctx.save();
375 ctx.lineWidth = options.series.pie.stroke.width;
376 currentAngle = startAngle;
377 for (var i = 0; i < slices.length; ++i)
378 drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
379 ctx.restore();
380
381 // draw donut hole
382 drawDonutHole(ctx);
383
384 // draw labels
385 if (options.series.pie.label.show)
386 drawLabels();
387
388 // restore to original state
389 ctx.restore();
390
391 function drawSlice(angle, color, fill)
392 {
393 if (angle<=0)
394 return;
395
396 if (fill)
397 ctx.fillStyle = color;
398 else
399 {
400 ctx.strokeStyle = color;
401 ctx.lineJoin = 'round';
402 }
403
404 ctx.beginPath();
405 if (Math.abs(angle - Math.PI*2) > 0.000000001)
406 ctx.moveTo(0,0); // Center of the pie
407 else if ($.browser.msie)
408 angle -= 0.0001;
409 //ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
410 ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
411 ctx.closePath();
412 //ctx.rotate(angle); // This doesn't work properly in Opera
413 currentAngle += angle;
414
415 if (fill)
416 ctx.fill();
417 else
418 ctx.stroke();
419 }
420
421 function drawLabels()
422 {
423 var currentAngle = startAngle;
424
425 // set radius
426 if (options.series.pie.label.radius>1)
427 var radius = options.series.pie.label.radius;
428 else
429 var radius = maxRadius * options.series.pie.label.radius;
430
431 for (var i = 0; i < slices.length; ++i)
432 {
433 if (slices[i].percent >= options.series.pie.label.threshold*100)
434 drawLabel(slices[i], currentAngle, i);
435 currentAngle += slices[i].angle;
436 }
437
438 function drawLabel(slice, startAngle, index)
439 {
440 if (slice.data[0][1]==0)
441 return;
442
443 // format label text
444 var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
445 if (lf)
446 text = lf(slice.label, slice);
447 else
448 text = slice.label;
449 if (plf)
450 text = plf(text, slice);
451
452 var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
453 var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
454 var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
455
456 var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
457 target.append(html);
458 var label = target.children('#pieLabel'+index);
459 var labelTop = (y - label.height()/2);
460 var labelLeft = (x - label.width()/2);
461 label.css('top', labelTop);
462 label.css('left', labelLeft);
463
464 // check to make sure that the label is not outside the canvas
465 if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
466 redraw = true;
467
468 if (options.series.pie.label.background.opacity != 0) {
469 // put in the transparent background separately to avoid blended labels and label boxes
470 var c = options.series.pie.label.background.color;
471 if (c == null) {
472 c = slice.color;
473 }
474 var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
475 $('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
476 }
477 } // end individual label function
478 } // end drawLabels function
479 } // end drawPie function
480 } // end draw function
481
482 // Placed here because it needs to be accessed from multiple locations
483 function drawDonutHole(layer)
484 {
485 // draw donut hole
486 if(options.series.pie.innerRadius > 0)
487 {
488 // subtract the center
489 layer.save();
490 innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
491 layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
492 layer.beginPath();
493 layer.fillStyle = options.series.pie.stroke.color;
494 layer.arc(0,0,innerRadius,0,Math.PI*2,false);
495 layer.fill();
496 layer.closePath();
497 layer.restore();
498
499 // add inner stroke
500 layer.save();
501 layer.beginPath();
502 layer.strokeStyle = options.series.pie.stroke.color;
503 layer.arc(0,0,innerRadius,0,Math.PI*2,false);
504 layer.stroke();
505 layer.closePath();
506 layer.restore();
507 // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
508 }
509 }
510
511 //-- Additional Interactive related functions --
512
513 function isPointInPoly(poly, pt)
514 {
515 for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
516 ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
517 && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
518 && (c = !c);
519 return c;
520 }
521
522 function findNearbySlice(mouseX, mouseY)
523 {
524 var slices = plot.getData(),
525 options = plot.getOptions(),
526 radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
527
528 for (var i = 0; i < slices.length; ++i)
529 {
530 var s = slices[i];
531
532 if(s.pie.show)
533 {
534 ctx.save();
535 ctx.beginPath();
536 ctx.moveTo(0,0); // Center of the pie
537 //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
538 ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
539 ctx.closePath();
540 x = mouseX-centerLeft;
541 y = mouseY-centerTop;
542 if(ctx.isPointInPath)
543 {
544 if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
545 {
546 //alert('found slice!');
547 ctx.restore();
548 return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
549 }
550 }
551 else
552 {
553 // excanvas for IE doesn;t support isPointInPath, this is a workaround.
554 p1X = (radius * Math.cos(s.startAngle));
555 p1Y = (radius * Math.sin(s.startAngle));
556 p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
557 p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
558 p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
559 p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
560 p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
561 p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
562 p5X = (radius * Math.cos(s.startAngle+s.angle));
563 p5Y = (radius * Math.sin(s.startAngle+s.angle));
564 arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
565 arrPoint = [x,y];
566 // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
567 if(isPointInPoly(arrPoly, arrPoint))
568 {
569 ctx.restore();
570 return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
571 }
572 }
573 ctx.restore();
574 }
575 }
576
577 return null;
578 }
579
580 function onMouseMove(e)
581 {
582 triggerClickHoverEvent('plothover', e);
583 }
584
585 function onClick(e)
586 {
587 triggerClickHoverEvent('plotclick', e);
588 }
589
590 // trigger click or hover event (they send the same parameters so we share their code)
591 function triggerClickHoverEvent(eventname, e)
592 {
593 var offset = plot.offset(),
594 canvasX = parseInt(e.pageX - offset.left),
595 canvasY = parseInt(e.pageY - offset.top),
596 item = findNearbySlice(canvasX, canvasY);
597
598 if (options.grid.autoHighlight)
599 {
600 // clear auto-highlights
601 for (var i = 0; i < highlights.length; ++i)
602 {
603 var h = highlights[i];
604 if (h.auto == eventname && !(item && h.series == item.series))
605 unhighlight(h.series);
606 }
607 }
608
609 // highlight the slice
610 if (item)
611 highlight(item.series, eventname);
612
613 // trigger any hover bind events
614 var pos = { pageX: e.pageX, pageY: e.pageY };
615 target.trigger(eventname, [ pos, item ]);
616 }
617
618 function highlight(s, auto)
619 {
620 if (typeof s == "number")
621 s = series[s];
622
623 var i = indexOfHighlight(s);
624 if (i == -1)
625 {
626 highlights.push({ series: s, auto: auto });
627 plot.triggerRedrawOverlay();
628 }
629 else if (!auto)
630 highlights[i].auto = false;
631 }
632
633 function unhighlight(s)
634 {
635 if (s == null)
636 {
637 highlights = [];
638 plot.triggerRedrawOverlay();
639 }
640
641 if (typeof s == "number")
642 s = series[s];
643
644 var i = indexOfHighlight(s);
645 if (i != -1)
646 {
647 highlights.splice(i, 1);
648 plot.triggerRedrawOverlay();
649 }
650 }
651
652 function indexOfHighlight(s)
653 {
654 for (var i = 0; i < highlights.length; ++i)
655 {
656 var h = highlights[i];
657 if (h.series == s)
658 return i;
659 }
660 return -1;
661 }
662
663 function drawOverlay(plot, octx)
664 {
665 //alert(options.series.pie.radius);
666 var options = plot.getOptions();
667 //alert(options.series.pie.radius);
668
669 var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
670
671 octx.save();
672 octx.translate(centerLeft, centerTop);
673 octx.scale(1, options.series.pie.tilt);
674
675 for (i = 0; i < highlights.length; ++i)
676 drawHighlight(highlights[i].series);
677
678 drawDonutHole(octx);
679
680 octx.restore();
681
682 function drawHighlight(series)
683 {
684 if (series.angle < 0) return;
685
686 //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
687 octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
688
689 octx.beginPath();
690 if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
691 octx.moveTo(0,0); // Center of the pie
692 octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
693 octx.closePath();
694 octx.fill();
695 }
696
697 }
698
699 } // end init (plugin body)
700
701 // define pie specific options and their default values
702 var options = {
703 series: {
704 pie: {
705 show: false,
706 radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
707 innerRadius:0, /* for donut */
708 startAngle: 3/2,
709 tilt: 1,
710 offset: {
711 top: 0,
712 left: 'auto'
713 },
714 stroke: {
715 color: '#FFF',
716 width: 1
717 },
718 label: {
719 show: 'auto',
720 formatter: function(label, slice){
721 return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
722 }, // formatter function
723 radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
724 background: {
725 color: null,
726 opacity: 0
727 },
728 threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
729 },
730 combine: {
731 threshold: -1, // percentage at which to combine little slices into one larger slice
732 color: null, // color to give the new slice (auto-generated if null)
733 label: 'Other' // label to give the new slice
734 },
735 highlight: {
736 //color: '#FFF', // will add this functionality once parseColor is available
737 opacity: 0.5
738 }
739 }
740 }
741 };
742
743 $.plot.plugins.push({
744 init: init,
745 options: options,
746 name: "pie",
747 version: "1.0"
748 });
749 })(jQuery);
0 /*
1 Flot plugin for automatically redrawing plots when the placeholder
2 size changes, e.g. on window resizes.
3
4 It works by listening for changes on the placeholder div (through the
5 jQuery resize event plugin) - if the size changes, it will redraw the
6 plot.
7
8 There are no options. If you need to disable the plugin for some
9 plots, you can just fix the size of their placeholders.
10 */
11
12
13 /* Inline dependency:
14 * jQuery resize event - v1.1 - 3/14/2010
15 * http://benalman.com/projects/jquery-resize-plugin/
16 *
17 * Copyright (c) 2010 "Cowboy" Ben Alman
18 * Dual licensed under the MIT and GPL licenses.
19 * http://benalman.com/about/license/
20 */
21 (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);
22
23
24 (function ($) {
25 var options = { }; // no options
26
27 function init(plot) {
28 function onResize() {
29 var placeholder = plot.getPlaceholder();
30
31 // somebody might have hidden us and we can't plot
32 // when we don't have the dimensions
33 if (placeholder.width() == 0 || placeholder.height() == 0)
34 return;
35
36 plot.resize();
37 plot.setupGrid();
38 plot.draw();
39 }
40
41 function bindEvents(plot, eventHolder) {
42 plot.getPlaceholder().resize(onResize);
43 }
44
45 function shutdown(plot, eventHolder) {
46 plot.getPlaceholder().unbind("resize", onResize);
47 }
48
49 plot.hooks.bindEvents.push(bindEvents);
50 plot.hooks.shutdown.push(shutdown);
51 }
52
53 $.plot.plugins.push({
54 init: init,
55 options: options,
56 name: 'resize',
57 version: '1.0'
58 });
59 })(jQuery);
77 color: color
88 }
99
10 You enable selection support by setting the mode to one of "x", "y" or
10 Selection support is enabled by setting the mode to one of "x", "y" or
1111 "xy". In "x" mode, the user will only be able to specify the x range,
1212 similarly for "y" mode. For "xy", the selection becomes a rectangle
13 where both ranges can be specified. "color" is color of the selection.
14
15 When selection support is enabled, a "plotselected" event will be emitted
16 on the DOM element you passed into the plot function. The event
17 handler gets one extra parameter with the ranges selected on the axes,
13 where both ranges can be specified. "color" is color of the selection
14 (if you need to change the color later on, you can get to it with
15 plot.getOptions().selection.color).
16
17 When selection support is enabled, a "plotselected" event will be
18 emitted on the DOM element you passed into the plot function. The
19 event handler gets a parameter with the ranges selected on the axes,
1820 like this:
1921
2022 placeholder.bind("plotselected", function(event, ranges) {
2123 alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
22 // similar for yaxis, secondary axes are in x2axis
23 // and y2axis if present
24 // similar for yaxis - with multiple axes, the extra ones are in
25 // x2axis, x3axis, ...
2426 });
2527
2628 The "plotselected" event is only fired when the user has finished
3638 - setSelection(ranges, preventEvent)
3739
3840 Set the selection rectangle. The passed in ranges is on the same
39 form as returned in the "plotselected" event. If the selection
40 mode is "x", you should put in either an xaxis (or x2axis) object,
41 if the mode is "y" you need to put in an yaxis (or y2axis) object
42 and both xaxis/x2axis and yaxis/y2axis if the selection mode is
43 "xy", like this:
41 form as returned in the "plotselected" event. If the selection mode
42 is "x", you should put in either an xaxis range, if the mode is "y"
43 you need to put in an yaxis range and both xaxis and yaxis if the
44 selection mode is "xy", like this:
4445
4546 setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
4647
4748 setSelection will trigger the "plotselected" event when called. If
4849 you don't want that to happen, e.g. if you're inside a
49 "plotselected" handler, pass true as the second parameter.
50 "plotselected" handler, pass true as the second parameter. If you
51 are using multiple axes, you can specify the ranges on any of those,
52 e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
53 first one it sees.
5054
5155 - clearSelection(preventEvent)
5256
7680 // make this plugin much slimmer.
7781 var savedhandlers = {};
7882
83 var mouseUpHandler = null;
84
7985 function onMouseMove(e) {
8086 if (selection.active) {
87 updateSelection(e);
88
8189 plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
82
83 updateSelection(e);
8490 }
8591 }
8692
104110 setSelectionPos(selection.first, e);
105111
106112 selection.active = true;
107
108 $(document).one("mouseup", onMouseUp);
113
114 // this is a bit silly, but we have to use a closure to be
115 // able to whack the same handler again
116 mouseUpHandler = function (e) { onMouseUp(e); };
117
118 $(document).one("mouseup", mouseUpHandler);
109119 }
110120
111121 function onMouseUp(e) {
122 mouseUpHandler = null;
123
112124 // revert drag stuff for old-school browsers
113125 if (document.onselectstart !== undefined)
114126 document.onselectstart = savedhandlers.onselectstart;
115127 if (document.ondrag !== undefined)
116128 document.ondrag = savedhandlers.ondrag;
117129
118 // no more draggy-dee-drag
130 // no more dragging
119131 selection.active = false;
120132 updateSelection(e);
121133
134146 if (!selectionIsSane())
135147 return null;
136148
137 var x1 = Math.min(selection.first.x, selection.second.x),
138 x2 = Math.max(selection.first.x, selection.second.x),
139 y1 = Math.max(selection.first.y, selection.second.y),
140 y2 = Math.min(selection.first.y, selection.second.y);
141
142 var r = {};
143 var axes = plot.getAxes();
144 if (axes.xaxis.used)
145 r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
146 if (axes.x2axis.used)
147 r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
148 if (axes.yaxis.used)
149 r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
150 if (axes.y2axis.used)
151 r.y2axis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
149 var r = {}, c1 = selection.first, c2 = selection.second;
150 $.each(plot.getAxes(), function (name, axis) {
151 if (axis.used) {
152 var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
153 r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
154 }
155 });
152156 return r;
153157 }
154158
158162 plot.getPlaceholder().trigger("plotselected", [ r ]);
159163
160164 // backwards-compat stuff, to be removed in future
161 var axes = plot.getAxes();
162 if (axes.xaxis.used && axes.yaxis.used)
165 if (r.xaxis && r.yaxis)
163166 plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
164167 }
165168
166169 function clamp(min, value, max) {
167 return value < min? min: (value > max? max: value);
170 return value < min ? min: (value > max ? max: value);
168171 }
169172
170173 function setSelectionPos(pos, e) {
175178 pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
176179
177180 if (o.selection.mode == "y")
178 pos.x = pos == selection.first? 0: plot.width();
181 pos.x = pos == selection.first ? 0 : plot.width();
179182
180183 if (o.selection.mode == "x")
181 pos.y = pos == selection.first? 0: plot.height();
184 pos.y = pos == selection.first ? 0 : plot.height();
182185 }
183186
184187 function updateSelection(pos) {
203206 }
204207 }
205208
209 // function taken from markings support in Flot
210 function extractRange(ranges, coord) {
211 var axis, from, to, key, axes = plot.getAxes();
212
213 for (var k in axes) {
214 axis = axes[k];
215 if (axis.direction == coord) {
216 key = coord + axis.n + "axis";
217 if (!ranges[key] && axis.n == 1)
218 key = coord + "axis"; // support x1axis as xaxis
219 if (ranges[key]) {
220 from = ranges[key].from;
221 to = ranges[key].to;
222 break;
223 }
224 }
225 }
226
227 // backwards-compat stuff - to be removed in future
228 if (!ranges[key]) {
229 axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
230 from = ranges[coord + "1"];
231 to = ranges[coord + "2"];
232 }
233
234 // auto-reverse as an added bonus
235 if (from != null && to != null && from > to) {
236 var tmp = from;
237 from = to;
238 to = tmp;
239 }
240
241 return { from: from, to: to, axis: axis };
242 }
243
206244 function setSelection(ranges, preventEvent) {
207 var axis, range, axes = plot.getAxes();
208 var o = plot.getOptions();
245 var axis, range, o = plot.getOptions();
209246
210247 if (o.selection.mode == "y") {
211248 selection.first.x = 0;
212249 selection.second.x = plot.width();
213250 }
214251 else {
215 axis = ranges["xaxis"]? axes["xaxis"]: (ranges["x2axis"]? axes["x2axis"]: axes["xaxis"]);
216 range = ranges["xaxis"] || ranges["x2axis"] || { from:ranges["x1"], to:ranges["x2"] }
217 selection.first.x = axis.p2c(Math.min(range.from, range.to));
218 selection.second.x = axis.p2c(Math.max(range.from, range.to));
252 range = extractRange(ranges, "x");
253
254 selection.first.x = range.axis.p2c(range.from);
255 selection.second.x = range.axis.p2c(range.to);
219256 }
220257
221258 if (o.selection.mode == "x") {
223260 selection.second.y = plot.height();
224261 }
225262 else {
226 axis = ranges["yaxis"]? axes["yaxis"]: (ranges["y2axis"]? axes["y2axis"]: axes["yaxis"]);
227 range = ranges["yaxis"] || ranges["y2axis"] || { from:ranges["y1"], to:ranges["y2"] }
228 selection.first.y = axis.p2c(Math.min(range.from, range.to));
229 selection.second.y = axis.p2c(Math.max(range.from, range.to));
263 range = extractRange(ranges, "y");
264
265 selection.first.y = range.axis.p2c(range.from);
266 selection.second.y = range.axis.p2c(range.to);
230267 }
231268
232269 selection.show = true;
233270 plot.triggerRedrawOverlay();
234 if (!preventEvent)
271 if (!preventEvent && selectionIsSane())
235272 triggerSelectedEvent();
236273 }
237274
247284
248285 plot.hooks.bindEvents.push(function(plot, eventHolder) {
249286 var o = plot.getOptions();
250 if (o.selection.mode != null)
287 if (o.selection.mode != null) {
251288 eventHolder.mousemove(onMouseMove);
252
253 if (o.selection.mode != null)
254289 eventHolder.mousedown(onMouseDown);
290 }
255291 });
256292
257293
282318 ctx.restore();
283319 }
284320 });
321
322 plot.hooks.shutdown.push(function (plot, eventHolder) {
323 eventHolder.unbind("mousemove", onMouseMove);
324 eventHolder.unbind("mousedown", onMouseDown);
325
326 if (mouseUpHandler)
327 $(document).unbind("mouseup", mouseUpHandler);
328 });
329
285330 }
286331
287332 $.plot.plugins.push({
293338 }
294339 },
295340 name: 'selection',
296 version: '1.0'
341 version: '1.1'
297342 });
298343 })(jQuery);
00 /*
11 Flot plugin for stacking data sets, i.e. putting them on top of each
2 other, for accumulative graphs. Note that the plugin assumes the data
3 is sorted on x. Also note that stacking a mix of positive and negative
4 values in most instances doesn't make sense (so it looks weird).
2 other, for accumulative graphs.
3
4 The plugin assumes the data is sorted on x (or y if stacking
5 horizontally). For line charts, it is assumed that if a line has an
6 undefined gap (from a null point), then the line above it should have
7 the same gap - insert zeros instead of "null" if you want another
8 behaviour. This also holds for the start and end of the chart. Note
9 that stacking a mix of positive and negative values in most instances
10 doesn't make sense (so it looks weird).
511
612 Two or more series are stacked when their "stack" attribute is set to
713 the same key (which can be any number or string or just "true"). To
1319
1420 or specify it for a specific series
1521
16 $.plot($("#placeholder"), [{ data: [ ... ], stack: true ])
22 $.plot($("#placeholder"), [{ data: [ ... ], stack: true }])
1723
1824 The stacking order is determined by the order of the data series in
1925 the array (later series end up on top of the previous).
2026
2127 Internally, the plugin modifies the datapoints in each series, adding
2228 an offset to the y value. For line series, extra data points are
23 inserted through interpolation. For bar charts, the second y value is
24 also adjusted.
29 inserted through interpolation. If there's a second y value, it's also
30 adjusted (e.g for bar charts or filled areas).
2531 */
2632
2733 (function ($) {
5056 var other = findMatchingSeries(s, plot.getData());
5157 if (!other)
5258 return;
53
59
5460 var ps = datapoints.pointsize,
5561 points = datapoints.points,
5662 otherps = other.datapoints.pointsize,
5763 otherpoints = other.datapoints.points,
5864 newpoints = [],
5965 px, py, intery, qx, qy, bottom,
60 withlines = s.lines.show, withbars = s.bars.show,
66 withlines = s.lines.show,
67 horizontal = s.bars.horizontal,
68 withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),
6169 withsteps = withlines && s.lines.steps,
70 fromgap = true,
71 keyOffset = horizontal ? 1 : 0,
72 accumulateOffset = horizontal ? 0 : 1,
6273 i = 0, j = 0, l;
6374
6475 while (true) {
6778
6879 l = newpoints.length;
6980
70 if (j >= otherpoints.length
71 || otherpoints[j] == null
72 || points[i] == null) {
73 // degenerate cases
81 if (points[i] == null) {
82 // copy gaps
7483 for (m = 0; m < ps; ++m)
7584 newpoints.push(points[i + m]);
7685 i += ps;
7786 }
87 else if (j >= otherpoints.length) {
88 // for lines, we can't use the rest of the points
89 if (!withlines) {
90 for (m = 0; m < ps; ++m)
91 newpoints.push(points[i + m]);
92 }
93 i += ps;
94 }
95 else if (otherpoints[j] == null) {
96 // oops, got a gap
97 for (m = 0; m < ps; ++m)
98 newpoints.push(null);
99 fromgap = true;
100 j += otherps;
101 }
78102 else {
79103 // cases where we actually got two points
80 px = points[i];
81 py = points[i + 1];
82 qx = otherpoints[j];
83 qy = otherpoints[j + 1];
104 px = points[i + keyOffset];
105 py = points[i + accumulateOffset];
106 qx = otherpoints[j + keyOffset];
107 qy = otherpoints[j + accumulateOffset];
84108 bottom = 0;
85109
86110 if (px == qx) {
87111 for (m = 0; m < ps; ++m)
88112 newpoints.push(points[i + m]);
89113
90 newpoints[l + 1] += qy;
114 newpoints[l + accumulateOffset] += qy;
91115 bottom = qy;
92116
93117 i += ps;
97121 // we got past point below, might need to
98122 // insert interpolated extra point
99123 if (withlines && i > 0 && points[i - ps] != null) {
100 intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
124 intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);
101125 newpoints.push(qx);
102 newpoints.push(intery + qy)
126 newpoints.push(intery + qy);
103127 for (m = 2; m < ps; ++m)
104128 newpoints.push(points[i + m]);
105129 bottom = qy;
107131
108132 j += otherps;
109133 }
110 else {
134 else { // px < qx
135 if (fromgap && withlines) {
136 // if we come from a gap, we just skip this point
137 i += ps;
138 continue;
139 }
140
111141 for (m = 0; m < ps; ++m)
112142 newpoints.push(points[i + m]);
113143
114144 // we might be able to interpolate a point below,
115145 // this can give us a better y
116 if (withlines && j > 0 && otherpoints[j - ps] != null)
117 bottom = qy + (otherpoints[j - ps + 1] - qy) * (px - qx) / (otherpoints[j - ps] - qx);
146 if (withlines && j > 0 && otherpoints[j - otherps] != null)
147 bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
118148
119 newpoints[l + 1] += bottom;
149 newpoints[l + accumulateOffset] += bottom;
120150
121151 i += ps;
122152 }
153
154 fromgap = false;
123155
124 if (l != newpoints.length && withbars)
156 if (l != newpoints.length && withbottom)
125157 newpoints[l + 2] += bottom;
126158 }
127159
135167 newpoints[l + 1] = newpoints[l - ps + 1];
136168 }
137169 }
138
170
139171 datapoints.points = newpoints;
140172 }
141173
146178 init: init,
147179 options: options,
148180 name: 'stack',
149 version: '1.0'
181 version: '1.2'
150182 });
151183 })(jQuery);
0 /*
1 Flot plugin that adds some extra symbols for plotting points.
2
3 The symbols are accessed as strings through the standard symbol
4 choice:
5
6 series: {
7 points: {
8 symbol: "square" // or "diamond", "triangle", "cross"
9 }
10 }
11
12 */
13
14 (function ($) {
15 function processRawData(plot, series, datapoints) {
16 // we normalize the area of each symbol so it is approximately the
17 // same as a circle of the given radius
18
19 var handlers = {
20 square: function (ctx, x, y, radius, shadow) {
21 // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2
22 var size = radius * Math.sqrt(Math.PI) / 2;
23 ctx.rect(x - size, y - size, size + size, size + size);
24 },
25 diamond: function (ctx, x, y, radius, shadow) {
26 // pi * r^2 = 2s^2 => s = r * sqrt(pi/2)
27 var size = radius * Math.sqrt(Math.PI / 2);
28 ctx.moveTo(x - size, y);
29 ctx.lineTo(x, y - size);
30 ctx.lineTo(x + size, y);
31 ctx.lineTo(x, y + size);
32 ctx.lineTo(x - size, y);
33 },
34 triangle: function (ctx, x, y, radius, shadow) {
35 // pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3))
36 var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3));
37 var height = size * Math.sin(Math.PI / 3);
38 ctx.moveTo(x - size/2, y + height/2);
39 ctx.lineTo(x + size/2, y + height/2);
40 if (!shadow) {
41 ctx.lineTo(x, y - height/2);
42 ctx.lineTo(x - size/2, y + height/2);
43 }
44 },
45 cross: function (ctx, x, y, radius, shadow) {
46 // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2
47 var size = radius * Math.sqrt(Math.PI) / 2;
48 ctx.moveTo(x - size, y - size);
49 ctx.lineTo(x + size, y + size);
50 ctx.moveTo(x - size, y + size);
51 ctx.lineTo(x + size, y - size);
52 }
53 }
54
55 var s = series.points.symbol;
56 if (handlers[s])
57 series.points.symbol = handlers[s];
58 }
59
60 function init(plot) {
61 plot.hooks.processDatapoints.push(processRawData);
62 }
63
64 $.plot.plugins.push({
65 init: init,
66 name: 'symbols',
67 version: '1.0'
68 });
69 })(jQuery);