UNPKG

simplesvg

Version:

A very simple svg wrapper, inspired by original vivagraph

310 lines (243 loc) 8.91 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.sivg = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ module.exports = svg; svg.compile = require('./lib/compile'); var compileTemplate = svg.compileTemplate = require('./lib/compile_template'); var domEvents = require('add-event-listener'); var svgns = "http://www.w3.org/2000/svg"; var xlinkns = "http://www.w3.org/1999/xlink"; function svg(element, attrBag) { var svgElement = augment(element); if (attrBag === undefined) { return svgElement; } svgElement.attr(attrBag); return svgElement; } function augment(element) { var svgElement = element; if (typeof element === "string") { svgElement = window.document.createElementNS(svgns, element); } else if (element.simplesvg) { return element; } var compiledTemplate; svgElement.simplesvg = true; // this is not good, since we are monkey patching svg svgElement.attr = attr; svgElement.append = append; svgElement.link = link; svgElement.text = text; // add easy eventing svgElement.on = on; svgElement.off = off; // data binding: svgElement.dataSource = dataSource; return svgElement; function dataSource(model) { if (!compiledTemplate) compiledTemplate = compileTemplate(svgElement); compiledTemplate.link(model); return svgElement; } function on(name, cb, useCapture) { domEvents.addEventListener(svgElement, name, cb, useCapture); return svgElement; } function off(name, cb, useCapture) { domEvents.removeEventListener(svgElement, name, cb, useCapture); return svgElement; } function append(content) { var child = svg(content); svgElement.appendChild(child); return child; } function attr(name, value) { if (arguments.length === 2) { if (value !== null) { svgElement.setAttributeNS(null, name, value); } else { svgElement.removeAttributeNS(null, name); } return svgElement; } if (typeof name === 'string') { // someone wants to get value of an attribute: return svgElement.getAttributeNS(null, name); } if (typeof name !== 'object') throw new Error('attr() expects to have either string or object as first argument'); var attrBag = name; var attributes = Object.keys(attrBag); for (var i = 0; i < attributes.length; ++i) { var attributeName = attributes[i]; var value = attrBag[attributeName]; if (attributeName === 'link') { svgElement.link(value); } else { svgElement.attr(attributeName, value); } } return svgElement; } function link(target) { if (arguments.length) { svgElement.setAttributeNS(xlinkns, "xlink:href", target); return svgElement; } return svgElement.getAttributeNS(xlinkns, "xlink:href"); } function text(textContent) { if (textContent !== undefined) { svgElement.textContent = textContent; return svgElement; } return svgElement.textContent; } } },{"./lib/compile":2,"./lib/compile_template":3,"add-event-listener":5}],2:[function(require,module,exports){ var parser = require('./domparser.js'); var svg = require('../'); module.exports = compile; function compile(svgText) { try { svgText = addNamespaces(svgText); return svg(parser.parseFromString(svgText, "text/xml").documentElement); } catch (e) { throw e; } } function addNamespaces(text) { if (!text) return; var namespaces = 'xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"'; var match = text.match(/^<\w+/); if (match) { var tagLength = match[0].length; return text.substr(0, tagLength) + ' ' + namespaces + ' ' + text.substr(tagLength); } else { throw new Error('Cannot parse input text: invalid xml?'); } } },{"../":1,"./domparser.js":4}],3:[function(require,module,exports){ module.exports = template; var BINDING_EXPR = /{{(.+?)}}/; function template(domNode) { var allBindings = Object.create(null); extractAllBindings(domNode, allBindings); return { link: function(model) { Object.keys(allBindings).forEach(function(key) { var setter = allBindings[key]; setter.forEach(changeModel); }); function changeModel(setter) { setter(model); } } }; } function extractAllBindings(domNode, allBindings) { var nodeType = domNode.nodeType; var typeSupported = (nodeType === 1) || (nodeType === 3); if (!typeSupported) return; var i; if (domNode.hasChildNodes()) { var domChildren = domNode.childNodes; for (i = 0; i < domChildren.length; ++i) { extractAllBindings(domChildren[i], allBindings); } } if (nodeType === 3) { // text: bindTextContent(domNode, allBindings); } if (!domNode.attributes) return; // this might be a text. Need to figure out what to do in that case var attrs = domNode.attributes; for (i = 0; i < attrs.length; ++i) { bindDomAttribute(attrs[i], domNode, allBindings); } } function bindDomAttribute(domAttribute, element, allBindings) { var value = domAttribute.value; if (!value) return; // unary attribute? var modelNameMatch = value.match(BINDING_EXPR); if (!modelNameMatch) return; // does not look like a binding var attrName = domAttribute.localName; var modelPropertyName = modelNameMatch[1]; var isSimpleValue = modelPropertyName.indexOf('.') < 0; if (!isSimpleValue) throw new Error('simplesvg currently does not support nested bindings'); var propertyBindings = allBindings[modelPropertyName]; if (!propertyBindings) { propertyBindings = allBindings[modelPropertyName] = [attributeSetter]; } else { propertyBindings.push(attributeSetter); } function attributeSetter(model) { element.setAttributeNS(null, attrName, model[modelPropertyName]); } } function bindTextContent(element, allBindings) { // todo reduce duplication var value = element.nodeValue; if (!value) return; // unary attribute? var modelNameMatch = value.match(BINDING_EXPR); if (!modelNameMatch) return; // does not look like a binding var modelPropertyName = modelNameMatch[1]; var isSimpleValue = modelPropertyName.indexOf('.') < 0; var propertyBindings = allBindings[modelPropertyName]; if (!propertyBindings) { propertyBindings = allBindings[modelPropertyName] = [textSetter]; } else { propertyBindings.push(textSetter); } function textSetter(model) { element.nodeValue = model[modelPropertyName]; } } },{}],4:[function(require,module,exports){ module.exports = createDomparser(); function createDomparser() { if (typeof DOMParser === 'undefined') { return { parseFromString: fail }; } return new DOMParser(); } function fail() { throw new Error('DOMParser is not supported by this platform. Please open issue here https://github.com/anvaka/simplesvg'); } },{}],5:[function(require,module,exports){ addEventListener.removeEventListener = removeEventListener addEventListener.addEventListener = addEventListener module.exports = addEventListener var Events = null function addEventListener(el, eventName, listener, useCapture) { Events = Events || ( document.addEventListener ? {add: stdAttach, rm: stdDetach} : {add: oldIEAttach, rm: oldIEDetach} ) return Events.add(el, eventName, listener, useCapture) } function removeEventListener(el, eventName, listener, useCapture) { Events = Events || ( document.addEventListener ? {add: stdAttach, rm: stdDetach} : {add: oldIEAttach, rm: oldIEDetach} ) return Events.rm(el, eventName, listener, useCapture) } function stdAttach(el, eventName, listener, useCapture) { el.addEventListener(eventName, listener, useCapture) } function stdDetach(el, eventName, listener, useCapture) { el.removeEventListener(eventName, listener, useCapture) } function oldIEAttach(el, eventName, listener, useCapture) { if(useCapture) { throw new Error('cannot useCapture in oldIE') } el.attachEvent('on' + eventName, listener) } function oldIEDetach(el, eventName, listener, useCapture) { el.detachEvent('on' + eventName, listener) } },{}]},{},[1])(1) });