Permalink
Browse files

Add support for rotated text.

This replaces the old clunky filter rotation with a new true VML solution. Non-rotated labels are still drawn using span elements so those not using them (currently everyone) should see no change.
  • Loading branch information...
1 parent 6df474c commit e2594752ec919df3e454c3f8d64a7c2454eb4aab @borgar borgar committed Jul 4, 2012
Showing with 94 additions and 53 deletions.
  1. +0 −1 README.md
  2. +94 −52 src/VmlLabel.js
View
@@ -28,7 +28,6 @@ The shim can translate lines, areas, panels, rules, labels and most basic things
Things known not to work are:
* Polar interpolation for lines is missing.
-* Rotated labels are incorrectly positioned.
* Label shadow is missing.
* Label text does not support opacity.
* Zoom property is not supported.
View
@@ -13,65 +13,107 @@ pv.VmlScene.label = function(scenes) {
if ( s.cursor ) { attr.cursor = s.cursor; }
// measure text
- var txt = s.text.replace( /\s+/g, '\xA0' );
- var label = vml.text_dims( txt, s.font );
+ var txt = s.text.replace( /\s+/g, '\xA0' )
+ , label = vml.text_dims( txt, s.font )
+ , dx1 = 0
+ , dx2 = 100
+ , dy = 0
+ , vTextAlign = 'left'
+ ;
+ ;
- var dx = 0, dy = 0;
+ // rotated text
+ if ( s.textAngle ) {
- if ( s.textBaseline === 'middle' ) {
- dy -= label.fontsize / 2;
- }
- else if ( s.textBaseline === 'top' ) {
- dy += s.textMargin;
- }
- else if ( s.textBaseline === 'bottom' ) {
- dy -= s.textMargin + label.fontsize;
- }
+ if ( s.textBaseline === 'top' ) {
+ dy += s.textMargin + ( label.fontsize * 0.4 );
+ }
+ else if ( s.textBaseline === 'bottom' ) {
+ dy -= s.textMargin + ( label.fontsize * 0.33 );
+ }
- if ( s.textAlign === 'center' ) {
- dx -= label.width / 2;
- }
- else if ( s.textAlign === 'right' ) {
- dx -= label.width + s.textMargin;
- }
- else if ( s.textAlign === 'left' ) {
- dx += s.textMargin;
- }
+ if ( s.textAlign === 'center' ) {
+ dx1 = -label.width / 2;
+ dx2 = label.width;
+ }
+ else if ( s.textAlign === 'right' ) {
+ dx1 = -s.textMargin;
+ dx2 = -( s.textMargin + label.width );
+ vTextAlign = 'right';
+ }
+ else if ( s.textAlign === 'left' ) {
+ dx1 = s.textMargin;
+ dx2 = s.textMargin + label.width;
+ }
- e = this.expect(e, "text", attr, {
- "font": s.font,
- // "text-shadow": s.textShadow,
- "textDecoration": s.textDecoration,
- 'top': Math.round( s.top + dy ) + 'px',
- 'left': Math.round( s.left + dx ) + 'px',
- 'position': 'absolute',
- 'display': 'block',
- 'lineHeight': 1,
- 'whiteSpace': 'nowrap',
- 'zoom': 1,
- 'cursor': 'default',
- 'color': vml.color( fill.color ) || 'black'
- });
- e.innerText = txt;
+ // create element
+ var rot = ( s.textAngle ) ? " rotate(" + 180 * s.textAngle / Math.PI + ")" : "";
+ e = this.expect(e, "path", {
+ "pointer-events": s.events,
+ "cursor": s.cursor,
+ "transform": "translate(" + s.left + "," + s.top + ")" + rot,
+ "d": "M" + dx1 + "," + dy + " L" + dx2 + "," + dy + " Z",
+ "fill": fill.color,
+ "fill-rule": "evenodd",
+ "fill-opacity": fill.opacity || null,
+ });
+
+ // bind text to path
+ var p = e.getElementsByTagName( 'path' )[0];
+ if ( p ) {
+ p.textpathok = true;
+ var tp = e.getElementsByTagName( 'textpath' )[0];
+ if ( !tp ) {
+ tp = document.createElement( vml.pre + 'textpath' + vml.post );
+ e.appendChild( tp );
+ tp.on = true;
+ tp.style["v-text-kern"] = true;
+ }
+ tp.string = txt;
+ tp.style.font = s.font;
+ tp.style["v-text-align"] = vTextAlign;
+ }
- // Rotation is broken in serveral different ways:
- // 1. it looks REALLY ugly
- // 2. it is incredibly slow
- // 3. rotated text is offset completely wrong and it takes a ton of math to correct it
- // when text is rotated we need to switch to a VML textpath solution
- var rotation = 180 * s.textAngle / Math.PI;
- if ( rotation ) {
- var r = (~~rotation % 360) * vml.d2r,
- ct = Math.cos(r),
- st = Math.sin(r);
- e.style.filter = ['progid:DXImageTransform.Microsoft.Matrix(',
- 'M11=', ct.toFixed( 8 ), ',',
- 'M12=', -st.toFixed( 8 ), ',',
- 'M21=', st.toFixed( 8 ), ',',
- 'M22=', ct.toFixed( 8 ), ',sizingMethod=\'auto expand\')";'].join('');
}
+ // non-rotated text
else {
- e.style.filter = '';
+
+ if ( s.textBaseline === 'middle' ) {
+ dy -= label.fontsize / 2;
+ }
+ else if ( s.textBaseline === 'top' ) {
+ dy += s.textMargin;
+ }
+ else if ( s.textBaseline === 'bottom' ) {
+ dy -= s.textMargin + label.fontsize;
+ }
+
+ if ( s.textAlign === 'center' ) {
+ dx1 -= label.width / 2;
+ }
+ else if ( s.textAlign === 'right' ) {
+ dx1 -= label.width + s.textMargin;
+ }
+ else if ( s.textAlign === 'left' ) {
+ dx1 += s.textMargin;
+ }
+
+ e = this.expect(e, "text", attr, {
+ "font": s.font,
+ // "text-shadow": s.textShadow,
+ "textDecoration": s.textDecoration,
+ 'top': Math.round( s.top + dy ) + 'px',
+ 'left': Math.round( s.left + dx1 ) + 'px',
+ 'position': 'absolute',
+ 'display': 'block',
+ 'lineHeight': 1,
+ 'whiteSpace': 'nowrap',
+ 'zoom': 1,
+ 'cursor': 'default',
+ 'color': vml.color( fill.color ) || 'black'
+ });
+ e.innerText = txt;
+
}
e = this.append(e, scenes, i);

0 comments on commit e259475

Please sign in to comment.