This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.4 KiB
201 lines
5.4 KiB
var Class = require('../../core/class'); |
|
var Path = require('./path'); |
|
var Base = require('./base'); |
|
var Surface = require('./surface'); |
|
var DOM = require('./dom'); |
|
var createElement = DOM.createElement; |
|
|
|
var ua = typeof navigator !== 'undefined' && navigator && navigator.userAgent, |
|
hasBaseline = !(/opera|safari|ie/i).test(ua) || (/chrome/i).test(ua); |
|
|
|
var fontAnchors = { left: 'start', center: 'middle', right: 'end' }, |
|
fontAnchorOffsets = { middle: '50%', end: '100%' }; |
|
|
|
module.exports = Class(Base, { |
|
|
|
base_initialize: Base.prototype.initialize, |
|
|
|
initialize: function(text, font, alignment, path){ |
|
this.base_initialize('text'); |
|
this.draw.apply(this, arguments); |
|
}, |
|
|
|
draw: function(text, font, alignment, path){ |
|
var element = this.element; |
|
|
|
if (font){ |
|
if (typeof font == 'string'){ |
|
element.style.font = font; |
|
} else { |
|
for (var key in font){ |
|
var ckey = key.camelCase ? key.camelCase() : key; |
|
// NOT UNIVERSALLY SUPPORTED OPTIONS |
|
// if (ckey == 'kerning') element.setAttribute('kerning', font[key] ? 'auto' : '0'); |
|
// else if (ckey == 'letterSpacing') element.setAttribute('letter-spacing', Number(font[key]) + 'ex'); |
|
// else if (ckey == 'rotateGlyphs') element.setAttribute('glyph-orientation-horizontal', font[key] ? '270deg' : ''); |
|
// else |
|
element.style[ckey] = font[key]; |
|
} |
|
element.style.lineHeight = '0.5em'; |
|
} |
|
} |
|
|
|
if (alignment) element.setAttribute('text-anchor', this.textAnchor = (fontAnchors[alignment] || alignment)); |
|
|
|
if (path && typeof path != 'number'){ |
|
this._createPaths(new Path(path)); |
|
} else if (path === false){ |
|
this._ejectPaths(); |
|
this.pathElements = null; |
|
} |
|
|
|
var paths = this.pathElements, child; |
|
|
|
while ((child = element.firstChild)){ |
|
element.removeChild(child); |
|
} |
|
|
|
// Note: Gecko will (incorrectly) align gradients for each row, while others applies one for the entire element |
|
|
|
var lines = String(text).split(/\r?\n/), l = lines.length, |
|
baseline = 'central'; |
|
|
|
if (paths && l > paths.length) l = paths.length; |
|
|
|
if (hasBaseline) element.setAttribute('dominant-baseline', baseline); |
|
|
|
DOM.preserveSpace(element); |
|
|
|
for (var i = 0; i < l; i++){ |
|
var line = lines[i], row, content; |
|
if (paths){ |
|
row = createElement('textPath'); |
|
DOM.link(row, '#' + paths[i].getAttribute('id')); |
|
row.setAttribute('startOffset', fontAnchorOffsets[this.textAnchor] || 0); |
|
} else { |
|
row = createElement('tspan'); |
|
row.setAttribute('x', 0); |
|
row.setAttribute('y', (i * 1.1 + 0.5) + 'em'); |
|
} |
|
if (hasBaseline){ |
|
row.setAttribute('dominant-baseline', baseline); |
|
content = row; |
|
} else if (paths){ |
|
content = createElement('tspan'); |
|
content.setAttribute('dy', '0.35em'); |
|
row.appendChild(content); |
|
} else { |
|
content = row; |
|
row.setAttribute('y', (i * 1.1 + 0.85) + 'em'); |
|
} |
|
DOM.preserveSpace(content); |
|
content.appendChild(DOM.createTextNode(line)); |
|
element.appendChild(row); |
|
} |
|
|
|
// Measure |
|
// TODO: Move to lazy ES5 left/top/width/height/bottom/right property getters |
|
var bb; |
|
try { bb = element.getBBox(); } catch (x){ } |
|
if (!bb || !bb.width) bb = this._whileInDocument(element.getBBox, element); |
|
|
|
this.left = bb.x; |
|
this.top = bb.y; |
|
this.width = bb.width; |
|
this.height = bb.height; |
|
this.right = bb.x + bb.width; |
|
this.bottom = bb.y + bb.height; |
|
return this; |
|
}, |
|
|
|
// TODO: Unify path injection with gradients and imagefills |
|
|
|
base_place: Base.prototype._place, |
|
|
|
_place: function(){ |
|
if (this.parentNode){ |
|
this._injectPaths(); |
|
} else { |
|
this._ejectPaths(); |
|
} |
|
return this.base_place(); |
|
}, |
|
|
|
_injectPaths: function(){ |
|
var paths = this.pathElements; |
|
if (!this.parentNode || !paths) return; |
|
var defs = this.parentNode.defs; |
|
for (var i = 0, l = paths.length; i < l; i++) |
|
defs.appendChild(paths[i]); |
|
}, |
|
|
|
_ejectPaths: function(){ |
|
var paths = this.pathElements; |
|
if (!paths) return; |
|
for (var i = 0, l = paths; i < l; i++){ |
|
var path = paths[i]; |
|
if (path.parentNode) |
|
path.parentNode.removeChild(paths[i]); |
|
} |
|
}, |
|
|
|
_createPaths: function(path){ |
|
this._ejectPaths(); |
|
var id = 'p' + DOM.uniqueID() + '-'; |
|
|
|
//splitPaths = []; splitPath = ['M', 0, 0]; |
|
//path.visit(splitLine, splitCurve, null, splitMove); |
|
//splitPaths.push(splitPath); |
|
var splitPaths = [path.path]; |
|
|
|
var result = []; |
|
for (var i = 0, l = splitPaths.length; i < l; i++){ |
|
var p = createElement('path'); |
|
p.setAttribute('d', splitPaths[i].join(' ')); |
|
p.setAttribute('id', id + i); |
|
result.push(p); |
|
} |
|
this.pathElements = result; |
|
this._injectPaths(); |
|
}, |
|
|
|
_whileInDocument: function(fn, bind){ |
|
// Temporarily inject into the document |
|
var element = this.element, |
|
container = this.parentNode, |
|
parent = element.parentNode, |
|
sibling = element.nextSibling, |
|
body = element.ownerDocument.body, |
|
canvas = new Surface(1, 1).inject(body); |
|
this.inject(canvas); |
|
var result = fn.call(bind); |
|
canvas.eject(); |
|
if (container) this.inject(container); |
|
if (parent) parent.insertBefore(element, sibling); |
|
return result; |
|
} |
|
|
|
}); |
|
|
|
/* split each continuous line into individual paths */ |
|
|
|
/* |
|
var pathSplitter = new CorePath(); |
|
pathSplitter.splitPaths = []; |
|
|
|
var PathPerRow = Class(CorePath, { |
|
|
|
function splitMove(sx, sy, x, y){ |
|
if (splitPath.length > 3) splitPaths.push(splitPath); |
|
splitPath = ['M', x, y]; |
|
}; |
|
|
|
function splitLine(sx, sy, x, y){ |
|
splitPath.push('L', x, y); |
|
}; |
|
|
|
function splitCurve(sx, sy, p1x, p1y, p2x, p2y, x, y){ |
|
splitPath.push('C', p1x, p1y, p2x, p2y, x, y); |
|
}; |
|
|
|
});*/
|
|
|