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

Added colored area support with an example to show it

git-svn-id: https://flot.googlecode.com/svn/trunk@43 1e0a6537-2640-0410-bfb7-f154510ff394
parent c97acff9
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<li><a href="selection.html">Selection support and zooming</a></li> <li><a href="selection.html">Selection support and zooming</a></li>
<li><a href="zooming.html">Zooming with overview</a></li> <li><a href="zooming.html">Zooming with overview</a></li>
<li><a href="time.html">Plotting time series</a></li> <li><a href="time.html">Plotting time series</a></li>
<li><a href="visitors.html">Visitors per day with zooming and weekends</a></li>
<li><a href="interacting.html">Interacting with the data</a></li> <li><a href="interacting.html">Interacting with the data</a></li>
</ul> </ul>
</body> </body>
......
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Flot Examples</title>
<link href="layout.css" rel="stylesheet" type="text/css"></link>
<!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.pack.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../jquery.js"></script>
<script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
</head>
<body>
<h1>Flot Examples</h1>
<div id="placeholder" style="width:600px;height:300px;"></div>
<p>Visitors per day to the Flot homepage. Weekends are colored. Try zooming.
The plot below shows an overview.</p>
<div id="overview" style="margin-left:50px;margin-top:20px;width:400px;height:50px"></div>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], [1196722800000, 77], [1196809200000, 3636], [1196895600000, 3575], [1196982000000, 2736], [1197068400000, 1086], [1197154800000, 676], [1197241200000, 1205], [1197327600000, 906], [1197414000000, 710], [1197500400000, 639], [1197586800000, 540], [1197673200000, 435], [1197759600000, 301], [1197846000000, 575], [1197932400000, 481], [1198018800000, 591], [1198105200000, 608], [1198191600000, 459], [1198278000000, 234], [1198364400000, 1352], [1198450800000, 686], [1198537200000, 279], [1198623600000, 449], [1198710000000, 468], [1198796400000, 392], [1198882800000, 282], [1198969200000, 208], [1199055600000, 229], [1199142000000, 177], [1199228400000, 374], [1199314800000, 436], [1199401200000, 404], [1199487600000, 253], [1199574000000, 218], [1199660400000, 476], [1199746800000, 462], [1199833200000, 448], [1199919600000, 442], [1200006000000, 403], [1200092400000, 204], [1200178800000, 194], [1200265200000, 327], [1200351600000, 374], [1200438000000, 507], [1200524400000, 546], [1200610800000, 482], [1200697200000, 283], [1200783600000, 221], [1200870000000, 483], [1200956400000, 523], [1201042800000, 528], [1201129200000, 483], [1201215600000, 452], [1201302000000, 270], [1201388400000, 222], [1201474800000, 439], [1201561200000, 559], [1201647600000, 521], [1201734000000, 477], [1201820400000, 442], [1201906800000, 252], [1201993200000, 236], [1202079600000, 525], [1202166000000, 477], [1202252400000, 386], [1202338800000, 409], [1202425200000, 408], [1202511600000, 237], [1202598000000, 193], [1202684400000, 357], [1202770800000, 414], [1202857200000, 393], [1202943600000, 353], [1203030000000, 364], [1203116400000, 215], [1203202800000, 214], [1203289200000, 356], [1203375600000, 399], [1203462000000, 334], [1203548400000, 348], [1203634800000, 243], [1203721200000, 126], [1203807600000, 157], [1203894000000, 288]];
// helper for returning the week-ends in a period
function weekendAreas(plotarea) {
var areas = [];
var d = new Date(plotarea.xmin);
// go to the first Saturday
d.setDate(d.getDate() - ((d.getDay() + 1) % 7))
d.setSeconds(0);
d.setMinutes(0);
d.setHours(0);
var i = d.getTime();
do {
// when we don't set y1 and y2 the rectangle
// automatically extends to infinity in those directions
areas.push({ x1: i, x2: i + 2 * 24 * 60 * 60 * 1000 });
i += 7 * 24 * 60 * 60 * 1000;
} while (i < plotarea.xmax);
return areas;
}
var options = {
xaxis: { datatype: "time" },
selection: { mode: "x" },
grid: { coloredAreas: weekendAreas }
};
var plot = $.plot($("#placeholder"), [d], options);
var overview = $.plot($("#overview"), [d], {
lines: { show: true, lineWidth: 1 },
shadowSize: 0,
xaxis: { ticks: [], datatype: "time" },
yaxis: { ticks: [], min: 0, max: 4000 },
selection: { mode: "x" }
});
// now connect the two
var internalSelection = false;
$("#placeholder").bind("selected", function (event, area) {
// do the zooming
plot = $.plot($("#placeholder"), [d],
$.extend(true, {}, options, {
xaxis: { min: area.x1, max: area.x2 }
}));
if (internalSelection)
return; // prevent eternal loop
internalSelection = true;
overview.setSelection(area);
internalSelection = false;
});
$("#overview").bind("selected", function (event, area) {
if (internalSelection)
return;
internalSelection = true;
plot.setSelection(area);
internalSelection = false;
});
});
</script>
</body>
</html>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
backgroundOpacity: 0.85 // set to 0 to avoid background backgroundOpacity: 0.85 // set to 0 to avoid background
}, },
xaxis: { xaxis: {
ticks: null, // either [1, 3] or [[1, "a"], 3] or function that outputs this ticks: null, // either [1, 3] or [[1, "a"], 3] or fn: axis info -> ticks
noTicks: 5, // approximate number of ticks for auto-ticks noTicks: 5, // approximate number of ticks for auto-ticks
tickFormatter: null, // fn: number -> string or format string if datatype is date tickFormatter: null, // fn: number -> string or format string if datatype is date
tickDecimals: null, // no. of decimals, null means auto tickDecimals: null, // no. of decimals, null means auto
...@@ -67,15 +67,19 @@ ...@@ -67,15 +67,19 @@
backgroundColor: null, // null for transparent, else color backgroundColor: null, // null for transparent, else color
tickColor: "#dddddd", // color used for the ticks tickColor: "#dddddd", // color used for the ticks
labelMargin: 3, // in pixels labelMargin: 3, // in pixels
clickable: null clickable: null,
coloredAreas: null, // array of { x1, y1, x2, y2 } or fn: plot area -> areas
coloredAreasColor: "#f4f4f4"
}, },
selection: { selection: {
mode: null, // one of null, "x", "y" or "xy" mode: null, // one of null, "x", "y" or "xy"
color: "#e8cfac" color: "#e8cfac"
}, },
shadowSize: 4, shadowSize: 4,
date: { datatype: {
monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] time: {
monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
}
} }
}; };
var canvas = null, overlay = null; var canvas = null, overlay = null;
...@@ -95,7 +99,7 @@ ...@@ -95,7 +99,7 @@
var vertScale = 0; var vertScale = 0;
// map of app. size of time units in milliseconds // map of app. size of time units in milliseconds
var dateUnitSize = { var timeUnitSize = {
"second": 1000, "second": 1000,
"minute": 60 * 1000, "minute": 60 * 1000,
"hour": 60 * 60 * 1000, "hour": 60 * 60 * 1000,
...@@ -286,23 +290,23 @@ ...@@ -286,23 +290,23 @@
// where it's simply matter of adding a fixed no. of seconds // where it's simply matter of adding a fixed no. of seconds
var genericTimeGenerator = function(axis) { var genericTimeGenerator = function(axis) {
var ticks = []; var ticks = [];
var step = axis.tickSize * dateUnitSize[axis.tickSizeUnit]; var step = axis.tickSize * timeUnitSize[axis.tickSizeUnit];
var d = new Date(axis.min); var d = new Date(axis.min);
d.setMilliseconds(0); d.setMilliseconds(0);
if (axis.tickSizeUnit == "second") if (axis.tickSizeUnit == "second")
d.setSeconds(floorInBase(d.getSeconds(), axis.tickSize)); d.setSeconds(floorInBase(d.getSeconds(), axis.tickSize));
else if (step >= dateUnitSize.minute) else if (step >= timeUnitSize.minute)
d.setSeconds(0); d.setSeconds(0);
if (axis.tickSizeUnit == "minute") if (axis.tickSizeUnit == "minute")
d.setMinutes(floorInBase(d.getMinutes(), axis.tickSize)); d.setMinutes(floorInBase(d.getMinutes(), axis.tickSize));
else if (step >= dateUnitSize.hour) else if (step >= timeUnitSize.hour)
d.setMinutes(0); d.setMinutes(0);
if (axis.tickSizeUnit == "hour") if (axis.tickSizeUnit == "hour")
d.setHours(floorInBase(d.getHours(), axis.tickSize)); d.setHours(floorInBase(d.getHours(), axis.tickSize));
else if (step >= dateUnitSize.day) else if (step >= timeUnitSize.day)
d.setHours(0); d.setHours(0);
do { do {
...@@ -328,16 +332,23 @@ ...@@ -328,16 +332,23 @@
d.setHours(0); d.setHours(0);
d.setDate(1); d.setDate(1);
d.setMonth(floorInBase(d.getMonth(), axis.tickSize)); d.setMonth(floorInBase(d.getMonth(), axis.tickSize));
var carry = 0;
do { do {
var v = d.getTime(); var v = d.getTime();
ticks.push({ v: v, label: axis.tickFormatter(v, axis) }); ticks.push({ v: v, label: axis.tickFormatter(v, axis) });
//console.log(d, "month", axis.tickSize) //console.log(d, "month", axis.tickSize)
if (axis.tickSize < 1) { if (axis.tickSize < 1) {
// a bit complicated - we'll divide the month
// up but we need to take care
// of fractions so we don't end up in the
// middle of a day
d.setDate(1); d.setDate(1);
var start = d.getTime(); var start = d.getTime();
d.setMonth(d.getMonth() + 1); d.setMonth(d.getMonth() + 1);
var end = d.getTime(); var end = d.getTime();
d.setTime(v + (end - start) * axis.tickSize); d.setTime(v + carry * timeUnitSize.hour + (end - start) * axis.tickSize);
carry = d.getHours();
d.setHours(0);
} }
else else
d.setMonth(d.getMonth() + axis.tickSize); d.setMonth(d.getMonth() + axis.tickSize);
...@@ -366,8 +377,8 @@ ...@@ -366,8 +377,8 @@
} }
for (i = 0; i < spec.length - 1; ++i) for (i = 0; i < spec.length - 1; ++i)
if (delta < (spec[i][0] * dateUnitSize[spec[i][1]] if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]
+ spec[i + 1][0] * dateUnitSize[spec[i + 1][1]]) / 2) + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2)
break; break;
size = spec[i][0]; size = spec[i][0];
unit = spec[i][1]; unit = spec[i][1];
...@@ -375,8 +386,8 @@ ...@@ -375,8 +386,8 @@
// special-case the possibility of several years // special-case the possibility of several years
if (unit == "year") { if (unit == "year") {
var magn = Math.pow(10, Math.floor(Math.log(delta / dateUnitSize.year) / Math.LN10)); var magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));
var norm = (delta / dateUnitSize.year) / magn; var norm = (delta / timeUnitSize.year) / magn;
if (norm < 1.5) if (norm < 1.5)
size = 1; size = 1;
else if (norm < 3) else if (norm < 3)
...@@ -396,21 +407,21 @@ ...@@ -396,21 +407,21 @@
else else
formatter = function (v, axis) { formatter = function (v, axis) {
var d = new Date(v); var d = new Date(v);
var t = axis.tickSize * dateUnitSize[axis.tickSizeUnit]; var t = axis.tickSize * timeUnitSize[axis.tickSizeUnit];
var span = axis.max - axis.min; var span = axis.max - axis.min;
if (t < dateUnitSize.minute) if (t < timeUnitSize.minute)
fmt = "%h:%M:%S"; fmt = "%h:%M:%S";
else if (t < dateUnitSize.day) { else if (t < timeUnitSize.day) {
if (span < 2 * dateUnitSize.day) if (span < 2 * timeUnitSize.day)
fmt = "%h:%M"; fmt = "%h:%M";
else else
fmt = "%b %d %h:%M"; fmt = "%b %d %h:%M";
} }
else if (t < dateUnitSize.month) else if (t < timeUnitSize.month)
fmt = "%b %d"; fmt = "%b %d";
else if (t < dateUnitSize.year) { else if (t < timeUnitSize.year) {
if (span < dateUnitSize.year) if (span < timeUnitSize.year)
fmt = "%b"; fmt = "%b";
else else
fmt = "%b %y"; fmt = "%b %y";
...@@ -579,6 +590,8 @@ ...@@ -579,6 +590,8 @@
} }
function drawGrid() { function drawGrid() {
var i;
ctx.save(); ctx.save();
ctx.translate(plotOffset.left, plotOffset.top); ctx.translate(plotOffset.left, plotOffset.top);
...@@ -587,12 +600,52 @@ ...@@ -587,12 +600,52 @@
ctx.fillStyle = options.grid.backgroundColor; ctx.fillStyle = options.grid.backgroundColor;
ctx.fillRect(0, 0, plotWidth, plotHeight); ctx.fillRect(0, 0, plotWidth, plotHeight);
} }
// draw colored areas
if (options.grid.coloredAreas) {
var areas = options.grid.coloredAreas;
if ($.isFunction(areas))
areas = areas({ xmin: xaxis.min, xmax: xaxis.max, ymin: yaxis.min, ymax: yaxis.max });
ctx.fillStyle = options.grid.coloredAreasColor;
for (i = 0; i < areas.length; ++i) {
var a = areas[i];
// clip
if (a.x1 == null || a.x1 < xaxis.min)
a.x1 = xaxis.min;
if (a.x2 == null || a.x2 > xaxis.max)
a.x2 = xaxis.max;
if (a.y1 == null || a.y1 < yaxis.min)
a.y1 = yaxis.min;
if (a.y2 == null || a.y2 > yaxis.max)
a.y2 = yaxis.max;
var tmp;
if (a.x1 > a.x2) {
tmp = a.x1;
a.x1 = a.x2;
a.x2 = tmp;
}
if (a.y1 > a.y2) {
tmp = a.y1;
a.y1 = a.y2;
a.y2 = tmp;
}
if (a.x1 >= xaxis.max || a.x2 <= xaxis.min || a.x1 == a.x2
|| a.y1 >= yaxis.max || a.y2 <= yaxis.min || a.y1 == a.y2)
continue;
ctx.fillRect(Math.floor(tHoz(a.x1)), Math.floor(tVert(a.y2)),
Math.floor(tHoz(a.x2) - tHoz(a.x1)), Math.floor(tVert(a.y1) - tVert(a.y2)));
}
}
// draw the inner grid // draw the inner grid
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.strokeStyle = options.grid.tickColor; ctx.strokeStyle = options.grid.tickColor;
ctx.beginPath(); ctx.beginPath();
var i, v; var v;
for (i = 0; i < xaxis.ticks.length; ++i) { for (i = 0; i < xaxis.ticks.length; ++i) {
v = xaxis.ticks[i].v; v = xaxis.ticks[i].v;
if (v <= xaxis.min || v >= xaxis.max) if (v <= xaxis.min || v >= xaxis.max)
...@@ -1403,7 +1456,7 @@ ...@@ -1403,7 +1456,7 @@
case 'd': c = "" + d.getDate(); break; case 'd': c = "" + d.getDate(); break;
case 'm': c = "" + (d.getMonth() + 1); break; case 'm': c = "" + (d.getMonth() + 1); break;
case 'y': c = "" + d.getFullYear(); break; case 'y': c = "" + d.getFullYear(); break;
case 'b': c = "" + options.date.monthNames[d.getMonth()]; break; case 'b': c = "" + options.datatype.time.monthNames[d.getMonth()]; break;
default: c; default: c;
} }
r.push(c); r.push(c);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment