]> source.dussan.org Git - svg.js.git/commitdiff
Implemented core library
authorwout <wout@impinc.co.uk>
Sun, 16 Dec 2012 15:15:47 +0000 (16:15 +0100)
committerwout <wout@impinc.co.uk>
Sun, 16 Dec 2012 15:15:47 +0000 (16:15 +0100)
18 files changed:
Rakefile
src/circle.js [new file with mode: 0644]
src/clip_path.js
src/container.js
src/defs.js
src/dispatcher.js
src/document.js
src/draggable.js
src/element.js
src/ellipse.js [new file with mode: 0644]
src/group.js
src/image.js
src/nested.js
src/object.js
src/path.js [new file with mode: 0644]
src/rect.js [new file with mode: 0644]
src/shape.js
src/svg.js

index 7eac6695f4ae916c8f2046ff4dc3f653b55f2cd8..f9ef0fface36cd0d0c67a4ec493cb1231dba749c 100644 (file)
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,6 @@
 SVGJS_VERSION = '0.1'
 
-DEFAULT_MODULES = %w[ svg ]
+DEFAULT_MODULES = %w[ svg container dispatcher draggable object element document defs group nested clip_path shape rect circle ellipse path image ]
 
 KILO = 1024   # how many bytes in a "kilobyte"
 
@@ -8,6 +8,7 @@ task :default => :dist
 
 # module-aware file task
 class BuildTask < Rake::FileTask
+  
   def modules
     prerequisites.map {|f| File.basename(f, '.js') }
   end
@@ -28,24 +29,33 @@ class BuildTask < Rake::FileTask
   end
 
   def first_line
-    File.open(name, 'r') {|f| f.gets }
+    File.open(name, 'r') { |f| f.gets }
   end
+  
 end
 
 BuildTask.define_task 'dist/svg.js' => DEFAULT_MODULES.map {|m| "src/#{ m }.js" } do |task|
   mkdir_p 'dist', :verbose => false
-  File.open(task.name, 'w') do |svgjs|
-    svgjs.puts "/* svg.js %s - %s - svgjs.com/license */" %
-                [version_string, task.modules.join(' ')]
-
-    task.prerequisites.each do |src|
-      # bring in source files one by one, but without copyright info
-      copyright = true
-      File.open(src).each_line do |line|
-        copyright = false if copyright and line !~ %r{^(/|\s*$)}
-        svgjs.puts line unless copyright
-      end
+  
+  svgjs = ''
+  
+  task.prerequisites.each do |src|
+    # bring in source files one by one, but without copyright info
+    copyright = true
+    File.open(src).each_line do |line|
+      copyright = false if copyright and line !~ %r{^(/|\s*$)}
+      svgjs << "  #{ line }" unless copyright
     end
+    svgjs << "\n\n"
+  end
+  
+  File.open(task.name, 'w') do |file|
+    file.puts "/* svg.js %s - %s - svgjs.com/license */" % [version_string, task.modules.join(' ')]
+
+    file.puts '(function() {'
+    file.puts "\n"
+    file.puts svgjs
+    file.puts '}).call(this);'
   end
 end
 
diff --git a/src/circle.js b/src/circle.js
new file mode 100644 (file)
index 0000000..7d1fbee
--- /dev/null
@@ -0,0 +1,32 @@
+
+SVG.Circle = function Circle() {
+  this.constructor.call(this, SVG.createElement('circle'));
+};
+
+// inherit from SVG.Shape
+SVG.Circle.prototype = new SVG.Shape();
+
+// custom move function
+SVG.Circle.prototype.move = function(x, y) {
+  this.attributes.x = x;
+  this.attributes.y = y;
+  this._center();
+  
+  return this;
+};
+
+// custom size function
+SVG.Circle.prototype.size = function(w, h) {
+  this.setAttribute('r', w / 2);
+  this._center();
+  
+  return this;
+};
+
+// private: center 
+SVG.Circle.prototype._center = function() {
+  var r = this.attributes.r || 0;
+  
+  this.setAttribute('cx', (this.attributes.x || 0) + r);
+  this.setAttribute('cy', (this.attributes.y || 0) + r);
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2eece4962f7c8cb08d819d2905c3f6d7ed5f9e24 100644 (file)
@@ -0,0 +1,14 @@
+// initialize id sequence
+var clipID = 0;
+
+SVG.ClipPath = function ClipPath() {
+  this.constructor.call(this, SVG.createElement('clipPath'));
+  this.id = '_' + (clipID++);
+  this.setAttribute('id', this.id);
+};
+
+// inherit from SVG.Element
+SVG.ClipPath.prototype = new SVG.Element();
+
+// include the container object
+SVG.ClipPath.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..339e5549ca2cf2baa0725edaf2104efdfb2b8998 100644 (file)
@@ -0,0 +1,138 @@
+
+SVG.Container = {
+  
+  add: function(e) {
+    return this.addAt(e);
+  },
+  
+  addAt: function(e, i) {
+    if (!this.contains(e)) {
+      i = i == null ? this.children().length : i;
+      this.children().splice(i, 0, e);
+      this.svgElement.insertBefore(e.svgElement, this.svgElement.childNodes[i + 1]);
+      e.parent = this;
+    }
+    
+    return this;
+  },
+  
+  contains: function(e) {
+    return Array.prototype.indexOf.call(this.children(), e) >= 0;
+  },
+  
+  children: function() {
+    return this._children || [];
+  },
+  
+  sendBack: function(e) {
+    var i = this.children().indexOf(e);
+    if (i !== -1)
+      return this.remove(e).addAt(e, i - 1);
+  },
+  
+  bringForward: function(e) {
+    var i = this.children().indexOf(e);
+    if (i !== -1)
+      return this.remove(e).addAt(e, i + 1);
+  },
+  
+  bringToFront: function(e) {
+    if (this.contains(e))
+      this.remove(e).add(e);
+    
+    return this;
+  },
+  
+  sendToBottom: function(e) {
+    if (this.contains(e))
+      this.remove(e).addAt(e, 0);
+    
+    return this;
+  },
+  
+  remove: function(e) {
+    return this.removeAt(this.children().indexOf(e));
+  },
+  
+  removeAt: function(i) {
+    if (0 <= i && i < this.children().length) {
+      var e = this.children()[i];
+      this.children().splice(i, 1);
+      this.svgElement.removeChild(e.svgElement);
+      e.parent = null;
+    }
+    
+    return this;
+  },
+  
+  defs: function() {
+    if (this._defs == null) {
+      this._defs = new SVG.Defs();
+      this.add(this._defs);
+    }
+    
+    return this._defs;
+  },
+  
+  group: function() {
+    var e = new SVG.Group();
+    this.add(e);
+    
+    return e;
+  },
+  
+  svg: function(v) {
+    return this.place(new SVG.Nested(), v);
+  },
+  
+  rect: function(v) {
+    return this.place(new SVG.Rect(), v);
+  },
+  
+  circle: function(v) {
+    return this.place(new SVG.Circle(), {
+      x: v != null ? v.x : void 0,
+      y: v != null ? v.y : void 0,
+      width: (v != null ? (v.width || v.r || v.radius) : void 0),
+      height: null
+    });
+  },
+  
+  ellipse: function(v) {
+    return this.place(new SVG.Ellipse(), {
+      x: v != null ? v.x : void 0,
+      y: v != null ? v.y : void 0,
+      width:  (v != null ? (v.width  || v.rx || v.radiusX) : void 0),
+      height: (v != null ? (v.height || v.ry || v.radiusY) : void 0)
+    });
+  },
+  
+  path: function(v) {
+    return this.place(new SVG.Path(), v);
+  },
+  
+  image: function(v) {
+    return this.place(new SVG.Image(), v);
+  },
+  
+  place: function(e, v) {
+    if (v != null) {
+      if (v.x != null && v.y != null)
+        e.move(v.x, v.y);
+      
+      if (v.width != null && v.height != null)
+        e.size(v.width, v.height);
+      
+      if (v.data != null)
+        e.data(v.data);
+      
+      if (v.src != null)
+        e.load(v.src);
+    }
+    
+    this.add(e);
+    
+    return e;
+  }
+  
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4661a54dc580b1b15a3374883dfad9d68da1ac1d 100644 (file)
@@ -0,0 +1,17 @@
+SVG.Defs = function Defs() {
+  this.constructor.call(this, SVG.createElement('defs'));
+};
+
+// inherit from SVG.Element
+SVG.Defs.prototype = new SVG.Element();
+
+// define clippath
+SVG.Defs.prototype.clipPath = function() {
+  var e = new SVG.ClipPath();
+  this.add(e);
+  
+  return e;
+};
+
+// include the container object
+SVG.Defs.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..27656525abdc28ec1129939cd5fe26dd6aebc859 100644 (file)
@@ -0,0 +1,17 @@
+SVG.Dispatcher = {
+  
+  on: function(events, listener) {
+    events = events.split(' ');
+    
+    for (var i = 0, l = events.length; i < l; i++)
+      this.svgElement.addEventListener(events[i], listener)
+  },
+  
+  off: function(events, listener) {
+    events = events.split(' ');
+    
+    for (var i = 0, l = events.length; i < l; i++)
+      this.svgElement.removeEventListener(events[i], listener)
+  }
+  
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a510c447a29d41e3668f1871bcf430195ae0b036 100644 (file)
@@ -0,0 +1,16 @@
+
+SVG.Document = function Document(c) {
+  this.constructor.call(this, SVG.createElement('svg'));
+  
+  this.setAttribute('xmlns', SVG.namespace);
+  this.setAttribute('version', '1.1');
+  this.setAttribute('xlink', 'http://www.w3.org/1999/xlink', SVG.namespace);
+  
+  document.getElementById(c).appendChild(this.svgElement);
+};
+
+// inherit from SVG.Element
+SVG.Document.prototype = new SVG.Element();
+
+// include the container object
+SVG.Document.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b0deac7974b661a85b5fcacf9bd246e2642c92cf 100644 (file)
@@ -0,0 +1,46 @@
+
+var bind = function(fn, me) {
+  return function() { return fn.apply(me, arguments); };
+};
+
+SVG.Draggable = function Draggable(e) {
+  this._windowMouseUp = bind(this._windowMouseUp, this);
+  this._windowMouseMove = bind(this._windowMouseMove, this);
+  this.draggable = bind(this.draggable, this);
+  this.element = e;
+  this.element.draggable = this.draggable;
+};
+
+SVG.Draggable.prototype.draggable = function() {
+  var self = this;
+  this.element.on('mousedown', function(e) {
+    self.startDragEvent = e;
+    self.startDragPosition = {
+      x: self.element.attributes.x || 0,
+      y: self.element.attributes.y || 0
+    };
+    window.addEventListener('mousemove', self._windowMouseMove);
+    window.addEventListener('mouseup', self._windowMouseUp);
+    return typeof self.element.dragstart === 'function' ? self.element.dragstart(e) : void 0;
+  });
+  return this.element;
+};
+
+SVG.Draggable.prototype._windowMouseMove = function(e) {
+  if (this.startDragEvent != null) {
+    var d = {
+      x: e.pageX - this.startDragEvent.pageX,
+      y: e.pageY - this.startDragEvent.pageY
+    };
+    this.element.move(this.startDragPosition.x + d.x, this.startDragPosition.y + d.y);
+    return typeof this.element.dragmove === 'function' ? this.element.dragmove(d, e) : void 0;
+  }
+};
+
+SVG.Draggable.prototype._windowMouseUp = function(e) {
+  this.startDragEvent = null;
+  this.startDragPosition = null;
+  window.removeEventListener('mousemove', this._windowMouseMove);
+  window.removeEventListener('mouseup', this._windowMouseUp);
+  return typeof this.element.dragend === 'function' ? this.element.dragend(e) : void 0;
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d38e3233de2148e9addf3aa1c3e0b17eca16cc23 100644 (file)
@@ -0,0 +1,87 @@
+
+SVG.Element = function Element(svgElement) {
+  this.svgElement = svgElement;
+  this.attributes = {};
+};
+
+//-D // inherit from SVG.Object
+//-D SVG.Element.prototype = new SVG.Object();
+
+// move element to given x and y values
+SVG.Element.prototype.move = function(x, y) {
+  this.setAttribute('x', x);
+  this.setAttribute('y', y);
+  
+  return this;
+};
+
+// set element opacity
+SVG.Element.prototype.opacity = function(o) {
+  return this.setAttribute('opacity', Math.max(0, Math.min(1, o)));
+};
+
+// set element size to given width and height
+SVG.Element.prototype.size = function(w, h) {
+  this.setAttribute('width', w);
+  this.setAttribute('height', h);
+  
+  return this;
+};
+
+// clip element using another element
+SVG.Element.prototype.clip = function(block) {
+  var p = this.parentSVG().defs().clipPath();
+  block(p);
+  
+  return this.clipTo(p);
+};
+
+// distribute clipping path to svg element
+SVG.Element.prototype.clipTo = function(p) {
+  return this.setAttribute('clip-path', 'url(#' + p.id + ')');
+};
+
+// remove element
+SVG.Element.prototype.destroy = function() {
+  return this.parent != null ? this.parent.remove(this) : void 0;
+};
+
+// get parent document
+SVG.Element.prototype.parentDoc = function() {
+  return this._findParent(SVG.Document);
+};
+
+// get parent svg wrapper
+SVG.Element.prototype.parentSVG = function() {
+  return this._findParent(SVG.Nested) || this.parentDoc();
+};
+
+// set svg element attribute
+SVG.Element.prototype.setAttribute = function(a, v, ns) {
+  this.attributes[a] = v;
+  
+  if (ns != null)
+    this.svgElement.setAttributeNS(ns, a, v);
+  else
+    this.svgElement.setAttribute(a, v);
+  
+  return this;
+};
+
+// get bounding box
+SVG.Element.prototype.getBBox = function() {
+  return this.svgElement.getBBox();
+};
+
+// private: find svg parent
+SVG.Element.prototype._findParent = function(pt) {
+  var e = this;
+  
+  while (e != null && !(e instanceof pt))
+    e = e.parent;
+  
+  return e;
+};
+
+// include the dispatcher object
+SVG.Element.include(SVG.Dispatcher);
\ No newline at end of file
diff --git a/src/ellipse.js b/src/ellipse.js
new file mode 100644 (file)
index 0000000..9e03277
--- /dev/null
@@ -0,0 +1,30 @@
+
+SVG.Ellipse = function Ellipse() {
+  this.constructor.call(this, SVG.createElement('ellipse'));
+};
+
+// inherit from SVG.Shape
+SVG.Ellipse.prototype = new SVG.Shape();
+
+// custom move function
+SVG.Ellipse.prototype.move = function(x, y) {
+  this.attributes.x = x;
+  this.attributes.y = y;
+  this._center();
+  
+  return this;
+};
+
+// custom size function
+SVG.Ellipse.prototype.size = function(w, h) {
+  this.setAttribute('rx', w / 2);
+  this.setAttribute('ry', h / 2);
+  this._center();
+  
+  return this; 
+};
+
+SVG.Ellipse.prototype._center = function() {
+  this.setAttribute('cx', (this.attributes.x || 0) + (this.attributes.rx || 0));
+  this.setAttribute('cy', (this.attributes.y || 0) + (this.attributes.ry || 0));
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e46035f2bec42409a770810dd17372333ba7ca5f 100644 (file)
@@ -0,0 +1,16 @@
+
+SVG.Group = function Group() {
+  this.constructor.call(this, SVG.createElement("g"));
+};
+
+// inherit from SVG.Element
+SVG.Group.prototype = new SVG.Element();
+
+// group rotation
+SVG.Group.prototype.rotate = function(d) {
+  this.setAttribute('transform', 'rotate(' + d + ')');
+  return this;
+};
+
+// include the container object
+SVG.Group.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ff70aeedd33d21210efe7b0e912b128b1c922f54 100644 (file)
@@ -0,0 +1,17 @@
+
+SVG.Image = function Image() {
+  this.drag = new SVG.Draggable(this);
+  this.constructor.call(this, SVG.createElement('image'));
+};
+
+// inherit from SVG.Element
+SVG.Image.prototype = new SVG.Element();
+
+// (re)load image
+SVG.Image.prototype.load = function(url) {
+  this.setAttribute('href', url, SVG.xlink);
+  return this;
+};
+
+// include the container object
+SVG.Image.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6245ca61c4f2234cc4aa266994e7e2a1ab9d7e86 100644 (file)
@@ -0,0 +1,12 @@
+
+SVG.Nested = function Nested() {
+  this.drag = new SVG.Draggable(this);
+  this.constructor.call(this, SVG.createElement('svg'));
+  this.setAttribute('overflow', 'visible');
+};
+
+// inherit from SVG.Element
+SVG.Nested.prototype = new SVG.Element();
+
+// include the container object
+SVG.Nested.include(SVG.Container);
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ecf43ee90cda69b9b97c637518d2490ce534eac0 100644 (file)
@@ -0,0 +1,11 @@
+
+Object.prototype.include = function(module) {
+  
+  for (var key in module)
+    this.prototype[key] = module[key];
+  
+  if (module.included != null)
+    module.included.apply(this);
+  
+  return this;
+};
\ No newline at end of file
diff --git a/src/path.js b/src/path.js
new file mode 100644 (file)
index 0000000..c064a91
--- /dev/null
@@ -0,0 +1,13 @@
+
+SVG.Path = function Path() {
+  this.constructor.call(this, SVG.createElement('path'));
+};
+
+// inherit from SVG.Shape
+SVG.Path.prototype = new SVG.Shape();
+
+// set path data
+SVG.Path.prototype.data = function(d) {
+  this.setAttribute('d', d);
+  return this;
+};
\ No newline at end of file
diff --git a/src/rect.js b/src/rect.js
new file mode 100644 (file)
index 0000000..b08d68e
--- /dev/null
@@ -0,0 +1,7 @@
+
+SVG.Rect = function Rect() {
+  this.constructor.call(this, SVG.createElement('rect'));
+};
+
+// inherit from SVG.Shape
+SVG.Rect.prototype = new SVG.Shape();
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8295f1c482d7bee125d04be624bfcbc352b011b1 100644 (file)
@@ -0,0 +1,51 @@
+
+SVG.Shape = function Shape(element) {
+  this.drag = new SVG.Draggable(this);
+  this.constructor.call(this, element);
+};
+
+// inherit from SVG.Element
+SVG.Shape.prototype = new SVG.Element();
+
+// set fill color and opacity
+SVG.Shape.prototype.fill = function(fill) {
+  this._formatColor(fill);
+  
+  if (fill.color != null)
+    this.setAttribute('fill', fill.color);
+  
+  if (fill.opacity != null)
+    this.setAttribute('fill-opacity', fill.opacity);
+  
+  return this;
+};
+
+// set stroke color and opacity
+SVG.Shape.prototype.stroke = function(stroke) {
+  this._formatColor(stroke);
+  
+  if (stroke.color != null)
+    this.setAttribute('stroke', stroke.color);
+  
+  if (stroke.width != null)
+    this.setAttribute('stroke-width', stroke.width);
+  
+  if (stroke.opacity != null)
+    this.setAttribute('stroke-opacity', stroke.opacity);
+  
+  if (this.attributes['fill-opacity'] == null)
+    this.fill({ opacity: 0 });
+  
+  return this;
+};
+
+// ensure correct color string
+SVG.Shape.prototype._formatColor = function(obj) {
+  if (typeof obj.color === 'number') {
+    obj.color = '' + obj.color.toString(16);
+    while (obj.color.length < 6)
+      obj.color = '0' + obj.color;
+    
+    return obj.color = '#' + obj.color;
+  }
+};
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4f17c926e6f733671901a0ed4f3dd54662a3f526 100644 (file)
@@ -0,0 +1,11 @@
+
+var SVG = {
+  namespace: "http://www.w3.org/2000/svg",
+  xlink:     "http://www.w3.org/1999/xlink",
+  
+  createElement: function(e) {
+    return document.createElementNS(this.namespace, e);
+  }
+};
+
+this.SVG = SVG;
\ No newline at end of file