Commit ea4bfb11 authored by David Schnur's avatar David Schnur

Merge pull request #1178 from Jeff-Tian/0.9-work

Enrich Flot with the ability to add text into markings.
parents a8aac7a1 b100f441
...@@ -948,6 +948,50 @@ markings: function (axes) { ...@@ -948,6 +948,50 @@ markings: function (axes) {
} }
``` ```
By default, the markings will be drawn under the grid ticks, if you
need to draw a marking above the grid ticks, you can specifiy a
"aboveGrid" attribute and set it to true, e.g.
```js
markings: [ { xaxis: { from: 1, to: 2 }, yaxis: { from: 1, to: 2 }, aboveGrid: true }, ... ]
```
Usually a marking is a regular rectangle, when you want it to have a rounded
corner, you can specify a "rounded" value to it, e.g.
```js
markings: [ { xaxis: { from: 1, to: 2 }, yaxis: { from: 1, to: 2 }, aboveGrid: true, rounded: 3 }, ... ]
```
In case you want to put some texts attaching to markings, you can specifiy
an "text" object to the marking object, along with a font object as well as
other 2 attributes (textAlign and textBaseline) to align texts well in the
marking if you want to give the texts a customized look, e.g.
```js
markings: [
{
xaxis: { from: 1, to: 2 },
yaxis: { from: 1, to: 2 },
aboveGrid: true,
color: "#000",
rounded: 3,
text: "<strong style='margin: 0 0 0 1px;'>The 1st line.</strong><br />The 2nd line.",
textAlign: "center",
textBaseline: "middle",
font: {
color: "#fff",
size: "12"
}
},
...
]
```
As you see from the above code example, you can control the look and feel
of the texts by inline css style, besides this approach, you can also
customize the look and feel of these texts by defining css rules to the
class *flot-marking*, which class the texts has.
If you set "clickable" to true, the plot will listen for click events If you set "clickable" to true, the plot will listen for click events
on the plot area and fire a "plotclick" event on the placeholder with on the plot area and fire a "plotclick" event on the placeholder with
a position and a nearby data item object as parameters. The coordinates a position and a nearby data item object as parameters. The coordinates
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
<li><a href="series-errorbars/index.html">Plotting error bars</a> (with errorbars plugin)</li> <li><a href="series-errorbars/index.html">Plotting error bars</a> (with errorbars plugin)</li>
<li><a href="series-pie/index.html">Pie charts</a> (with pie plugin)</li> <li><a href="series-pie/index.html">Pie charts</a> (with pie plugin)</li>
<li><a href="canvas/index.html">Rendering text with canvas instead of HTML</a> (with canvas plugin)</li> <li><a href="canvas/index.html">Rendering text with canvas instead of HTML</a> (with canvas plugin)</li>
<li><a href="markings/index.html">Adding text into markings.</a></li>
</ul> </ul>
</div> </div>
......
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Flot Examples: Markings</title>
<link href="../examples.css" rel="stylesheet" type="text/css">
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../../excanvas.min.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../../lib/jquery.js"></script>
<script language="javascript" type="text/javascript" src="../../lib/jquery.colorhelpers.js"></script>
<script language="javascript" type="text/javascript" src="../../jquery.flot.js"></script>
<script language="javascript" type="text/javascript" src="../../jquery.flot.image.js"></script>
<script type="text/javascript">
$(function () {
var yAxisLabels = ["", "Pre A1", "A1", "A2", "B1.1", "B1.2", "B2.1", "C1.1", "C1.2", "Level", "", ""];
var xAxisLabels = ["", "", "Age", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", ""];
function yAxisLabelGenerator(y) {
return yAxisLabels[y];
}
function xAxisLabelGenerator(x) {
return xAxisLabels[x];
}
var markings = [
// markings that has 3 pixels rounded and with single line html
{ color: "rgba(87, 181, 255, 1)", xaxis: { from: 6, to: 10 }, yaxis: { from: 1.8, to: 2.2 }, text: "6 to 10", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#57b5ff", xaxis: { from: 9.5, to: 10.5 }, yaxis: { from: 2.8, to: 3.2 }, text: "10", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#57b5ff", xaxis: { from: 10, to: 14 }, yaxis: { from: 3.8, to: 4.2 }, text: "10 to 14", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#57b5ff", xaxis: { from: 14, to: 15 }, yaxis: { from: 4.8, to: 5.2 }, text: "14 to 15", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#d7048a", xaxis: { from: 15, to: 17 }, yaxis: { from: 5.8, to: 6.2 }, text: "15 to 17", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#838383", xaxis: { from: 17, to: 19 }, yaxis: { from: 6.8, to: 7.2 }, text: "17 and up", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#838383", xaxis: { from: 17, to: 19 }, yaxis: { from: 7.8, to: 8.2 }, text: "17 and up", rounded: 3, aboveGrid: true, font: { color: "#fff" }, textAlign: "center", textBaseline: "middle" },
{ color: "#57b5ff", xaxis: { from: 6.9, to: 7 }, yaxis: { from: 1.2, to: 1.8 }, aboveGrid: true },
// markings with multiline html.
{ color: "#e2f0f9", xaxis: { from: 7, to: 8 }, yaxis: { from: 1.2, to: 1.8 }, aboveGrid: true, text: "<strong>HF</strong><br />2A-2B", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#57b5ff", xaxis: { from: 7.9, to: 8 }, yaxis: { from: 2.2, to: 2.8 } },
{ color: "#e2f0f9", xaxis: { from: 8, to: 9 }, yaxis: { from: 2.2, to: 2.8 }, aboveGrid: true, text: "<strong>HF</strong><br />2A-2B", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#57b5ff", xaxis: { from: 8.9, to: 9 }, yaxis: { from: 2.2, to: 2.8 } },
{ color: "#e9e9e9", xaxis: { from: 9, to: 10 }, yaxis: { from: 2.2, to: 2.8 }, aboveGrid: true, text: "<strong>HF</strong><br />2A-2B", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#e2f0f9", xaxis: { from: 10, to: 10.5 }, yaxis: { from: 2.2, to: 2.8 }, aboveGrid: true, text: "<strong>TB</strong><br />BX4", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#57b5ff", xaxis: { from: 10.4, to: 10.5 }, yaxis: { from: 3.2, to: 3.8 }, aboveGrid: true },
{ color: "#e2f0f9", xaxis: { from: 10.5, to: 11.5 }, yaxis: { from: 3.2, to: 3.8 }, aboveGrid: true, text: "<strong>TB</strong><br />BX7-8", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arail" } },
{ color: "#b8b8b8", xaxis: { from: 11.4, to: 11.5 }, yaxis: { from: 4.2, to: 4.8 }, aboveGrid: true },
{ color: "#e6e6e6", xaxis: { from: 11.5, to: 12.5 }, yaxis: { from: 4.2, to: 4.8 }, aboveGrid: true, text: "<strong>TB</strong><br />BX7-8", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#b8b8b8", xaxis: { from: 12.4, to: 12.5 }, yaxis: { from: 5.2, to: 5.8 }, aboveGrid: true },
{ color: "#e6e6e6", xaxis: { from: 12.5, to: 13.5 }, yaxis: { from: 5.2, to: 5.8 }, aboveGrid: true, text: "<strong>FR</strong><br />BX3-10", textAlign: "left", textBaseline: "middle", font: { color: "#000", size: "12px", family: "Arial" } },
{ color: "#b8b8b8", xaxis: { from: 13.4, to: 13.5 }, yaxis: { from: 6.2, to: 6.8 }, aboveGrid: true },
{ color: "#e6e6e6", xaxis: { from: 13.5, to: 14.5 }, yaxis: { from: 6.2, to: 6.8 }, aboveGrid: true, text: "<strong>FR</strong><br />BX11-12", textAlign: "left", textBaseline: "middle", font: { style: "", variant: "", weight: "", color: "#000", size: "12", lineHeight: "12", family: "Arial" } },
{ color: "#b8b8b8", xaxis: { from: 14.4, to: 14.5 }, yaxis: { from: 7.2, to: 7.8 }, aboveGrid: true },
{ color: "#e6e6e6", xaxis: { from: 14.5, to: 15.5 }, yaxis: { from: 7.2, to: 7.8 }, aboveGrid: true, text: "<div style='margin: 0 0 0 1px;'><strong>FR</strong><br />BX13-14</div>", textAlign: "left", textBaseline: "top", font: { color: "#000", size: "10", family: "Arial" } },
// A example marking that is behind the grid (by specify a color with a opacity value).
// By default the markings will be above the grid.
{ aboveGrid: false, color: "rgb(170, 170, 170)", xaxis: { from: 3.5, to: 6.5 }, yaxis: { from: 5.5, to: 8.5 }, text: "<strong>I'm behind the grid</strong>,<br />others are above it.", font: { color: "#00f", size: "13", family: "Arial" }, textAlign: "center", textBaseline: "middle" }
];
var data = [[
["you_are_here.png", 10, 3.9, 11.1, 5.4]
]];
var options = {
series: { images: { show: true } },
xaxis: {
ticks: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
tickFormatter: xAxisLabelGenerator,
min: 2,
max: 19
},
yaxis: {
ticks: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
tickFormatter: yAxisLabelGenerator,
min: 0,
max: 9
},
grid: {
show: true,
markings: markings,
markingsAboveGrid: true,
borderColor: "#000",
backgroundColor: { colors: ["#fff", "#fff"] }
}
};
$(document).ready(function () {
$.plot.image.loadDataImages(data, options, function () {
$.plot("#goal-map-canvas-wrapper", data, options);
});
});
});
</script>
</head>
<body>
<div id="header">
<h2>Adding text into markings</h2>
</div>
<div id="content">
<div class="demo-container">
<div id="goal-map-canvas-wrapper" class="demo-placeholder"></div>
</div>
<p>This example shows how to add text into markings, and how to draw markings with rounded corner.</p>
<p>The chart here is actually a goal ladder map, and it also shows how to use image plugin to draw icons on to your chart (Notice the "You are here" icon <img src="you_are_here.png" height="30" alt="You are here"/> on this chart.). If you don't need to draw images/icons onto your chart, you don't need to reference the image plugin.</p>
</div>
<div id="footer">
Copyright &copy; 2007 - 2013 IOLA and Ole Laursen
</div>
</body>
</html>
...@@ -866,7 +866,8 @@ Licensed under the MIT license. ...@@ -866,7 +866,8 @@ Licensed under the MIT license.
variant: placeholder.css("font-variant"), variant: placeholder.css("font-variant"),
weight: placeholder.css("font-weight"), weight: placeholder.css("font-weight"),
family: placeholder.css("font-family") family: placeholder.css("font-family")
}; },
markings;
fontDefaults.lineHeight = fontDefaults.size * 1.15; fontDefaults.lineHeight = fontDefaults.size * 1.15;
...@@ -938,6 +939,16 @@ Licensed under the MIT license. ...@@ -938,6 +939,16 @@ Licensed under the MIT license.
} }
} }
markings = options.grid.markings;
if ($.isArray(markings)) {
for (i = 0; i < markings.length; ++i) {
if (markings[i].font) {
markings[i].font = $.extend({}, fontDefaults, markings[i].font);
}
}
}
// backwards compatibility, to be removed in future // backwards compatibility, to be removed in future
if (options.xaxis.noTicks && options.xaxis.ticks == null) { if (options.xaxis.noTicks && options.xaxis.ticks == null) {
options.xaxis.ticks = options.xaxis.noTicks; options.xaxis.ticks = options.xaxis.noTicks;
...@@ -2089,7 +2100,13 @@ Licensed under the MIT license. ...@@ -2089,7 +2100,13 @@ Licensed under the MIT license.
ctx.save(); ctx.save();
ctx.translate(plotOffset.left, plotOffset.top); ctx.translate(plotOffset.left, plotOffset.top);
// draw markings var markingLayer = "flot-markings";
surface.removeText(markingLayer);
// process markings
var markingsUnderGrid = [];
var markingsAboveGrid = [];
var markings = options.grid.markings; var markings = options.grid.markings;
if (markings) { if (markings) {
if ($.isFunction(markings)) { if ($.isFunction(markings)) {
...@@ -2105,63 +2122,18 @@ Licensed under the MIT license. ...@@ -2105,63 +2122,18 @@ Licensed under the MIT license.
} }
for (i = 0; i < markings.length; ++i) { for (i = 0; i < markings.length; ++i) {
var m = markings[i], var m = markings[i];
xrange = extractRange(m, "x"),
yrange = extractRange(m, "y");
// fill in missing
if (xrange.from == null) {
xrange.from = xrange.axis.min;
}
if (xrange.to == null) {
xrange.to = xrange.axis.max;
}
if (yrange.from == null) {
yrange.from = yrange.axis.min;
}
if (yrange.to == null) {
yrange.to = yrange.axis.max;
}
// clip
if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) {
continue;
}
xrange.from = Math.max(xrange.from, xrange.axis.min);
xrange.to = Math.min(xrange.to, xrange.axis.max);
yrange.from = Math.max(yrange.from, yrange.axis.min);
yrange.to = Math.min(yrange.to, yrange.axis.max);
if (xrange.from === xrange.to && yrange.from === yrange.to) { if (m.aboveGrid) {
continue; markingsAboveGrid.push(m);
}
// then draw
xrange.from = xrange.axis.p2c(xrange.from);
xrange.to = xrange.axis.p2c(xrange.to);
yrange.from = yrange.axis.p2c(yrange.from);
yrange.to = yrange.axis.p2c(yrange.to);
if (xrange.from === xrange.to || yrange.from === yrange.to) {
// draw line
ctx.beginPath();
ctx.strokeStyle = m.color || options.grid.markingsColor;
ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
ctx.moveTo(xrange.from, yrange.from);
ctx.lineTo(xrange.to, yrange.to);
ctx.stroke();
} else { } else {
// fill area markingsUnderGrid.push(m);
ctx.fillStyle = m.color || options.grid.markingsColor;
ctx.fillRect(xrange.from, yrange.to,
xrange.to - xrange.from,
yrange.from - yrange.to);
} }
} }
} }
drawMarkings(markingsUnderGrid, markingLayer);
// draw the ticks // draw the ticks
axes = allAxes(); axes = allAxes();
bw = options.grid.borderWidth; bw = options.grid.borderWidth;
...@@ -2265,6 +2237,7 @@ Licensed under the MIT license. ...@@ -2265,6 +2237,7 @@ Licensed under the MIT license.
ctx.stroke(); ctx.stroke();
} }
drawMarkings(markingsAboveGrid, markingLayer);
// draw border // draw border
if (bw) { if (bw) {
...@@ -2324,6 +2297,109 @@ Licensed under the MIT license. ...@@ -2324,6 +2297,109 @@ Licensed under the MIT license.
ctx.restore(); ctx.restore();
} }
function drawMarkings(markings, markingLayer) {
if (!markings) {
return;
}
for (var i = 0; i < markings.length; i++) {
drawMarking(markings[i], markingLayer);
}
}
function drawMarking(m, markingLayer) {
var xrange = extractRange(m, "x"),
yrange = extractRange(m, "y");
// fill in missing
if (xrange.from == null) {
xrange.from = xrange.axis.min;
}
if (xrange.to == null) {
xrange.to = xrange.axis.max;
}
if (yrange.from == null) {
yrange.from = yrange.axis.min;
}
if (yrange.to == null) {
yrange.to = yrange.axis.max;
}
// clip
if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) {
return;
}
xrange.from = Math.max(xrange.from, xrange.axis.min);
xrange.to = Math.min(xrange.to, xrange.axis.max);
yrange.from = Math.max(yrange.from, yrange.axis.min);
yrange.to = Math.min(yrange.to, yrange.axis.max);
if (xrange.from === xrange.to && yrange.from === yrange.to) {
return;
}
// then draw
xrange.from = xrange.axis.p2c(xrange.from);
xrange.to = xrange.axis.p2c(xrange.to);
yrange.from = yrange.axis.p2c(yrange.from);
yrange.to = yrange.axis.p2c(yrange.to);
if (xrange.from === xrange.to || yrange.from === yrange.to) {
// draw line
ctx.beginPath();
ctx.strokeStyle = m.color || options.grid.markingsColor;
ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
ctx.moveTo(xrange.from, yrange.from);
ctx.lineTo(xrange.to, yrange.to);
ctx.stroke();
} else {
// fill area
ctx.fillStyle = m.color || options.grid.markingsColor;
if (!m.rounded) {
ctx.fillRect(xrange.from, yrange.to,
xrange.to - xrange.from,
yrange.from - yrange.to);
} else {
roundRect(ctx, xrange.from, yrange.to, xrange.to - xrange.from, yrange.from - yrange.to, m.rounded);
ctx.fill();
}
}
if (m.text) {
// left aligned horizontal position:
var xPos = xrange.from + plotOffset.left;
// top baselined vertical position:
var yPos = (yrange.to + plotOffset.top);
if (!!m.textAlign) {
switch (m.textAlign.toLowerCase()) {
case "right":
xPos = xrange.to + plotOffset.left;
break;
case "center":
xPos = (xrange.from + plotOffset.left + xrange.to + plotOffset.left) / 2;
break;
}
}
if (!!m.textBaseline) {
switch (m.textBaseline.toLowerCase()) {
case "bottom":
yPos = (yrange.from + plotOffset.top);
break;
case "middle":
yPos = (yrange.from + plotOffset.top + yrange.to + plotOffset.top) / 2;
break;
}
}
surface.addText(markingLayer, xPos, yPos, m.text, m.font || "flot-marking", 0, null, m.textAlign, m.textBaseline);
}
}
function drawAxisLabels() { function drawAxisLabels() {
$.each(allAxes(), function (_, axis) { $.each(allAxes(), function (_, axis) {
...@@ -3405,4 +3481,32 @@ Licensed under the MIT license. ...@@ -3405,4 +3481,32 @@ Licensed under the MIT license.
return base * Math.floor(n / base); return base * Math.floor(n / base);
} }
// Draw a rectangle with rounded corner on the canvas.
//
// @param {CanvasRenderingContext2D} ctx The canvas 2D context.
// @param {number} x The x-axis coordinate of the upper left corner of
// the rectangle to be drawn.
// @param {number} y The y-axis coordinate of the upper left corner of
// the rectangle to be drawn.
// @param {number} width The width of the rectangle to be drawn.
// @param {number} height The height of the rectangle to be drawn.
// @param {number} radius The radius of the corner of the rectangle
// to be drawn.
function roundRect(ctx, x, y, width, height, radius) {
var r = x + width;
var b = y + height;
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(r - radius, y);
ctx.quadraticCurveTo(r, y, r, y + radius);
ctx.lineTo(r, y + height - radius);
ctx.quadraticCurveTo(r, b, r - radius, b);
ctx.lineTo(x + radius, b);
ctx.quadraticCurveTo(x, b, x, b - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
return ctx;
}
})(jQuery); })(jQuery);
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