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.
231 lines
6.3 KiB
231 lines
6.3 KiB
var Class = require('../../core/class'); |
|
var Color = require('../../core/color'); |
|
var Node = require('./node'); |
|
var DOM = require('./dom'); |
|
var createElement = DOM.createElement; |
|
|
|
module.exports = Class(Node, { |
|
|
|
element_initialize: Node.prototype.initialize, |
|
|
|
initialize: function(tag){ |
|
this.element_initialize(tag); |
|
this.brushes = {}; |
|
this.fill(); |
|
this.stroke(); |
|
}, |
|
|
|
_place: function(){ |
|
if (this.parentNode){ |
|
this._injectBrush('fill'); |
|
this._injectBrush('stroke'); |
|
} else { |
|
this._ejectBrush('fill'); |
|
this._ejectBrush('stroke'); |
|
} |
|
return this; |
|
}, |
|
|
|
_injectBrush: function(type){ |
|
if (!this.parentNode) return; |
|
var brush = type == 'fill' ? this.fillBrush : this.strokeBrush; |
|
if (brush) this.parentNode.defs.appendChild(brush); |
|
}, |
|
|
|
_ejectBrush: function(type){ |
|
var brush = this[type + 'Brush']; |
|
if (brush && brush.parentNode) brush.parentNode.removeChild(brush); |
|
}, |
|
|
|
/* styles */ |
|
|
|
_createBrush: function(type, tag){ |
|
this._ejectBrush(type); |
|
|
|
var brush = createElement(tag); |
|
if (type == 'fill') |
|
this.fillBrush = brush; |
|
else |
|
this.strokeBrush = brush; |
|
|
|
var id = type + '-brush-e' + DOM.uniqueID(); |
|
brush.setAttribute('id', id); |
|
|
|
this._injectBrush(type); |
|
|
|
this.element.setAttribute(type, 'url(#' + id + ')'); |
|
|
|
return brush; |
|
}, |
|
|
|
_createGradient: function(type, style, stops){ |
|
var gradient = this._createBrush(type, style); |
|
|
|
var addColor = function(offset, color){ |
|
color = Color.detach(color); |
|
var stop = createElement('stop'); |
|
stop.setAttribute('offset', offset); |
|
stop.setAttribute('stop-color', color[0]); |
|
stop.setAttribute('stop-opacity', color[1]); |
|
gradient.appendChild(stop); |
|
}; |
|
|
|
// Enumerate stops, assumes offsets are enumerated in order |
|
// TODO: Sort. Chrome doesn't always enumerate in expected order but requires stops to be specified in order. |
|
if ('length' in stops) for (var i = 0, l = stops.length - 1; i <= l; i++) addColor(i / l, stops[i]); |
|
else for (var offset in stops) addColor(offset, stops[offset]); |
|
|
|
gradient.setAttribute('spreadMethod', 'reflect'); // Closer to the VML gradient |
|
|
|
this.element.removeAttribute('fill-opacity'); |
|
return gradient; |
|
}, |
|
|
|
_setColor: function(type, color){ |
|
this._ejectBrush(type); |
|
this[type + 'Brush'] = null; |
|
var element = this.element; |
|
if (color == null){ |
|
element.setAttribute(type, 'none'); |
|
element.removeAttribute(type + '-opacity'); |
|
} else { |
|
color = Color.detach(color); |
|
element.setAttribute(type, color[0]); |
|
element.setAttribute(type + '-opacity', color[1]); |
|
} |
|
}, |
|
|
|
fill: function(color){ |
|
if (arguments.length > 1) this.fillLinear(arguments); |
|
else this._setColor('fill', color); |
|
return this; |
|
}, |
|
|
|
fillRadial: function(stops, focusX, focusY, radiusX, radiusY, centerX, centerY){ |
|
var gradient = this._createGradient('fill', 'radialGradient', stops); |
|
|
|
gradient.setAttribute('gradientUnits', 'userSpaceOnUse'); |
|
|
|
|
|
if (focusX == null) focusX = (this.left || 0) + (this.width || 0) * 0.5; |
|
if (focusY == null) focusY = (this.top || 0) + (this.height || 0) * 0.5; |
|
if (radiusY == null) radiusY = radiusX || (this.height * 0.5) || 0; |
|
if (radiusX == null) radiusX = (this.width || 0) * 0.5; |
|
if (centerX == null) centerX = focusX; |
|
if (centerY == null) centerY = focusY; |
|
|
|
var ys = radiusY / radiusX; |
|
|
|
gradient.setAttribute('fx', focusX); |
|
gradient.setAttribute('fy', focusY / ys); |
|
|
|
gradient.setAttribute('r', radiusX); |
|
if (ys != 1) gradient.setAttribute('gradientTransform', 'scale(1,' + ys + ')'); |
|
|
|
gradient.setAttribute('cx', centerX); |
|
gradient.setAttribute('cy', centerY / ys); |
|
|
|
return this; |
|
}, |
|
|
|
fillLinear: function(stops, x1, y1, x2, y2){ |
|
var gradient = this._createGradient('fill', 'linearGradient', stops); |
|
|
|
if (arguments.length == 5){ |
|
gradient.setAttribute('gradientUnits', 'userSpaceOnUse'); |
|
} else { |
|
var angle = ((x1 == null) ? 270 : x1) * Math.PI / 180; |
|
|
|
var x = Math.cos(angle), y = -Math.sin(angle), |
|
l = (Math.abs(x) + Math.abs(y)) / 2; |
|
|
|
x *= l; y *= l; |
|
|
|
x1 = 0.5 - x; |
|
x2 = 0.5 + x; |
|
y1 = 0.5 - y; |
|
y2 = 0.5 + y; |
|
} |
|
|
|
gradient.setAttribute('x1', x1); |
|
gradient.setAttribute('y1', y1); |
|
gradient.setAttribute('x2', x2); |
|
gradient.setAttribute('y2', y2); |
|
|
|
return this; |
|
}, |
|
|
|
fillImage: function(url, width, height, left, top, color1, color2){ |
|
var pattern = this._createBrush('fill', 'pattern'); |
|
|
|
var image = createElement('image'); |
|
DOM.link(image, url); |
|
image.setAttribute('width', width); |
|
image.setAttribute('height', height); |
|
image.setAttribute('preserveAspectRatio', 'none'); // none, xMidYMid slice, xMidYMid meet |
|
|
|
if (color1 != null){ |
|
color1 = new Color(color1); |
|
if (color2 == null){ |
|
color2 = new Color(color1); |
|
color2.alpha = 0; |
|
} else { |
|
color2 = new Color(color2); |
|
} |
|
|
|
var r = (color1.red - color2.red) / (255 * 3), |
|
g = (color1.green - color2.green) / (255 * 3), |
|
b = (color1.blue - color2.blue) / (255 * 3), |
|
a = (color1.alpha - color2.alpha) / 3; |
|
|
|
var matrix = [ |
|
r, r, r, 0, color2.red / 255, |
|
g, g, g, 0, color2.green / 255, |
|
b, b, b, 0, color2.blue / 255, |
|
a, a, a, 0, color2.alpha |
|
]; |
|
|
|
var filter = createElement('filter'); |
|
filter.setAttribute('id', 'testfilter' + this.uid); |
|
|
|
var cm = createElement('feColorMatrix'); |
|
cm.setAttribute('type', 'matrix'); |
|
cm.setAttribute('values', matrix.join(' ')); |
|
|
|
image.setAttribute('fill', '#000'); |
|
image.setAttribute('filter', 'url(#testfilter' + this.uid + ')'); |
|
|
|
filter.appendChild(cm); |
|
pattern.appendChild(filter); |
|
} |
|
|
|
pattern.appendChild(image); |
|
|
|
pattern.setAttribute('patternUnits', 'userSpaceOnUse'); |
|
pattern.setAttribute('patternContentsUnits', 'userSpaceOnUse'); |
|
|
|
pattern.setAttribute('x', left || 0); |
|
pattern.setAttribute('y', top || 0); |
|
|
|
pattern.setAttribute('width', width); |
|
pattern.setAttribute('height', height); |
|
|
|
//pattern.setAttribute('viewBox', '0 0 75 50'); |
|
//pattern.setAttribute('preserveAspectRatio', 'xMidYMid slice'); |
|
|
|
return this; |
|
}, |
|
|
|
stroke: function(color, width, cap, join, dash){ |
|
var element = this.element; |
|
element.setAttribute('stroke-width', (width != null) ? width : 1); |
|
element.setAttribute('stroke-linecap', (cap != null) ? cap : 'round'); |
|
element.setAttribute('stroke-linejoin', (join != null) ? join : 'round'); |
|
if (dash) { |
|
element.setAttribute('stroke-dasharray', dash.join(',')); |
|
} |
|
this._setColor('stroke', color); |
|
return this; |
|
} |
|
|
|
});
|
|
|