Commit 6350cc67 authored by David Schnur's avatar David Schnur

Added core support for rotated HTML text.

parent 97f2a127
......@@ -151,28 +151,33 @@ Licensed under the MIT license.
for (var styleKey in layerCache) {
if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) {
var styleCache = layerCache[styleKey];
for (var key in styleCache) {
if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
var positions = styleCache[key].positions;
for (var i = 0, position; position = positions[i]; i++) {
if (position.active) {
if (!position.rendered) {
layer.append(position.element);
position.rendered = true;
}
} else {
positions.splice(i--, 1);
if (position.rendered) {
position.element.detach();
}
}
}
if (positions.length === 0) {
delete styleCache[key];
}
for (var angleKey in styleCache) {
if (Object.prototype.hasOwnProperty.call(styleCache, angleKey)) {
var angleCache = styleCache[angleKey];
for (var key in angleCache) {
if (Object.prototype.hasOwnProperty.call(angleCache, key)) {
var positions = angleCache[key].positions;
for (var i = 0, position; position = positions[i]; i++) {
if (position.active) {
if (!position.rendered) {
layer.append(position.element);
position.rendered = true;
}
} else {
positions.splice(i--, 1);
if (position.rendered) {
position.element.detach();
}
}
}
if (positions.length === 0) {
delete angleCache[key];
}
}
}
}
}
}
......@@ -264,17 +269,15 @@ Licensed under the MIT license.
// @param {(string|object)=} font Either a string of space-separated CSS
// classes or a font-spec object, defining the text's font and style.
// @param {number=} angle Angle at which to rotate the text, in degrees.
// Angle is currently unused, it will be implemented in the future.
// @param {number=} width Maximum width of the text before it wraps.
// @return {object} a text info object.
Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
var textStyle, layerCache, styleCache, info;
// Cast the value to a string, in case we were given a number or such
var textStyle, layerCache, styleCache, angleCache, info;
text = "" + text;
text = "" + text; // Cast to string in case we have a number or such
angle = (360 + (angle || 0)) % 360; // Normalize the angle to 0...359
// If the font is a font-spec object, generate a CSS font definition
......@@ -284,21 +287,24 @@ Licensed under the MIT license.
textStyle = font;
}
// Retrieve (or create) the cache for the text's layer and styles
// Retrieve or create the caches for the text's layer, style, and angle
layerCache = this._textCache[layer];
if (layerCache == null) {
layerCache = this._textCache[layer] = {};
}
styleCache = layerCache[textStyle];
if (styleCache == null) {
styleCache = layerCache[textStyle] = {};
}
info = styleCache[text];
angleCache = styleCache[angle];
if (angleCache == null) {
angleCache = styleCache[angle] = {};
}
info = angleCache[text];
// If we can't find a matching element in our cache, create a new one
......@@ -321,9 +327,117 @@ Licensed under the MIT license.
element.addClass(font);
}
info = styleCache[text] = {
width: element.outerWidth(true),
height: element.outerHeight(true),
// Save the original dimensions of the text; we'll modify these
// later to take into account rotation, if there is any.
var textWidth = element.outerWidth(true),
textHeight = element.outerHeight(true);
// Apply rotation to the text using CSS3/IE matrix transforms
// Note how we also set the element's width, as a work-around for
// the way most browsers resize the div on rotate, which may cause
// the contents to wrap differently. The extra +1 is because IE
// rounds the width differently and needs a little extra help.
if (angle) {
var radians = angle * Math.PI / 180,
sin = Math.sin(radians),
cos = Math.cos(radians),
a = cos.toFixed(6), // Use fixed-point so these don't
b = (-sin).toFixed(6), // show up in scientific notation
c = sin.toFixed(6), // when we add them to the string
transformRule;
if ($.support.leadingWhitespace) {
// The transform origin defaults to '50% 50%', producing
// blurry text on some browsers (Chrome) when the width or
// height happens to be odd, making 50% fractional. Avoid
// this by setting the origin to rounded values.
var cx = textWidth / 2,
cy = textHeight / 2,
transformOrigin = Math.floor(cx) + "px " + Math.floor(cy) + "px";
// Transforms alter the div's appearance without changing
// its origin. This will make it difficult to position it
// later, since we'll be positioning the new bounding box
// with respect to the old origin. We can work around this
// by adding a translation to align the new bounding box's
// top-left corner with the origin, using the same matrix.
// Rather than examining all four points, we can use the
// angle to figure out in advance which two points are in
// the top-left quadrant; we can then use the x-coordinate
// of the first (left-most) point and the y-coordinate of
// the second (top-most) point as the bounding box corner.
var x, y;
if (angle < 90) {
x = Math.floor(cx * cos + cy * sin - cx);
y = Math.floor(cx * sin + cy * cos - cy);
} else if (angle < 180) {
x = Math.floor(cy * sin - cx * cos - cx);
y = Math.floor(cx * sin - cy * cos - cy);
} else if (angle < 270) {
x = Math.floor(-cx * cos - cy * sin - cx);
y = Math.floor(-cx * sin - cy * cos - cy);
} else {
x = Math.floor(cx * cos - cy * sin - cx);
y = Math.floor(cy * cos - cx * sin - cy);
}
transformRule = "matrix(" + a + "," + c + "," + b + "," + a + "," + x + "," + y + ")";
element.css({
width: textWidth + 1,
transform: transformRule,
"-o-transform": transformRule,
"-ms-transform": transformRule,
"-moz-transform": transformRule,
"-webkit-transform": transformRule,
"transform-origin": transformOrigin,
"-o-transform-origin": transformOrigin,
"-ms-transform-origin": transformOrigin,
"-moz-transform-origin": transformOrigin,
"-webkit-transform-origin": transformOrigin
});
} else {
// The IE7/8 matrix filter produces very ugly aliasing for
// text with a transparent background. Using a solid color
// greatly improves text clarity, although it does result
// in ugly boxes for plots using a non-white background.
// TODO: Instead of white use the actual background color?
// This still wouldn't solve the problem when the plot has
// a gradient background, but it would at least help.
transformRule = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + a + ",sizingMethod='auto expand')";
element.css({
width: textWidth + 1,
filter: transformRule,
"-ms-filter": transformRule,
"background-color": "#fff"
});
}
// Compute the final dimensions of the text's bounding box
var ac = Math.abs(cos),
as = Math.abs(sin),
originalWidth = textWidth;
textWidth = Math.round(ac * textWidth + as * textHeight);
textHeight = Math.round(as * originalWidth + ac * textHeight);
}
info = angleCache[text] = {
width: textWidth,
height: textHeight,
element: element,
positions: []
};
......@@ -347,7 +461,6 @@ Licensed under the MIT license.
// @param {(string|object)=} font Either a string of space-separated CSS
// classes or a font-spec object, defining the text's font and style.
// @param {number=} angle Angle at which to rotate the text, in degrees.
// Angle is currently unused, it will be implemented in the future.
// @param {number=} width Maximum width of the text before it wraps.
// @param {string=} halign Horizontal alignment of the text; either "left",
// "center" or "right".
......@@ -435,14 +548,19 @@ Licensed under the MIT license.
for (var styleKey in layerCache) {
if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) {
var styleCache = layerCache[styleKey];
for (var key in styleCache) {
if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
positions = styleCache[key].positions;
for (i = 0; position = positions[i]; i++) {
position.active = false;
}
}
}
for (var angleKey in styleCache) {
if (Object.prototype.hasOwnProperty.call(styleCache, angleKey)) {
var angleCache = styleCache[angleKey];
for (var key in angleCache) {
if (Object.prototype.hasOwnProperty.call(angleCache, key)) {
positions = angleCache[key].positions;
for (i = 0; position = positions[i]; i++) {
position.active = false;
}
}
}
}
}
}
}
}
......
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