272 lines
7.6 KiB
JavaScript
272 lines
7.6 KiB
JavaScript
|
|
SVG.Element = SVG.invent({
|
|
// Initialize node
|
|
create: function(node) {
|
|
// make stroke value accessible dynamically
|
|
this._stroke = SVG.defaults.attrs.stroke
|
|
this._event = null
|
|
this._events = {}
|
|
|
|
// initialize data object
|
|
this.dom = {}
|
|
|
|
// create circular reference
|
|
if (this.node = node) {
|
|
this.type = node.nodeName
|
|
this.node.instance = this
|
|
this._events = node._events || {}
|
|
|
|
// store current attribute value
|
|
this._stroke = node.getAttribute('stroke') || this._stroke
|
|
}
|
|
}
|
|
|
|
// Add class methods
|
|
, extend: {
|
|
// Move over x-axis
|
|
x: function(x) {
|
|
return this.attr('x', x)
|
|
}
|
|
// Move over y-axis
|
|
, y: function(y) {
|
|
return this.attr('y', y)
|
|
}
|
|
// Move by center over x-axis
|
|
, cx: function(x) {
|
|
return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
|
|
}
|
|
// Move by center over y-axis
|
|
, cy: function(y) {
|
|
return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)
|
|
}
|
|
// Move element to given x and y values
|
|
, move: function(x, y) {
|
|
return this.x(x).y(y)
|
|
}
|
|
// Move element by its center
|
|
, center: function(x, y) {
|
|
return this.cx(x).cy(y)
|
|
}
|
|
// Set width of element
|
|
, width: function(width) {
|
|
return this.attr('width', width)
|
|
}
|
|
// Set height of element
|
|
, height: function(height) {
|
|
return this.attr('height', height)
|
|
}
|
|
// Set element size to given width and height
|
|
, size: function(width, height) {
|
|
var p = proportionalSize(this, width, height)
|
|
|
|
return this
|
|
.width(new SVG.Number(p.width))
|
|
.height(new SVG.Number(p.height))
|
|
}
|
|
// Clone element
|
|
, clone: function(parent) {
|
|
// write dom data to the dom so the clone can pickup the data
|
|
this.writeDataToDom()
|
|
|
|
// clone element and assign new id
|
|
var clone = assignNewId(this.node.cloneNode(true))
|
|
|
|
// insert the clone in the given parent or after myself
|
|
if(parent) parent.add(clone)
|
|
else this.after(clone)
|
|
|
|
return clone
|
|
}
|
|
// Remove element
|
|
, remove: function() {
|
|
if (this.parent())
|
|
this.parent().removeElement(this)
|
|
|
|
return this
|
|
}
|
|
// Replace element
|
|
, replace: function(element) {
|
|
this.after(element).remove()
|
|
|
|
return element
|
|
}
|
|
// Add element to given container and return self
|
|
, addTo: function(parent) {
|
|
return parent.put(this)
|
|
}
|
|
// Add element to given container and return container
|
|
, putIn: function(parent) {
|
|
return parent.add(this)
|
|
}
|
|
// Get / set id
|
|
, id: function(id) {
|
|
return this.attr('id', id)
|
|
}
|
|
// Checks whether the given point inside the bounding box of the element
|
|
, inside: function(x, y) {
|
|
var box = this.bbox()
|
|
|
|
return x > box.x
|
|
&& y > box.y
|
|
&& x < box.x + box.width
|
|
&& y < box.y + box.height
|
|
}
|
|
// Show element
|
|
, show: function() {
|
|
return this.style('display', '')
|
|
}
|
|
// Hide element
|
|
, hide: function() {
|
|
return this.style('display', 'none')
|
|
}
|
|
// Is element visible?
|
|
, visible: function() {
|
|
return this.style('display') != 'none'
|
|
}
|
|
// Return id on string conversion
|
|
, toString: function() {
|
|
return this.attr('id')
|
|
}
|
|
// Return array of classes on the node
|
|
, classes: function() {
|
|
var attr = this.attr('class')
|
|
|
|
return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)
|
|
}
|
|
// Return true if class exists on the node, false otherwise
|
|
, hasClass: function(name) {
|
|
return this.classes().indexOf(name) != -1
|
|
}
|
|
// Add class to the node
|
|
, addClass: function(name) {
|
|
if (!this.hasClass(name)) {
|
|
var array = this.classes()
|
|
array.push(name)
|
|
this.attr('class', array.join(' '))
|
|
}
|
|
|
|
return this
|
|
}
|
|
// Remove class from the node
|
|
, removeClass: function(name) {
|
|
if (this.hasClass(name)) {
|
|
this.attr('class', this.classes().filter(function(c) {
|
|
return c != name
|
|
}).join(' '))
|
|
}
|
|
|
|
return this
|
|
}
|
|
// Toggle the presence of a class on the node
|
|
, toggleClass: function(name) {
|
|
return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
|
|
}
|
|
// Get referenced element form attribute value
|
|
, reference: function(attr) {
|
|
return SVG.get(this.attr(attr))
|
|
}
|
|
// Returns the parent element instance
|
|
, parent: function(type) {
|
|
var parent = this
|
|
|
|
// check for parent
|
|
if(!parent.node.parentNode) return null
|
|
|
|
// get parent element
|
|
parent = SVG.adopt(parent.node.parentNode)
|
|
|
|
if(!type) return parent
|
|
|
|
// loop trough ancestors if type is given
|
|
while(parent && parent.node instanceof window.SVGElement){
|
|
if(typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
|
|
if(!parent.node.parentNode || parent.node.parentNode.nodeName == '#document' || parent.node.parentNode.nodeName == '#document-fragment') return null // #759, #720
|
|
parent = SVG.adopt(parent.node.parentNode)
|
|
}
|
|
}
|
|
// Get parent document
|
|
, doc: function() {
|
|
return this instanceof SVG.Doc ? this : this.parent(SVG.Doc)
|
|
}
|
|
// return array of all ancestors of given type up to the root svg
|
|
, parents: function(type) {
|
|
var parents = [], parent = this
|
|
|
|
do{
|
|
parent = parent.parent(type)
|
|
if(!parent || !parent.node) break
|
|
|
|
parents.push(parent)
|
|
} while(parent.parent)
|
|
|
|
return parents
|
|
}
|
|
// matches the element vs a css selector
|
|
, matches: function(selector){
|
|
return matches(this.node, selector)
|
|
}
|
|
// Returns the svg node to call native svg methods on it
|
|
, native: function() {
|
|
return this.node
|
|
}
|
|
// Import raw svg
|
|
, svg: function(svg) {
|
|
// create temporary holder
|
|
var well = document.createElement('svg')
|
|
|
|
// act as a setter if svg is given
|
|
if (svg && this instanceof SVG.Parent) {
|
|
// dump raw svg
|
|
well.innerHTML = '<svg>' + svg.replace(/\n/, '').replace(/<([\w:-]+)([^<]+?)\/>/g, '<$1$2></$1>') + '</svg>'
|
|
|
|
// transplant nodes
|
|
for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++)
|
|
this.node.appendChild(well.firstChild.firstChild)
|
|
|
|
// otherwise act as a getter
|
|
} else {
|
|
// create a wrapping svg element in case of partial content
|
|
well.appendChild(svg = document.createElement('svg'))
|
|
|
|
// write svgjs data to the dom
|
|
this.writeDataToDom()
|
|
|
|
// insert a copy of this node
|
|
svg.appendChild(this.node.cloneNode(true))
|
|
|
|
// return target element
|
|
return well.innerHTML.replace(/^<svg>/, '').replace(/<\/svg>$/, '')
|
|
}
|
|
|
|
return this
|
|
}
|
|
// write svgjs data to the dom
|
|
, writeDataToDom: function() {
|
|
|
|
// dump variables recursively
|
|
if(this.each || this.lines){
|
|
var fn = this.each ? this : this.lines();
|
|
fn.each(function(){
|
|
this.writeDataToDom()
|
|
})
|
|
}
|
|
|
|
// remove previously set data
|
|
this.node.removeAttribute('svgjs:data')
|
|
|
|
if(Object.keys(this.dom).length)
|
|
this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
|
|
|
|
return this
|
|
}
|
|
// set given data to the elements data property
|
|
, setData: function(o){
|
|
this.dom = o
|
|
return this
|
|
}
|
|
, is: function(obj){
|
|
return is(this, obj)
|
|
}
|
|
}
|
|
})
|