Skip to content

Commit

Permalink
Merge branch 'master' of github.com:kamicane/art
Browse files Browse the repository at this point in the history
Conflicts:
	Source/ART.js
  • Loading branch information
kamicane committed Oct 27, 2010
2 parents 989816f + 97354df commit c42f135
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Color
Submodule Color updated 1 files
+13 −0 Source/Color.js
3 changes: 2 additions & 1 deletion Source/ART.Base.js
Expand Up @@ -2,7 +2,7 @@
---
name: ART.Base
description: "Implements ART, ART.Shape and ART.Group based on the current browser."
provides: [ART.Base, ART.Group, ART.Shape]
provides: [ART.Base, ART.Group, ART.Shape, ART.Text]
requires: [ART.VML, ART.SVG]
...
*/
Expand All @@ -27,6 +27,7 @@ if (!MODE) return;

ART.Shape = new Class({Extends: ART[MODE].Shape});
ART.Group = new Class({Extends: ART[MODE].Group});
ART.Text = new Class({Extends: ART[MODE].Text});
ART.implement({Extends: ART[MODE]});

})();
4 changes: 3 additions & 1 deletion Source/ART.Font.js
Expand Up @@ -63,7 +63,9 @@ ART.Font = new Class({
width += w;
}

this.fontSize = {width: width, height: size * (font.face.ascent - font.face.descent)};
height -= size * font.face.descent;

this.fontSize = {left: 0, top: 0, right: width, bottom: height, width: width, height: height};

return this.parent(path);
},
Expand Down
83 changes: 68 additions & 15 deletions Source/ART.Path.js
Expand Up @@ -176,6 +176,28 @@ var extrapolate = function(parts, precision){

};

/* Utility command factories */

var point = function(c){
return function(x, y){
return this.push(c, x, y);
};
};

var arc = function(c, cc){
return function(x, y, rx, ry, outer){
return this.push(c, Math.abs(rx || x), Math.abs(ry || rx || y), 0, outer ? 1 : 0, cc, x, y);
};
};

var curve = function(t, q, c){
return function(c1x, c1y, c2x, c2y, ex, ey){
var args = Array.slice(arguments), l = args.length;
args.unshift(l < 4 ? t : l < 6 ? q : c);
return this.push.apply(this, args);
};
};

/* Path Class */

ART.Path = new Class({
Expand Down Expand Up @@ -214,28 +236,59 @@ ART.Path = new Class({

/*utility*/

move: function(x, y){
return this.push('m', x, y);
},
move: point('m'),
moveTo: point('M'),

line: function(x, y){
return this.push('l', x, y);
},
line: point('l'),
lineTo: point('L'),

curve: curve('t', 'q', 'c'),
curveTo: curve('T', 'Q', 'C'),

arc: arc('a', 1),
arcTo: arc('A', 1),

counterArc: arc('a', 0),
counterArcTo: arc('A', 0),

close: function(){
return this.push('z');
},

bezier: function(c1x, c1y, c2x, c2y, ex, ey){
return this.push('c', c1x, c1y, c2x, c2y, ex, ey);
},

arc: function(x, y, rx, ry, large){
return this.push('a', Math.abs(rx || x), Math.abs(ry || rx || y), 0, large ? 1 : 0, 1, x, y);
},
/* split each continuous line into individual paths */

counterArc: function(x, y, rx, ry, large){
return this.push('a', Math.abs(rx || x), Math.abs(ry || rx || y), 0, large ? 1 : 0, 0, x, y);
splitContinuous: function(){
var parts = this.path, newPaths = [], path = new ART.Path();

var X = 0, Y = 0, inX, inY;
for (i = 0; i < parts.length; i++){
var v = parts[i], f = v[0], l = f.toLowerCase();

if (l != 'm' && inX == null){ inX = X; inY = Y; }

if (l != f){ X = 0; Y = 0; }

if (l == 'm' || l == 'l' || l == 't'){ X += v[1]; Y += v[2]; }
else if (l == 'c'){ X += v[5]; Y += v[6]; }
else if (l == 's' || l == 'q'){ X += v[3]; Y += v[4]; }
else if (l == 'a'){ X += v[6]; Y += v[7]; }
else if (l == 'h'){ X += v[1]; }
else if (l == 'v'){ Y += v[1]; }
else if (l == 'z' && inX != null){
X = inX; Y = inY;
inX = null;
}

if (path.path.length > 0 && (l == 'm' || l == 'z')){
newPaths.push(path);
path = new ART.Path().push('M', X, Y);
} else {
path.path.push(v);
}
}

newPaths.push(path);
return newPaths;
},

/* transformation, measurement */
Expand Down
153 changes: 151 additions & 2 deletions Source/ART.SVG.js
Expand Up @@ -2,7 +2,7 @@
---
name: ART.SVG
description: "SVG implementation for ART"
provides: [ART.SVG, ART.SVG.Group, ART.SVG.Shape, ART.SVG.Image]
provides: [ART.SVG, ART.SVG.Group, ART.SVG.Shape, ART.SVG.Image, ART.SVG.Text]
requires: [ART, ART.Element, ART.Container, ART.Path]
...
*/
Expand Down Expand Up @@ -135,7 +135,6 @@ ART.SVG.Base = new Class({

initialize: function(tag){
this.parent(tag);
this.element.setAttribute('fill-rule', 'evenodd');
this.fill();
this.stroke();
},
Expand Down Expand Up @@ -286,6 +285,7 @@ ART.SVG.Shape = new Class({

initialize: function(path){
this.parent('path');
this.element.setAttribute('fill-rule', 'evenodd');
if (path != null) this.draw(path);
},

Expand Down Expand Up @@ -324,4 +324,153 @@ ART.SVG.Image = new Class({

});

var fontAnchors = { left: 'start', center: 'middle', right: 'end' },
fontAnchorOffsets = { middle: '50%', end: '100%' };

ART.SVG.Text = new Class({

Extends: ART.SVG.Base,

initialize: function(text, font, alignment, path){
this.parent('text');
this.draw.apply(this, arguments);
},

draw: function(text, font, alignment, path){
var element = this.element;

if (font){
if (typeof font == 'string'){
element.style.font = font;
} else {
for (var key in font){
var ckey = key.camelCase ? key.camelCase() : key;
// NOT UNIVERSALLY SUPPORTED OPTIONS
// if (ckey == 'kerning') element.setAttribute('kerning', font[key] ? 'auto' : '0');
// else if (ckey == 'letterSpacing') element.setAttribute('letter-spacing', Number(font[key]) + 'ex');
// else if (ckey == 'rotateGlyphs') element.setAttribute('glyph-orientation-horizontal', font[key] ? '270deg' : '');
// else
element.style[ckey] = font[key];
}
element.style.lineHeight = '0.5em';
}
}

if (alignment) element.setAttribute('text-anchor', this.textAnchor = (fontAnchors[alignment] || alignment));

if (path && typeof path != 'number'){
this._createPaths(new ART.Path(path));
} else if (path === false){
this._ejectPaths();
this.pathElements = null;
}

var paths = this.pathElements, child;

while (child = element.firstChild){
element.removeChild(child);
}

// Note: Gecko will (incorrectly) align gradients for each row, while others applies one for the entire element

var lines = String(text).split(/\r?\n/), l = lines.length,
baseline = paths ? 'middle' : 'text-before-edge';

if (paths && l > paths.length) l = paths.length;

element.setAttribute('dominant-baseline', baseline);

for (var i = 0; i < l; i++){
var line = lines[i], row;
if (paths){
row = createElement('textPath');
row.setAttributeNS(XLINK, 'href', '#' + paths[i].getAttribute('id'));
row.setAttribute('startOffset', fontAnchorOffsets[this.textAnchor] || 0);
} else {
row = createElement('tspan');
row.setAttribute('x', 0);
row.setAttribute('dy', i == 0 ? '0' : '1em');
}
row.setAttribute('baseline-shift', paths ? '-0.5ex' : '-2ex'); // Opera
row.setAttribute('dominant-baseline', baseline);
row.appendChild(document.createTextNode(line));
element.appendChild(row);
}
},

// TODO: Unify path injection with gradients and imagefills

inject: function(container){
this.parent(container);
this._injectPaths();
return this;
},

eject: function(){
if (this.container){
this._ejectPaths();
this.parent();
this.container = null;
}
return this;
},

_injectPaths: function(){
var paths = this.pathElements;
if (!this.container || !paths) return;
var defs = this.container.defs;
for (var i = 0, l = paths.length; i < l; i++)
defs.appendChild(paths[i]);
},

_ejectPaths: function(){
var paths = this.pathElements;
if (!this.container || !paths) return;
var defs = this.container.defs;
for (var i = 0, l = paths; i < l; i++)
defs.removeChild(paths[i]);
},

_createPaths: function(path){
this._ejectPaths();
var id = 'p' + ART.uniqueID() + '-';
var paths = path.splitContinuous();
var result = [];
for (var i = 0, l = paths.length; i < l; i++){
var p = createElement('path');
p.setAttribute('d', paths[i].toSVG());
p.setAttribute('id', id + i);
result.push(p);
}
this.pathElements = result;
this._injectPaths();
},

_whileInDocument: function(fn, bind){
// Temporarily inject into the document
var element = this.element,
container = this.container,
parent = element.parentNode,
sibling = element.nextSibling,
body = element.ownerDocument.body,
canvas = new ART.SVG(1, 1).inject(body);
this.inject(canvas);
var result = fn.call(bind);
canvas.eject();
if (container) this.inject(container);
if (parent) parent.insertBefore(element, sibling);
return result;
},

measure: function(){
var element = this.element, bb;

try { bb = element.getBBox(); } catch (x){ }
if (!bb || !bb.width) bb = this._whileInDocument(element.getBBox, element);

return { left: bb.x, top: bb.y, width: bb.width, height: bb.height, right: bb.x + bb.width, bottom: bb.y + bb.height };
}

});

})();

0 comments on commit c42f135

Please sign in to comment.