Created
January 27, 2015 04:55
-
-
Save techird/7b6fde4285580a520f2d to your computer and use it in GitHub Desktop.
svg loader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function(require, exports, module) { | |
/*! | |
** Thenable -- Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable | |
** Copyright (c) 2013-2014 Ralf S. Engelschall <http://engelschall.com> | |
** Licensed under The MIT License <http://opensource.org/licenses/MIT> | |
** Source-Code distributed on <http://github.com/rse/thenable> | |
*/ | |
/* promise states [Promises/A+ 2.1] */ | |
var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */ | |
var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */ | |
var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */ | |
/* promise object constructor */ | |
var Promise = function(executor) { | |
/* optionally support non-constructor/plain-function call */ | |
if (!(this instanceof Promise)) | |
return new Promise(executor); | |
/* initialize object */ | |
this.id = 'Thenable/1.0.7'; | |
this.state = STATE_PENDING; /* initial state */ | |
this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */ | |
this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */ | |
this.onFulfilled = []; /* initial handlers */ | |
this.onRejected = []; /* initial handlers */ | |
/* support optional executor function */ | |
if (typeof executor === 'function') | |
executor.call(this, this.fulfill.bind(this), this.reject.bind(this)); | |
}; | |
/* Promise API methods */ | |
Promise.prototype = { | |
/* promise resolving methods */ | |
fulfill: function(value) { return deliver(this, STATE_FULFILLED, 'fulfillValue', value); }, | |
reject: function(value) { return deliver(this, STATE_REJECTED, 'rejectReason', value); }, | |
/* 'The then Method' [Promises/A+ 1.1, 1.2, 2.2] */ | |
then: function(onFulfilled, onRejected) { | |
var curr = this; | |
var next = new Promise(); /* [Promises/A+ 2.2.7] */ | |
curr.onFulfilled.push( | |
resolver(onFulfilled, next, 'fulfill')); /* [Promises/A+ 2.2.2/2.2.6] */ | |
curr.onRejected.push( | |
resolver(onRejected, next, 'reject')); /* [Promises/A+ 2.2.3/2.2.6] */ | |
execute(curr); | |
return next; /* [Promises/A+ 2.2.7, 3.3] */ | |
} | |
}; | |
/* deliver an action */ | |
var deliver = function(curr, state, name, value) { | |
if (curr.state === STATE_PENDING) { | |
curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */ | |
curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */ | |
execute(curr); | |
} | |
return curr; | |
}; | |
/* execute all handlers */ | |
var execute = function(curr) { | |
if (curr.state === STATE_FULFILLED) | |
execute_handlers(curr, 'onFulfilled', curr.fulfillValue); | |
else if (curr.state === STATE_REJECTED) | |
execute_handlers(curr, 'onRejected', curr.rejectReason); | |
}; | |
/* execute particular set of handlers */ | |
var execute_handlers = function(curr, name, value) { | |
/* global process: true */ | |
/* global setImmediate: true */ | |
/* global setTimeout: true */ | |
/* short-circuit processing */ | |
if (curr[name].length === 0) | |
return; | |
/* iterate over all handlers, exactly once */ | |
var handlers = curr[name]; | |
curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */ | |
var func = function() { | |
for (var i = 0; i < handlers.length; i++) | |
handlers[i](value); /* [Promises/A+ 2.2.5] */ | |
}; | |
/* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */ | |
if (typeof process === 'object' && typeof process.nextTick === 'function') | |
process.nextTick(func); | |
else if (typeof setImmediate === 'function') | |
setImmediate(func); | |
else | |
setTimeout(func, 0); | |
}; | |
/* generate a resolver function */ | |
var resolver = function(cb, next, method) { | |
return function(value) { | |
if (typeof cb !== 'function') /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */ | |
next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */ | |
else { | |
var result; | |
try { | |
if (value instanceof Promise) { | |
result = value.then(cb); | |
} | |
else result = cb(value); | |
} /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */ | |
catch (e) { | |
next.reject(e); /* [Promises/A+ 2.2.7.2] */ | |
return; | |
} | |
resolve(next, result); /* [Promises/A+ 2.2.7.1] */ | |
} | |
}; | |
}; | |
/* 'Promise Resolution Procedure' */ /* [Promises/A+ 2.3] */ | |
var resolve = function(promise, x) { | |
/* sanity check arguments */ /* [Promises/A+ 2.3.1] */ | |
if (promise === x) { | |
promise.reject(new TypeError('cannot resolve promise with itself')); | |
return; | |
} | |
/* surgically check for a 'then' method | |
(mainly to just call the 'getter' of 'then' only once) */ | |
var then; | |
if ((typeof x === 'object' && x !== null) || typeof x === 'function') { | |
try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */ | |
catch (e) { | |
promise.reject(e); /* [Promises/A+ 2.3.3.2] */ | |
return; | |
} | |
} | |
/* handle own Thenables [Promises/A+ 2.3.2] | |
and similar 'thenables' [Promises/A+ 2.3.3] */ | |
if (typeof then === 'function') { | |
var resolved = false; | |
try { | |
/* call retrieved 'then' method */ /* [Promises/A+ 2.3.3.3] */ | |
then.call(x, | |
/* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */ | |
function(y) { | |
if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */ | |
if (y === x) /* [Promises/A+ 3.6] */ | |
promise.reject(new TypeError('circular thenable chain')); | |
else | |
resolve(promise, y); | |
}, | |
/* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */ | |
function(r) { | |
if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */ | |
promise.reject(r); | |
} | |
); | |
} | |
catch (e) { | |
if (!resolved) /* [Promises/A+ 2.3.3.3.3] */ | |
promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */ | |
} | |
return; | |
} | |
/* handle other values */ | |
promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */ | |
}; | |
Promise.resolve = function(value) { | |
return new Promise(function(resolve) { | |
resolve(value); | |
}); | |
}; | |
Promise.reject = function(reason) { | |
return new Promise(function(resolve, reject) { | |
reject(reason); | |
}); | |
}; | |
/* export API */ | |
module.exports = Promise; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileOverview | |
* | |
* Convert SVG Dom Document to PNG DataURI | |
* | |
* @author: techird | |
* @copyright: Baidu FEX, 2014 | |
*/ | |
define(function(require, exports, module) { | |
var DomURL = window.URL || window.webkitURL || window; | |
function getSVGInfo(svg) { | |
var svgXml = new XMLSerializer().serializeToString(svg) | |
; | |
var width = parseInt(svg.getAttribute('width')); | |
var height = parseInt(svg.getAttribute('height')); | |
var blob = new Blob([svgXml], { | |
type: 'image/svg+xml' | |
}); | |
var svgUrl = DomURL.createObjectURL(blob); | |
// var svgUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgXml); | |
return { | |
width: width, | |
height: height, | |
dataUrl: svgUrl, | |
xml: svgXml | |
}; | |
} | |
function convert(svg, callback) { | |
var info = getSVGInfo(svg); | |
var canvas = document.createElement('canvas'); | |
canvas.width = info.width; | |
canvas.height = info.height; | |
var ctx = canvas.getContext('2d'); | |
var img = document.createElement('img'); | |
img.onload = function() { | |
ctx.drawImage(this, 0, 0); | |
callback(canvas.toDataURL('png')); | |
}; | |
img.src = info.dataUrl; | |
} | |
module.exports = convert; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* global $, console */ | |
define(function(require, exports, module) { | |
var UNIT_PERFIX = 'u-'; | |
var Promise = require('./promise'); | |
var svg2png = require('./svg2png'); | |
function fixNumber(n) { | |
return Math.round(n); | |
} | |
function makeBackground(target, svgXml) { | |
target.style.backgroundImage = 'url(data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgXml) + ')'; | |
} | |
var guid = 0; | |
function load(url, container, processor) { | |
return new Promise(function(resolve, reject) { | |
$.ajax({ | |
type: 'GET', | |
url: url, | |
dataType: 'text', | |
success: function(svgText) { | |
// 修复 id 冲突的问题 | |
guid++; | |
svgText = String(svgText).replace(/SVGID_(\d+)_/g, function(match, $1) { | |
return 'SVG_GUID_' + guid + '_' + $1 + '_'; | |
}); | |
var parse = new DOMParser(); | |
var svg = parse.parseFromString(svgText, 'text/xml'); | |
var root = svg.querySelector('svg'); | |
var each = [].forEach; | |
var viewbox = root.getAttribute('viewBox').split(' '); | |
var viewOffsetX = +viewbox[0]; | |
var viewOffsetY = +viewbox[1]; | |
var viewWidth = +viewbox[2]; | |
var viewHeight = +viewbox[3]; | |
var viewRatio = viewWidth / viewHeight; | |
var containerWidth = container.clientWidth; | |
var containerHeight = container.clientHeight; | |
var containerRatio = containerWidth / containerHeight; | |
var expand = 0; | |
var targetWidth, targetHeight, scale, xOffset, yOffset; | |
if (viewRatio > containerRatio) { | |
targetWidth = containerWidth; | |
targetHeight = targetWidth / viewRatio; | |
scale = targetWidth / viewWidth; | |
yOffset = (containerHeight - targetHeight) / 2; | |
xOffset = 0; | |
} else { | |
targetHeight = containerHeight; | |
targetWidth = containerHeight * viewRatio; | |
scale = targetHeight / viewHeight; | |
xOffset = (containerWidth - targetWidth) / 2; | |
yOffset = 0; | |
} | |
var units = []; | |
function transform(svgNode, divNode) { | |
each.call(svgNode.childNodes, function(g) { | |
if (!g.tagName || g.tagName.toLowerCase() != 'g' || !g.id) return; | |
var child = document.createElement('div'); | |
if (g.id && g.id.indexOf(UNIT_PERFIX) === 0) { | |
child.id = g.id.substr('u-'.length); | |
child.classList.add('unit'); | |
if (processor) { | |
processor(child); | |
} | |
delete g.id; | |
var unitContent = root.cloneNode(false); | |
unitContent.appendChild(g.cloneNode(true)); | |
child.appendChild(unitContent); | |
units.push(child); | |
} else { | |
child.id = g.id; | |
transform(g, child); | |
} | |
divNode.appendChild(child); | |
}); | |
} | |
transform(root, container); | |
units.forEach(function(unit) { | |
var unitContent = unit.querySelector('svg'); | |
if (unitContent) { | |
var box = unitContent.querySelector('g').getBBox(); | |
box = { | |
x: box.x - expand, | |
y: box.y - expand, | |
width: box.width + expand * 2, | |
height: box.height + expand * 2 | |
}; | |
var width = fixNumber(box.width * scale); | |
var height = fixNumber(box.height * scale); | |
if (width % 2) width++; | |
if (height % 2) height++; | |
unitContent.setAttribute('viewBox', | |
[box.x, box.y, box.width, box.height].map(fixNumber).join(' ')); | |
unitContent.setAttribute('width', width); | |
unitContent.setAttribute('height', height); | |
unit.style.left = Math.round((box.x + viewOffsetX) * scale + xOffset) + 'px'; | |
unit.style.top = Math.round((box.y + viewOffsetY) * scale + yOffset) + 'px'; | |
unit.style.width = width + 'px'; | |
unit.style.height = height + 'px'; | |
if (/export_png/.test(window.location.href)) { | |
svg2png(unitContent, function(url) { | |
var a = document.createElement('a'); | |
a.download = unit.id + '.png'; | |
a.href = url; | |
var e = new MouseEvent('click'); | |
a.dispatchEvent(e); | |
}); | |
}; | |
} | |
}); | |
if (/export_html/.test(window.location.href)) { | |
units.forEach(function(unit) { | |
var left = Math.ceil(parseInt(unit.style.left) / 2) + 'px'; | |
var top = Math.ceil(parseInt(unit.style.top) / 2) + 'px'; | |
var width = Math.ceil(parseInt(unit.style.width) / 2) + 'px'; | |
var height = Math.ceil(parseInt(unit.style.height) / 2) + 'px'; | |
var backgroundImage = 'url(img/' + unit.id + '.png)'; | |
unit.setAttribute('style', [ | |
'left: ' + left, | |
'top: ' + top, | |
'width: ' + width, | |
'height: ' + height, | |
'background-image: ' + backgroundImage, | |
'background-size: ' + width + ' ' + height | |
].join('; ')); | |
unit.innerHTML = ''; | |
}); | |
console.log(container.innerHTML); | |
} | |
resolve(units); | |
}, | |
error: reject | |
}); | |
}); | |
} | |
exports.load = load; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment