Permalink
Browse files

- this is the next major iteration of ART!

 - SVG/VML based instead of Canvas/VML
 - supports groups, dynamic transformations, dom operations with SVG/VML real elements via ART methods
 - real svg paths from any drawing application, including Illustrator, automatically converted to VML
 - and much more!
  • Loading branch information...
1 parent bf30d5c commit 18e21663827db08a89e93dfdc119e18b1bea3f76 @kamicane committed Feb 22, 2010
View
2 Fonts/MgOpen.Moderna.Bold.js → Fonts/Moderna.Bold.js
@@ -3,7 +3,7 @@
name: Moderna.Bold
-description: MgOpen Moderna Bold built with Cufón (http://wiki.github.com/sorccu/cufon/about)
+description: MgOpen Moderna Bold built with [Cufón](http://wiki.github.com/sorccu/cufon/about)
provides: Moderna.Bold
View
2 Fonts/MgOpen.Moderna.js → Fonts/Moderna.js
@@ -3,7 +3,7 @@
name: Moderna
-description: MgOpen Moderna built with Cufón (http://wiki.github.com/sorccu/cufon/about)
+description: MgOpen Moderna built with [Cufón](http://wiki.github.com/sorccu/cufon/about)
provides: Moderna
View
167 Source/ART.Canvas.js
@@ -1,167 +0,0 @@
-/*
----
-
-name: ART.Canvas
-
-description: Canvas implementation for ART
-
-authors: [Valerio Proietti](http://mad4milk.net) && [MooTools development team](http://mootools.net/developers)
-
-provides: ART.Canvas
-
-requires: ART
-
-...
-*/
-
-ART.Canvas = new Class({
-
- initialize: function(id, width, height){
- this.element = new Element('canvas', {'id': id || 'art-' + $time()});
- this.context = this.element.getContext('2d');
- this.resize({x: width, y: height});
- },
-
- resize: function(size){
- this.element.width = size.x;
- this.element.height = size.y;
- },
-
- clear: function(){
- this.context.clearRect(0, 0, this.element.width, this.element.height);
- },
-
- start: function(){
- this.drawStack = [];
- this.drawn = false;
- this.drawStyle = null;
- this.bounds = {x: [], y: []};
- this.context.beginPath();
- },
-
- end: function(style){
- this.drawStyle = style;
-
- if (style.shadow != null) this.shadow(style.shadow, style.shadowOffset, style.shadowBlur);
- else this.context.shadowColor = 'rgba(0, 0, 0, 0)'; //this makes sure the shadow is not drawn from a previous shape
-
- var stack = this.drawStack;
- for (var i=0; i < stack.length; i++){
- var s = stack[i], method = s[0], args = s[1];
- this.context[method].apply(this.context, args);
- }
-
- if (style.fill != null){
- var fill = $splat(style.fill);
- this.fill(fill[0], fill[1], style.fillMode);
- }
- if (style.outline != null) this.outline(style.outline, style.outlineWidth, style.outlineCap, style.outlineJoin);
- },
-
- join: function(){
- this.drawStack.push(['closePath', []]);
- },
-
- /* drawing methods */
-
- move: function(vector){
- if (!this.drawn) this.lastVector = vector;
- this.drawStack.push(['moveTo', [vector.x, vector.y]]);
- },
-
- line: function(vector){
- if (!this.drawn) this.setStartCoordinate();
- this.bounds.x.push(vector.x);
- this.bounds.y.push(vector.y);
- this.drawStack.push(['lineTo', [vector.x, vector.y]]);
- },
-
- bezier: function(c1, c2, end){
- if (!this.drawn) this.setStartCoordinate();
- this.bounds.x.push(c1.x, c2.x, end.x);
- this.bounds.y.push(c1.y, c2.y, end.y);
- this.drawStack.push(['bezierCurveTo', [c1.x, c1.y, c2.x, c2.y, end.x, end.y]]);
- },
-
- setStartCoordinate: function(){
- this.bounds.x.push(this.lastVector.x);
- this.bounds.y.push(this.lastVector.y);
- this.drawn = true;
- },
-
- /* privates */
-
- fill: function(color1, color2, mode){
- var fillStyle = color1.valueOf();
- if (color2 != null){
- var gradient;
-
- if (mode == 'vertical'){
- var minY = Math.min.apply(Math, this.bounds.y), maxY = Math.max.apply(Math, this.bounds.y);
- gradient = this.context.createLinearGradient(0, minY, 0, maxY);
- } else if (mode == 'horizontal') {
- var minX = Math.min.apply(Math, this.bounds.x), maxX = Math.max.apply(Math, this.bounds.x);
- gradient = this.context.createLinearGradient(minX, 0, maxX, 0);
- }
-
- gradient.addColorStop(0, fillStyle);
- gradient.addColorStop(1, color2.valueOf());
- fillStyle = gradient;
- }
-
- this.context.fillStyle = fillStyle;
-
- this.context.fill();
- },
-
- outline: function(color, width, cap, join){
- this.context.strokeStyle = color.valueOf();
- this.context.lineWidth = Number(width);
- this.context.lineCap = cap;
- this.context.lineJoin = join;
- this.context.stroke();
- },
-
- shadow: function(color, offset, blur){
- // If blur is not zero, we need to use real canvas shadows. The problem with those is that
- // 1: WebKit cannot draw shadows if the element being shadowed is filled with a gradient. This is a bug.
- // 2: WebKit and Gecko calculate the shadow opacity based on the element opacity, which is wrong. This is not real life, but a drawing API.
- // It is then impossible to draw a transparent element with a shadow in place of the real element as a workaround for (1),
- // because of (2). A transparent element would have no shadow.
- if (blur != 0){
- this.context.shadowColor = color.valueOf();
- this.context.shadowBlur = (Browser.Engine.gecko) ? blur * 3 : blur;
- this.context.shadowOffsetX = offset.x;
- this.context.shadowOffsetY = offset.y;
- } else {
- var path = this.drawStack, style = this.drawStyle, bounds = this.bounds;
- this.context.translate(offset.x, offset.y);
- this.end({
- fill: (style.fill != null) ? color : null,
- outline: (style.outline != null) ? color : null,
- outlineWidth: style.outlineWidth,
- outlineCap: style.outlineCap,
- outlineJoin: style.outlineJoin,
- shadow: null
- });
- this.context.translate(-offset.x, -offset.y);
- this.start();
- this.drawStack = path;
- this.bounds = bounds;
- }
- },
-
- /* $ */
-
- toElement: function(){
- return this.element;
- }
-
-});
-
-(function(){
-
-var dummy = document.createElement('canvas');
-if (!!(dummy && dummy.getContext)) ART.registerAdapter(ART.Canvas);
-
-})();
View
95 Source/ART.Font.js
@@ -7,73 +7,74 @@ description: Fonts for ART, implements code from [Cufón](http://cufon.shoqolate
authors: [Simo Kinnunen](http://twitter.com/sorccu), ART adaptation by [Valerio Proietti](http://mad4milk.net/)
-provides: [ART:text, ART.Font]
+provides: ART.Font
-requires: [ART.Canvas, ART.VML]
+requires: ART.Shape
...
*/
-// stub
-
-ART.Font = function(font){
- return font;
-};
-
(function(){
var fonts = {};
-ART.defineFont = function(name, font){
- fonts[name] = new ART.Font(font);
-};
-
-ART.lookupFont = function(name){
- return fonts[name];
-};
-
ART.registerFont = function(font){
- var face = font.face, name = face['font-family'].toLowerCase().split(' ');
- if (face['font-weight'] > 400) name.push('bold');
- if (face['font-stretch'] == 'oblique') name.push('italic');
- ART.defineFont(name.join('-'), font);
+ var face = font.face, name = face['font-family'];
+ if (!fonts[name]) fonts[name] = {};
+ var currentFont = fonts[name];
+ var isBold = (face['font-weight'] > 400), isItalic = (face['font-stretch'] == 'oblique');
+ if (isBold && isItalic) currentFont.boldItalic = font;
+ else if (isBold) currentFont.bold = font;
+ else if (isItalic) currentFont.italic = font;
+ else currentFont.normal = font;
+ return this;
};
-var path = function(path, s, self){
- var X = 0, Y = 0;
+var VMLToSVG = function(path, s, x, y){
+ var end = '';
var regexp = /([mrvxe])([^a-z]*)/g, match;
while ((match = regexp.exec(path))){
var c = match[2].split(',');
switch (match[1]){
- case 'v':
- self.bezierTo({x: X + s * ~~c[0], y: Y + s * ~~c[1]}, {x: X + s * ~~c[2], y: Y + s * ~~c[3]}, {x: X += s * ~~c[4], y: Y += s * ~~c[5]});
- break;
- case 'r': self.lineTo({x: X += s * ~~c[0], y: Y += s * ~~c[1]}); break;
- case 'm': self.moveTo({x: X = s * ~~c[0], y: Y = s * ~~c[1]}); break;
- case 'x': self.join(); break;
- case 'e': return;
+ case 'v': end += 'c ' + (s * c[0]) + ',' + (s * c[1]) + ',' + (s * c[2]) + ',' + (s * c[3]) + ',' + (s * c[4]) + ',' + (s * c[5]); break;
+ case 'r': end += 'l ' + (s * c[0]) + ',' + (s * c[1]); break;
+ case 'm': end += 'M ' + (x + (s * c[0])) + ',' + (y + (s * c[1])); break;
+ case 'x': end += 'z'; break;
}
}
+
+ return end;
};
-ART.implement({'text': function(font, size, text){
- if (typeof font == 'string') font = fonts[font];
- if (!font) return new Error('The specified font has not been found.');
-
- this.save();
- size = size / font.face['units-per-em'];
- // Temporary "relative" fix shifting the whole layer by the pointer, since the pointer is lost with path. Should not matter since it's later restored.
- this.shift({x: this.pointer.x, y: this.pointer.y + Math.round(size * font.face.ascent)});
- var width = 0;
- for (var i = 0, l = text.length; i < l; ++i){
- var glyph = font.glyphs[text.charAt(i)] || font.glyphs[' '];
- if (glyph.d) path('m' + glyph.d + 'x', size, this);
- var w = size * (glyph.w || font.w);
- this.shift({x: w, y: 0});
- width += w;
+ART.Font = new Class({
+
+ Extends: ART.Shape,
+
+ initialize: function(font, variant, text, size){
+ if (typeof font == 'string') font = fonts[font][(variant || 'normal').camelCase()];
+ if (!font) throw new Error('The specified font has not been found.');
+ this.font = font;
+
+ this.parent();
+ if (text != null && size != null) this.draw(text, size);
+ },
+
+ draw: function(text, size){
+ var font = this.font;
+ size = size / font.face['units-per-em'];
+
+ var width = 0, height = size * font.face.ascent, path = '';
+
+ for (var i = 0, l = text.length; i < l; ++i){
+ var glyph = font.glyphs[text.charAt(i)] || font.glyphs[' '];
+ var w = size * (glyph.w || font.w);
+ if (glyph.d) path += VMLToSVG('m' + glyph.d + 'x', size, width, height);
+ width += w;
+ }
+
+ return this.parent(path);
}
- this.restore();
- return {x: width, y: size * (font.face.ascent - font.face.descent)};
-}});
+
+});
})();
View
63 Source/ART.Path.js
@@ -0,0 +1,63 @@
+/*
+---
+
+name: ART.Path
+
+description: Class to generate a valid SVG path using method calls.
+
+authors: [Valerio Proietti](http://mad4milk.net)
+
+provides: ART.Path
+
+requires: ART
+
+...
+*/
+
+ART.Path = new Class({
+
+ initialize: function(){
+ this.clear();
+ },
+
+ clear: function(){
+ this.path = [];
+ this.x = 0;
+ this.y = 0;
+ return this;
+ },
+
+ move: function(x, y){
+ this.path.push('m', x, y);
+ return this;
+ },
+
+ line: function(x, y){
+ this.x = x; this.y = y;
+ this.path.push('l', x, y);
+ return this;
+ },
+
+ close: function(){
+ this.path.push('z');
+ return this;
+ },
+
+ bezier: function(c1x, c1y, c2x, c2y, ex, ey){
+ this.path.push('c', c1x, c1y, c2x, c2y, ex, ey);
+ return this;
+ },
+
+ arcLeft: function(x, y){
+ return this.bezier(0, y * Math.kappa, x - (x * Math.kappa), y, x, y);
+ },
+
+ arcRight: function(x, y){
+ return this.bezier(x * Math.kappa, 0, x, y - (y * Math.kappa), x, y);
+ }
+
+});
+
+ART.Path.prototype.toString = function(){
+ return this.path.join(' ');
+};
View
236 Source/ART.SVG.js
@@ -0,0 +1,236 @@
+/*
+---
+
+name: ART.SVG
+
+description: SVG implementation for ART
+
+authors: [Valerio Proietti](http://mad4milk.net)
+
+provides: [ART.SVG, ART.Group, ART.Shape]
+
+requires: [ART, ART.Element, ART.Container]
+
+...
+*/
+
+(function(){
+
+var implementation = document.implementation;
+if (!implementation || !implementation.hasFeature || !document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) return;
+
+var NS = 'http://www.w3.org/2000/svg', XLINK = 'http://www.w3.org/1999/xlink', UID = 0, createElement = function(tag){
+ return document.createElementNS(NS, tag);
+};
+
+// SVG Base Class
+
+ART.SVG = new Class({
+
+ Extends: ART.Element,
+ Implements: ART.Container,
+
+ initialize: function(width, height){
+ this.element = createElement('svg');
+ this.set({'xmlns': NS, version: 1.1});
+ this.defs = createElement('defs');
+ this.element.appendChild(this.defs);
+ this.resize(width, height);
+ },
+
+ resize: function(width, height){
+ this.set({width: width, height: height});
+ return this;
+ }
+
+});
+
+// SVG Element Class
+
+ART.SVG.Element = new Class({
+
+ Extends: ART.Element,
+
+ initialize: function(tag){
+ this.uid = (UID++).toString(16);
+ this.element = createElement(tag);
+ this.set('id', 'e' + this.uid);
+ this.transform = {translate: [0, 0], scale: [1, 1], rotate: [0, 0, 0]};
+ },
+
+ getBBox: function(){
+ return this.element.getBBox();
+ },
+
+ /* transforms */
+
+ _writeTransform: function(){
+ var transforms = [];
+ for (var transform in this.transform) transforms.push(transform + '(' + this.transform[transform].join(',') + ')');
+ this.set('transform', transforms.join(' '));
+ },
+
+ rotate: function(deg, x, y){
+ if (x == null || y == null){
+ var box = this.getBBox();
+ x = box.x + box.width / 2; y = box.y + box.height / 2;
+ }
+ this.transform.rotate = [deg, x, y];
+ this._writeTransform();
+ return this;
+ },
+
+ scale: function(x, y){
+ this.transform.scale = [x, y];
+ this._writeTransform();
+ return this;
+ },
+
+ translate: function(x, y){
+ this.transform.translate = [x, y];
+ this._writeTransform();
+ return this;
+ }
+
+});
+
+// SVG Group Class
+
+ART.SVG.Group = new Class({
+
+ Extends: ART.SVG.Element,
+ Implements: ART.Container,
+
+ initialize: function(){
+ this.parent('g');
+ this.defs = createElement('defs');
+ this.element.appendChild(this.defs);
+ }
+
+});
+
+// SVG Base Shape Class
+
+ART.SVG.Base = new Class({
+
+ Extends: ART.SVG.Element,
+
+ initialize: function(tag){
+ this.parent(tag);
+ this.set({fill: 'none', stroke: 'none'});
+ },
+
+ /* insertions */
+
+ inject: function(container){
+ this.eject();
+ this.container = container;
+ this._injectGradient('fill');
+ this._injectGradient('stroke');
+ this.parent(container);
+ return this;
+ },
+
+ eject: function(){
+ if (this.container){
+ this.parent();
+ this._ejectGradient('fill');
+ this._ejectGradient('stroke');
+ this.container = null;
+ }
+ return this;
+ },
+
+ _injectGradient: function(type){
+ if (!this.container) return;
+ var gradient = this[type + 'Gradient'];
+ if (gradient) this.container.defs.appendChild(gradient);
+ },
+
+ _ejectGradient: function(type){
+ if (!this.container) return;
+ var gradient = this[type + 'Gradient'];
+ if (gradient) this.container.defs.removeChild(gradient);
+ },
+
+ /* styles */
+
+ _createGradient: function(type, colors){
+ var gradient = createElement('linearGradient');
+ //TODO angle calculation from angle argument
+ var coords = {x1: '0%', x2: '0%', y1: '0%', y2: '100%'};
+ for (var c in coords) gradient.setAttribute(c, coords[c]);
+
+ var id = type + '-gradient-e' + this.uid;
+
+ gradient.setAttribute('id', id);
+
+ this[type + 'Gradient'] = gradient;
+
+ for (var i = 0; i < colors.length; i++){
+ var stop = createElement('stop'), color = Color.detach(colors[i]);
+ stop.setAttribute('offset', i / (colors.length - 1));
+ stop.setAttribute('stop-color', color[0]);
+ stop.setAttribute('stop-opacity', color[1]);
+ gradient.appendChild(stop);
+ }
+
+ this._injectGradient(type);
+ return 'url(#' + id + ')';
+ },
+
+ _setColor: function(type, color){
+ if (color.length > 1){
+ color = this._createGradient(type, color);
+ } else {
+ color = Color.detach(color[0]);
+ this.set(type + '-opacity', color[1]);
+ color = color[0];
+ }
+
+ this.set(type, color);
+ },
+
+ fill: function(flag){
+ this._ejectGradient('fill');
+ this.fillGradient = null;
+ if (flag == null) this.set('fill', 'none');
+ else this._setColor('fill', Array.slice(arguments));
+ return this;
+ },
+
+ stroke: function(flag){
+ this._ejectGradient('stroke');
+ this.strokeGradient = null;
+ if (flag == null) this.set('stroke', 'none');
+ else this._setColor('stroke', Array.slice(arguments));
+ return this;
+ }
+
+});
+
+// SVG Shape Class
+
+ART.SVG.Shape = new Class({
+
+ Extends: ART.SVG.Base,
+
+ initialize: function(path){
+ this.parent('path');
+ if (path != null) this.draw(path);
+ },
+
+ draw: function(path){
+ this.set('d', path.toString());
+ return this;
+ }
+
+});
+
+// Assign to ART
+
+ART.Shape = new Class({Extends: ART.SVG.Shape});
+ART.Group = new Class({Extends: ART.SVG.Group});
+ART.implement({Extends: ART.SVG});
+
+})();
View
123 Source/ART.Shape.js
@@ -1,123 +0,0 @@
-/*
----
-
-name: ART.Shape
-
-description: Shapes for ART
-
-authors: [Valerio Proietti](http://mad4milk.net) && [MooTools development team](http://mootools.net/developers)
-
-provides: [ART.Shape, ART:shape]
-
-requires: ART
-
-...
-*/
-
-// stub
-
-ART.Shape = function(shape){
- return shape;
-};
-
-// connect to ART
-
-(function(){
-
-var shapes = {};
-
-ART.defineShape = function(name, shape){
- shapes[name.camelCase()] = new ART.Shape(shape);
- return this;
-};
-
-ART.defineShapes = function(nShapes){
- for (var shape in nShapes) shapes[shape] = nShapes[shape];
- return this;
-};
-
-ART.lookupShape = function(name){
- return shapes[name.camelCase()];
-};
-
-})();
-
-ART.implement({
-
- shape: function(shape){
- var args = Array.slice(arguments, 1);
- if (typeof shape == 'string') shape = ART.lookupShape(shape.camelCase());
- if (!shape) return this;
- this.save();
- shape.apply(this, args);
- return this.restore();
- },
-
- /* some round caps to make things easier */
-
- roundCapLeftTo: function(vector){
- return this.roundCapLeftBy({x: vector.x - this.pointer.x, y: vector.y - this.pointer.y});
- },
-
- roundCapRightTo: function(vector){
- return this.roundCapRightBy({x: vector.x - this.pointer.x, y: vector.y - this.pointer.y});
- },
-
- roundCapLeftBy: function(end){
- var kappa = {x: end.x * Math.kappa, y: end.y * Math.kappa};
- this.bezierBy({x: 0, y: kappa.y}, {x: end.x - kappa.x, y: end.y}, end);
- return this;
- },
-
- roundCapRightBy: function(end){
- var kappa = {x: end.x * Math.kappa, y: end.y * Math.kappa};
- this.bezierBy({x: kappa.x, y: 0}, {x: end.x, y: end.y - kappa.y}, end);
- return this;
- }
-
-});
-
-// default shapes
-
-ART.defineShapes({
-
- rectangle: function(end){
- this.lineBy({x: end.x, y: 0}).lineBy({x: 0, y: end.y}).lineBy({x: -end.x, y: 0}).lineBy({x: 0, y: -end.y});
- },
-
- ellipse: function(end){
- var radius = {x: end.x / 2, y: end.y / 2};
- this.moveBy({x: 0, y: radius.y});
- this.roundCapLeftBy({x: radius.x, y: -radius.y}).roundCapRightBy({x: radius.x, y: radius.y});
- this.roundCapLeftBy({x: -radius.x, y: radius.y}).roundCapRightBy({x: -radius.x, y: -radius.y});
- },
-
- roundedRectangle: function(end, radius){
- if (radius == null) radius = [5, 5, 5, 5];
- if (typeof radius == 'number') radius = [radius, radius, radius, radius];
-
- var tl = radius[0], tr = radius[1], br = radius[2], bl = radius[3];
-
- this.moveBy({x: 0, y: tl});
-
- if (end.x < 0) this.moveBy({x: end.x, y: 0});
- if (end.y < 0) this.moveBy({x: 0, y: end.y});
-
- if (tl > 0) this.roundCapLeftBy({x: tl, y: -tl});
- this.lineBy({x: Math.abs(end.x) - (tr + tl), y: 0});
-
- if (tr > 0) this.roundCapRightBy({x: tr, y: tr});
- this.lineBy({x: 0, y: Math.abs(end.y) - (tr + br)});
-
- if (br > 0) this.roundCapLeftBy({x: -br, y: br});
- this.lineBy({x: - Math.abs(end.x) + (br + bl), y: 0});
-
- if (bl > 0) this.roundCapRightBy({x: -bl, y: -bl});
- this.lineBy({x: 0, y: - Math.abs(end.y) + (bl + tl)});
- },
-
- pill: function(size){
- this.shape('rounded-rectangle', {x: size.x, y: size.y}, size[(size.x < size.y) ? 'x' : 'y'] / 2);
- }
-
-});
View
89 Source/ART.Shapes.js
@@ -0,0 +1,89 @@
+/*
+---
+
+name: ART.Shapes
+
+description: Shapes for ART
+
+authors: [Valerio Proietti](http://mad4milk.net)
+
+provides: [ART.Shapes, ART.Rectangle, ART.Pill, ART.Ellipse]
+
+requires: [ART.Path, ART.Shape]
+
+...
+*/
+
+ART.Rectangle = new Class({
+
+ Extends: ART.Shape,
+
+ initialize: function(width, height, radius){
+ this.parent();
+ if (width != null && height != null) this.draw(width, height, radius);
+ },
+
+ draw: function(width, height, radius){
+
+ var path = new ART.Path;
+
+ if (!radius){
+
+ path.move(0, 0).line(width, 0).line(0, height).line(-width, 0).line(0, -height);
+
+ } else {
+
+ if (typeof radius == 'number') radius = [radius, radius, radius, radius];
+
+ var tl = radius[0], tr = radius[1], br = radius[2], bl = radius[3];
+
+ path.move(0, tl);
+
+ if (width < 0) path.move(width, 0);
+ if (height < 0) path.move(0, height);
+
+ if (tl > 0) path.arcLeft(tl, -tl);
+ path.line(Math.abs(width) - (tr + tl), 0);
+
+ if (tr > 0) path.arcRight(tr, tr);
+ path.line(0, Math.abs(height) - (tr + br));
+
+ if (br > 0) path.arcLeft(-br, br);
+ path.line(- Math.abs(width) + (br + bl), 0);
+
+ if (bl > 0) path.arcRight(-bl, -bl);
+ path.line(0, - Math.abs(height) + (bl + tl));
+ }
+
+ return this.parent(path);
+ }
+
+});
+
+ART.Pill = new Class({
+
+ Extends: ART.Rectangle,
+
+ draw: function(width, height){
+ return this.parent(width, height, ((width < height) ? width : height) / 2);
+ }
+
+});
+
+ART.Ellipse = new Class({
+
+ Extends: ART.Shape,
+
+ initialize: function(width, height){
+ this.parent();
+ if (width != null && height != null) this.draw(width, height);
+ },
+
+ draw: function(width, height){
+ var path = new ART.Path;
+ var rx = width / 2, ry = height / 2;
+ path.move(0, ry).arcLeft(rx, -ry).arcRight(rx, ry).arcLeft(-rx, ry).arcRight(-rx, -ry);
+ return this.parent(path);
+ }
+
+});
View
508 Source/ART.VML.js
@@ -5,178 +5,430 @@ name: ART.VML
description: VML implementation for ART
-author: [Simo Kinnunen](http://twitter.com/sorccu)
+authors: [Simo Kinnunen](http://twitter.com/sorccu), [Valerio Proietti](http://mad4milk.net)
-provides: ART.VML
+provides: [ART.VML, ART.Group, ART.Shape]
-requires: ART
+requires: [ART, ART.Element, ART.Container]
...
*/
-ART.VML = new Class({
+(function(){
+
+try {
- initialize: function(id, width, height){
- this.element = new Element('canvas', {'id': id || 'c-' + $time()});
- this.precisionFactor = 10;
- this.halfPixel = Math.floor(this.precisionFactor / 2);
- this.resize({x: width, y: height});
- },
+ var namespaces = document.namespaces;
+
+ namespaces.add('av', 'urn:schemas-microsoft-com:vml');
+ namespaces.add('ao', 'urn:schemas-microsoft-com:office:office');
- resize: function(size){
- this.clear(); // for canvas compatibility
- var style = this.element.style;
- style.pixelWidth = size.x;
- style.pixelHeight = size.y;
- this.size = size;
- this.coordSize = {
- x: size.x * this.precisionFactor,
- y: size.y * this.precisionFactor
- };
- },
+ var sheet = document.createStyleSheet();
+ sheet.addRule('vml', 'display:inline-block;position:relative;overflow:hidden;');
+
+ sheet.addRule('av\\:*', 'behavior:url(#default#VML);display:inline-block;position:absolute;width:100%;height:100%;left:0px;top:0px;');
+ sheet.addRule('ao\\:*', 'behavior:url(#default#VML);');
- clear: function(){
- this.element.innerHTML = '';
- },
+} catch(e){
+
+ return;
+
+}
+
+var precision = 100, UID = 0;
+
+// VML Base Class
+
+ART.VML = new Class({
- start: function(){
- this.currentShape = document.createElement('av:shape');
- this.currentShape.coordorigin = this.halfPixel + ',' + this.halfPixel; // optimize for fills
- this.currentShape.coordsize = this.coordSize.x + ',' + this.coordSize.y;
- var style = this.currentShape.style;
- style.width = '100%';
- style.height = '100%';
- this.currentPath = [];
+ Extends: ART.Element,
+ Implements: ART.Container,
+
+ initialize: function(width, height){
+ this.element = document.createElement('vml');
+ this.children = [];
+ this.resize(width, height);
},
- end: function(style){
-
- this.outline(style.outline, style.outlineWidth, style.outlineCap, style.outlineJoin);
+ resize: function(width, height){
+ this.width = width;
+ this.height = height;
+ var style = this.element.style;
+ style.pixelWidth = width;
+ style.pixelHeight = height;
+
+ this.children.each(function(child){
+ child._transform();
+ });
- var fill = $splat(style.fill);
- this.fill(fill[0], fill[1], style.fillMode);
+ return this;
+ }
+
+});
+
+// VML Element Class
+
+ART.VML.Element = new Class({
+
+ Extends: ART.Element,
+
+ initialize: function(tag){
+ this.uid = (UID++).toString(16);
+ var element = this.element = document.createElement('av:' + tag);
+ element.setAttribute('id', 'e' + this.uid);
- if (style.shadow != null) this.shadow(style.shadow, style.shadowOffset, style.shadowBlur);
+ this.transform = {translate: [0, 0], scale: [1, 1], rotate: [0, 0, 0]};
+ },
+
+ /* dom */
+
+ inject: function(container){
+ this.eject();
+ this.container = container;
+ container.children.include(this);
+ this._transform();
+ this.parent(container);
- var stretch = 'm' + this.currentShape.coordorigin + 'l' + this.currentShape.coordsize;
- this.currentShape.path = this.currentPath.join('') + 'e' + stretch + 'nsnf';
- this.element.appendChild(this.currentShape);
+ return this;
},
- join: function(){
- this.currentPath.push('x');
+ eject: function(){
+ if (this.container){
+ this.container.children.erase(this);
+ this.container = null;
+ this.parent();
+ }
+ return this;
},
-
- move: function(vector){
- var p = this.precisionFactor;
- this.currentPath.push('m' + ~~(vector.x * p) + ',' + ~~(vector.y * p));
+
+ translate: function(x, y){
+ this.transform.translate = [x, y];
+ this._transform();
+ return this;
},
+
+ scale: function(x, y){
+ this.transform.scale = [x, y];
+ this._transform();
+ return this;
+ }
+
+});
- line: function(vector){
- var p = this.precisionFactor;
- this.currentPath.push('l' + ~~(vector.x * p) + ',' + ~~(vector.y * p));
- },
+// VML Group Class
- bezier: function(c1, c2, end){
- var p = this.precisionFactor;
- this.currentPath.push('c' + ~~(c1.x * p) + ',' + ~~(c1.y * p) + ',' + ~~(c2.x * p) + ',' + ~~(c2.y * p) + ',' + ~~(end.x * p) + ',' + ~~(end.y * p));
+ART.VML.Group = new Class({
+
+ Extends: ART.VML.Element,
+ Implements: ART.Container,
+
+ initialize: function(){
+ this.parent('group');
+ this.children = [];
},
- /* styles */
+ getBBox: function(){
+ var widths = [], heights = [];
+ this.children.each(function(child, i){
+ widths[i] = child.x + child.width + child.transform.translate[0];
+ heights[i] = child.y + child.height + child.transform.translate[1];
+ }, this);
+ return {x: 0, y: 0, width: Math.max.apply(Math, widths), height: Math.max.apply(Math, heights)};
+ },
+
+ /* dom */
+
+ inject: function(container){
+ this.parent(container);
+ this.width = container.width;
+ this.height = container.height;
+ },
+
+ eject: function(){
+ this.parent();
+ this.width = this.height = null;
+ },
+
+ _transform: function(){
+ var container = this.container;
+ if (!container) return;
+ var cw = container.width, ch = container.height, w = this.width, h = this.height, x = this.x, y = this.y;
+ if (cw == null || ch == null || w == null || h == null) return;
+
+ this.element.coordorigin = (precision) + ',' + (precision);
+ this.element.coordsize = (cw * precision) + ',' + (ch * precision);
+
+ this.children.each(function(child){
+ child._transform();
+ });
+ }
- fill: function(color1, color2, mode){
- var fill = document.createElement('av:fill'), on = false;
+});
- if (color1 != null){
-
- color1 = new Color(color1);
- var opacity1 = color1.get('alpha');
- fill.color = color1.set('alpha', 1).toString();
- fill.opacity = opacity1;
-
- if (color2 != null){
- fill.method = 'none';
- fill.type = 'gradient';
- var angle;
- if (mode == 'horizontal') angle = 270;
- else if (mode == 'vertical') angle = 180;
- fill.angle = angle;
-
- color2 = new Color(color2);
- var opacity2 = color2.get('alpha');
- fill.color2 = color2.set('alpha', 1).toString();
- fill['ao:opacity2'] = opacity2;
- }
+// VML Shape Class
- on = true;
- }
+ART.VML.Shape = new Class({
+
+ Extends: ART.VML.Element,
+
+ initialize: function(path){
+ this.parent('shape');
+ var shape = this.shape = this.element;
+ var element = this.element = document.createElement('av:group');
+ element.appendChild(shape);
+
+ var fill = this.fillElement = document.createElement('av:fill');
+ fill.on = false;
+ shape.appendChild(fill);
+
+ var stroke = this.strokeElement = document.createElement('av:stroke');
+ stroke.on = false;
+ shape.appendChild(stroke);
- fill.on = on;
- this.currentShape.appendChild(fill);
+ if (path != null) this.draw(path);
+ },
+
+ getBBox: function(){
+ return {x: this.x || 0, y: this.y || 0, width: this.width || 0, height: this.height || 0};
},
- outline: function(color, width, cap, join){
- var outline = document.createElement('av:stroke'), on = false;
+ // SVG parser
+
+ // Possible SVG syntaxes that we want to support
+ // M & L could be M L C Z m l c z
+ // separators can always be spaces, one comma, or any combination of spaces and one comma
+ // numbers can also be separated by a minus or plus sign. "100+100" means [100, 100], "100-100" means [100, -100]
+
+ // Inputs Examples
+
+ // 'M 100.5,-100.5 L 100,100' //space separator for methods, comma separators for vectors
+ // 'M100.5,-100.5L100,100' //no separator for methods, comma separators for vectors
+ // 'M100.5-100.5L100,100' //comma separator for vectors when needed (Adobe Illustrator)
+ // 'M100.5-100.5L100 100' //space separator for vectors when needed
+ // 'M 100.5 -100.5 L 100 -100' //space separator (ART.Path)
+ // 'M 100.5, -100.5 L 100, 100' //space separator for methods, comma + space separators for vectors
+ // 'M 100.5-100.5 L 100.5,100.5' //space separator for methods, comma separators for vectors when needed
+ // 'M 100.5,-100.5 L 100,100' //space separator for methods, comma separators for vectors
+
+ // Outoput
+
+ // any output would do, as long as it provides separated parts. These are a couple of examples:
+
+ // [['M', 100.5, -100.5], ['L', 100, -100]]
+
+ // [{method: 'M': vectors: [100.5, -100.5]}, {method: 'L', vectors: [100, -100]}]
+
+ draw: function(path){
+ this.boundsX = []; this.boundsY = [];
- if (color != null){
-
- if (width == null) width = 1;
- if (cap == null) cap = 'round';
- if (join == null) join = 'round';
-
- outline.weight = width;
- outline.endcap = (cap == 'butt') ? 'flat' : cap;
- outline.joinstyle = join;
-
- color = new Color(color);
- outline.color = color.copy().set('alpha', 1).toString();
- outline.opacity = color.get('alpha');
+ path = path.toString().replace(/\s*([A-Za-z,-])\s*/ig, function(f, m, i){
+ switch (m){
+ case '-': return ' ' + m;
+ case ',': return ' ';
+ default: return ' ' + m + ' ';
+ }
+ });
- on = true;
+ var parts = [], index = -1, i, bits = path.split(/\s+/), p = precision, p2 = p / 2;
+
+ for (i = 0; i < bits.length; i++){
+ var bit = bits[i], e;
+ if (bit.match(/[A-Za-z]/i)) parts[++index] = [bit];
+ else parts[index].push(Number(bit));
}
+
+ path = '';
+
+ var reflect = function(sx, sy, ex, ey){
+ return [ex * 2 - sx, ey * 2 - sy];
+ };
+
+ var X = 0, Y = 0, px = 0, py = 0, r;
+
+ for (i = 0; i < parts.length; i++){
+ var v = parts[i];
+
+ switch (v.shift()){
+
+ case 'm':
+ path += 'm' + this._ux(X += v[0]) + ',' + this._uy(Y += v[1]);
+ break;
+ case 'M':
+ path += 'm' + this._ux(X = v[0]) + ',' + this._uy(Y = v[1]);
+ break;
+
+ case 'l':
+ path += 'l' + this._ux(X += v[0]) + ',' + this._uy(Y += v[1]);
+ break;
+ case 'L':
+ path += 'l' + this._ux(X = v[0]) + ',' + this._uy(Y = v[1]);
+ break;
+
+ case 'c':
+ px = X + v[2]; py = Y + v[3];
+ path += 'c' + this._ux(X + v[0]) + ',' + this._uy(Y + v[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X += v[4]) + ',' + this._uy(Y += v[5]);
+ break;
+ case 'C':
+ px = v[2]; py = v[3];
+ path += 'c' + this._ux(v[0]) + ',' + this._uy(v[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X = v[4]) + ',' + this._uy(Y = v[5]);
+ break;
+
+ case 's':
+ r = reflect(px, py, X, Y);
+ px = X + v[0]; py = Y + v[1];
+ path += 'c' + this._ux(r[0]) + ',' + this._uy(r[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X += v[2]) + ',' + this._uy(Y += v[3]);
+ break;
+ case 'S':
+ r = reflect(px, py, X, Y);
+ px = v[0]; py = v[1];
+ path += 'c' + this._ux(r[0]) + ',' + this._uy(r[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X = v[2]) + ',' + this._uy(Y = v[3]);
+ break;
+
+ case 'q':
+ px = X + v[0]; py = Y + v[1];
+ path += 'c' + this._ux(X + v[0]) + ',' + this._uy(Y + v[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X += v[2]) + ',' + this._uy(Y += v[3]);
+ break;
+ case 'Q':
+ px = v[0]; py = v[1];
+ path += 'c' + this._ux(v[0]) + ',' + this._uy(v[1]) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X = v[2]) + ',' + this._uy(Y = v[3]);
+ break;
+
+ case 't':
+ r = reflect(px, py, X, Y);
+ px = X + r[0]; py = Y + r[1];
+ path += 'c' + this._ux(px) + ',' + this._uy(py) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X += v[0]) + ',' + this._uy(Y += v[1]);
+ break;
+ case 'T':
+ r = reflect(px, py, X, Y);
+ px = r[0]; py = r[1];
+ path += 'c' + this._ux(px) + ',' + this._uy(py) + ',' + this._ux(px) + ',' +
+ this._uy(py) + ',' + this._ux(X = v[0]) + ',' + this._uy(Y = v[1]);
+ break;
+
+ case 'h':
+ path += 'l' + this._ux(X += v[0]) + ',' + this._uy(Y);
+ break;
+ case 'H':
+ path += 'l' + this._ux(X = v[0]) + ',' + this._uy(Y);
+ break;
+
+ case 'v':
+ path += 'l' + this._ux(X) + ',' + this._uy(Y += v[0]);
+ break;
+ case 'V':
+
+ path += 'l' + this._ux(X) + ',' + this._uy(Y = v[0]);
+ break;
+
+ case 'z':
+ path += 'x';
+ break;
+ case 'Z':
+ path += 'x';
+ break;
+
+ }
+ }
+
+ this.width = Math.max.apply(Math, this.boundsX);
+ this.height = Math.max.apply(Math, this.boundsY);
+ this.x = Math.min.apply(Math, this.boundsX);
+ this.y = Math.min.apply(Math, this.boundsY);
+
+ this._transform();
- outline.on = on;
- this.currentShape.appendChild(outline);
+ this.shape.path = path + 'e';
+ return this;
},
- shadow: function(color, offset, blur){
- // The VML shadow element works correctly in terms of offsets, opacity and color. However, it does not support blur.
- if (blur != 0) return;
- var shadow = document.createElement('av:shadow');
- color = new Color(color);
- var alpha = color.get('alpha');
- shadow.color = color.set('alpha', 1).toString();
- shadow.opacity = alpha;
- shadow.offset = offset.x + 'px,' + offset.y + 'px';
- shadow.on = true;
- this.currentShape.appendChild(shadow);
+ _ux: function(x){
+ this.boundsX.push(x);
+ return Math.round(x * precision);
},
- /* $ */
+ _uy: function(y){
+ this.boundsY.push(y);
+ return Math.round(y * precision);
+ },
- toElement: function(){
- return this.element;
- }
-
-});
+ /* transform */
+
+ _transform: function(){
+ var container = this.container;
+ if (!container) return;
+ var cw = container.width, ch = container.height, w = this.width, h = this.height, x = this.x, y = this.y;
+ if (cw == null || ch == null || w == null || h == null) return;
+
+ var p = precision, hp = p / 2;
+ var ct = this.container.transform, cts = (ct) ? ct.scale : [1, 1], ctt = (ct) ? ct.translate : [0, 0];
+ var ttt = this.transform.translate, tts = this.transform.scale;
+
+ // translate + halfpixel
+ this.element.coordorigin = (-((ctt[0] + (cts[0] * ttt[0])) * p) + hp) + ',' + (-((ctt[1] + (cts[1] * ttt[1])) * p) + hp);
+ this.shape.coordorigin = '0,0';
+
+ // scale
+ this.element.coordsize = (cw * p) + ',' + (ch * p);
+ this.shape.coordsize = ((cw * p) / (cts[0] * tts[0])) + ',' + ((ch * p) / (cts[1] * tts[1]));
+ },
+
+ /* styles */
+
+ fill: function(flag){
+ var fill = this.fillElement;
-// create XMLNS
+ if (flag == null){
+ fill.on = false;
+ } else {
+ var color1 = Color.detach(arguments[0]);
+ fill.color = color1[0];
+ fill.opacity = color1[1];
+
+ if (arguments.length > 1){
+ fill.method = 'none';
+ fill.type = 'gradient';
+ var color2 = Color.detach(arguments[arguments.length - 1]);
+ fill.angle = 180; //TODO angle
+ fill.color2 = color2[0];
+ fill['ao:opacity2'] = color2[1];
+ } else {
+ fill.color2 = null;
+ fill['ao:opacity2'] = null;
+ }
+
+ fill.on = true;
+ }
-(function(){
+ return this;
+ },
-var namespaces = document.namespaces;
-
-if (namespaces == null) return;
+ stroke: function(flag){
+ var stroke = this.strokeElement;
-namespaces.add('av', 'urn:schemas-microsoft-com:vml');
-namespaces.add('ao', 'urn:schemas-microsoft-com:office:office');
+ if (flag == null){
+ stroke.on = false;
+ } else {
+ var color = Color.detach(arguments[0]);
+ stroke.color = color[0];
+ stroke.opacity = color[1];
+ stroke.on = true;
+ }
+ return this;
+ }
-var sheet = document.createStyleSheet();
-sheet.addRule('canvas', 'display:inline-block;position:relative;');
+});
-sheet.addRule('av\\:*', 'behavior:url(#default#VML);display:inline-block;position:absolute;');
-sheet.addRule('ao\\:*', 'behavior:url(#default#VML);');
+// Assign to ART
-ART.registerAdapter(ART.VML);
+ART.Shape = new Class({Extends: ART.VML.Shape});
+ART.Group = new Class({Extends: ART.VML.Group});
+ART.implement({Extends: ART.VML});
})();
View
206 Source/ART.js
@@ -5,9 +5,9 @@ name: ART
description: The heart of ART.
-authors: [Valerio Proietti](http://mad4milk.net) && [MooTools development team](http://mootools.net/developers)
+authors: [Valerio Proietti](http://mad4milk.net), [The MooTools development team](http://mootools.net/developers)
-provides: ART
+provides: [ART, ART.Element, ART.Container]
...
*/
@@ -16,184 +16,74 @@ provides: ART
Math.kappa = (4 * (Math.sqrt(2) - 1) / 3);
-/* # ART */
+var ART = new Class;
-var ART = new Class({
+ART.Element = new Class({
- style: {
- 'fill': null,
- 'fill-mode': 'vertical',
- 'outline': null,
- 'outline-width': 1,
- 'outline-cap': 'round',
- 'outline-join': 'round',
- 'shadow': null,
- 'shadow-blur': 0,
- 'shadow-offset': {x: 0, y: 0}
- },
-
- initialize: function(options){
- options = options || {};
- if (!options.height) options.height = 240;
- if (!options.width) options.width = 320;
- if (!options.id) options.id = 'art-' + $time();
- var Adapter = (!options.adapter) ? ART.recoverAdapter() : options.adapter;
-
- if (!Adapter) new Error('No suitable adapter found.');
-
- this.adapter = new Adapter(options.id, options.width, options.height);
-
- this.stack = {global: []};
- this.global = {x: 0, y: 0};
- this.shift({x: 0, y: 0});
- },
-
- resize: function(vector){
- this.adapter.resize(vector);
+ /* dom */
+
+ inject: function(element){
+ if (element.toElement) element = element.toElement();
+ element.appendChild(this.element);
return this;
},
- /* beginning a layer and ending a layer */
-
- start: function(vector){
- vector = vector || {x: 0, y: 0};
-
- this.started = true;
-
- this.stack.local = [];
- this.stack.pointer = [];
-
- this.local = {x: 0, y: 0};
- this.pointer = {x: 0, y: 0};
- this.adapter.start();
- return this.shift(vector);
- },
-
- end: function(style){
- this.started = false;
- this.adapter.end(this.sanitizeStyle(style));
+ eject: function(){
+ var parent = this.element.parentNode;
+ if (parent) parent.removeChild(this.element);
return this;
},
- /* origin shifting */
+ /* attributes */
- shift: function(vector){
- if (this.started){
- this.local = {x: this.local.x + vector.x, y: this.local.y + vector.y};
- this.moveBy({x: 0, y: 0});
- } else {
- this.global = {x: this.global.x + vector.x, y: this.global.y + vector.y};
- }
-
+ set: function(k, v){
+ var element = this.toElement();
+ if (typeof k != 'string') for (var p in k) this.set(p, k[p]);
+ else element.setAttribute(k.hyphenate(), v);
return this;
},
- /* states */
-
- save: function(){
- if (this.started){
- this.stack.pointer.push(this.pointer);
- this.stack.local.push(this.local);
+ get: function(a){
+ var element = this.toElement();
+ if (arguments.length > 1){
+ var res = {};
+ for (var i = 0; i < arguments.length; i++){
+ var argCC = arguments[i].camelCase();
+ res[argCC] = element.getAttribute(arg.hyphenate());
+ }
+ return res;
} else {
- this.stack.global.push(this.global);
+ return this.element.getAttribute(a.hyphenate());
}
-
- return this;
- },
-
- restore: function(){
- if (this.started){
- var pointerVector = this.stack.pointer.pop();
- var localVector = this.stack.local.pop();
- this.local = localVector;
- this.moveTo(pointerVector);
- } else {
- var globalVector = this.stack.global.pop();
- this.global = globalVector;
- }
-
- return this;
- },
-
- join: function(){
- this.adapter.join();
- return this;
- },
-
- /* to methods */
-
- moveTo: function(vector){
- this.pointer = vector;
- this.adapter.move(this.updateVector(vector));
- return this;
- },
-
- lineTo: function(vector){
- this.updateVector(this.pointer);
- this.pointer = vector;
- this.adapter.line(this.updateVector(vector));
- return this;
- },
-
- bezierTo: function(c1, c2, end){
- this.updateVector(this.pointer);
- this.pointer = end;
- this.adapter.bezier(this.updateVector(c1), this.updateVector(c2), this.updateVector(end));
- return this;
- },
-
- /* by methods */
-
- moveBy: function(vector){
- return this.moveTo({x: this.pointer.x + vector.x, y: this.pointer.y + vector.y});
- },
-
- lineBy: function(vector){
- return this.lineTo({x: this.pointer.x + vector.x, y: this.pointer.y + vector.y});
- },
-
- bezierBy: function(c1, c2, end){
- var n = this.pointer;
- return this.bezierTo({x: c1.x + n.x, y: c1.y + n.y}, {x: c2.x + n.x, y: c2.y + n.y}, {x: end.x + n.x, y: end.y + n.y});
- },
-
- /* "protected" */
-
- updateVector: function(vector){
- return {x: this.global.x + this.local.x + vector.x, y: this.global.y + this.local.y + vector.y};
- },
-
- sanitizeStyle: function(style){
- var tSCC = {}, sCC = {}, p;
- for (p in this.style) tSCC[p.camelCase()] = this.style[p];
-
- for (p in style){
- var pCC = p.camelCase();
- if (pCC in tSCC) sCC[pCC] = style[p];
- }
-
- return $extend(tSCC, sCC);
},
/* $ */
-
+
toElement: function(){
- return this.adapter.toElement();
+ return this.element;
}
-
+
});
-(function(){
+ART.Container = new Class({
-var adapter = null;
+ push: function(){
+ for (var i = 0; i < arguments.length; i++) arguments[i].inject(this);
+ return this;
+ },
+
+ pull: function(){
+ var element = (this.toElement) ? this.toElement() : null;
+ for (var i = 0; i < arguments.length; i++){
+ var child = arguments[i], parent = child.parentNode;
+ if (child.parentNode && child.parentNode === element) child.eject();
+ }
+ return this;
+ }
-ART.registerAdapter = function(klass){
- if (!adapter) adapter = klass;
- return ART;
-};
+});
-ART.recoverAdapter = function(){
- return adapter;
+Color.detach = function(color){
+ color = new Color(color); var alpha = color.get('alpha');
+ return [color.set('alpha', 1).toString(), alpha];
};
-
-})();
View
9 package.yml
@@ -14,9 +14,10 @@ authors: "[Valerio Proietti](http://mad4milk.net) && [MooTools development team]
sources:
- "Source/ART.js"
- - "Source/ART.Canvas.js"
+ - "Source/ART.SVG.js"
- "Source/ART.VML.js"
- - "Source/ART.Shape.js"
+ - "Source/ART.Path.js"
+ - "Source/ART.Shapes.js"
- "Source/ART.Font.js"
- - "Fonts/MgOpen.Moderna.js"
- - "Fonts/MgOpen.Moderna.Bold.js"
+ - "Fonts/Moderna.js"
+ - "Fonts/Moderna.Bold.js"

1 comment on commit 18e2166

@ibolmo

Woo! Congrats

Please sign in to comment.