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.
186 lines
5.8 KiB
186 lines
5.8 KiB
var Class = require('../../core/class'); |
|
var Color = require('../../core/color'); |
|
var Transform = require('../../core/transform'); |
|
var Node = require('./node'); |
|
|
|
var genericCanvas = typeof document !== 'undefined' && document.createElement('canvas'), |
|
genericContext = genericCanvas && genericCanvas.getContext && genericCanvas.getContext('2d'); |
|
|
|
function recolorImage(img, color1, color2){ |
|
// TODO: Fix this experimental implementation |
|
color1 = Color.detach(color1); |
|
color2 = Color.detach(color2); |
|
var canvas = document.createElement('canvas'), |
|
context = canvas.getContext('2d'); |
|
canvas.width = img.width; |
|
canvas.height = img.height; |
|
context.fillStyle = color2[0]; |
|
context.fillRect(0, 0, img.width, img.height); |
|
context.globalCompositeOperation = 'lighter'; |
|
context.drawImage(img, 0, 0); |
|
return canvas; |
|
} |
|
|
|
var Base = Class(Node, { |
|
|
|
initialize: function(){ |
|
this._fill = null; |
|
this._pendingFill = null; |
|
this._fillTransform = null; |
|
this._stroke = null; |
|
this._strokeCap = null; |
|
this._strokeDash = null; |
|
this._strokeJoin = null; |
|
this._strokeWidth = null; |
|
}, |
|
|
|
/* styles */ |
|
|
|
_addColors: function(gradient, stops){ |
|
// 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++) |
|
gradient.addColorStop(i / l, new Color(stops[i]).toString()); |
|
else for (var offset in stops) |
|
gradient.addColorStop(offset, new Color(stops[offset]).toString()); |
|
return gradient; |
|
}, |
|
|
|
|
|
fill: function(color){ |
|
if (arguments.length > 1) return this.fillLinear(arguments); |
|
if (this._pendingFill) this._pendingFill(); |
|
this._fill = color ? new Color(color).toString() : null; |
|
return this.invalidate(); |
|
}, |
|
|
|
fillRadial: function(stops, focusX, focusY, radiusX, radiusY, centerX, centerY){ |
|
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; |
|
|
|
centerX += centerX - focusX; |
|
centerY += centerY - focusY; |
|
|
|
if (radiusX === 0 || radiusX === '0') return this.fillLinear(stops); |
|
var ys = radiusY / radiusX; |
|
|
|
if (this._pendingFill) this._pendingFill(); |
|
|
|
var gradient = genericContext.createRadialGradient(focusX, focusY / ys, 0, centerX, centerY / ys, radiusX * 2); |
|
|
|
// Double fill radius to simulate repeating gradient |
|
if ('length' in stops) for (var i = 0, l = stops.length - 1; i <= l; i++){ |
|
gradient.addColorStop(i / l / 2, new Color(stops[i]).toString()); |
|
gradient.addColorStop(1 - i / l / 2, new Color(stops[i]).toString()); |
|
} else for (var offset in stops){ |
|
gradient.addColorStop(offset / 2, new Color(stops[offset]).toString()); |
|
gradient.addColorStop(1- offset / 2, new Color(stops[offset]).toString()); |
|
} |
|
|
|
this._fill = gradient; |
|
this._fillTransform = new Transform(1, 0, 0, ys); |
|
return this.invalidate(); |
|
}, |
|
|
|
fillLinear: function(stops, x1, y1, x2, y2){ |
|
if (arguments.length < 5){ |
|
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, |
|
w = this.width || 1, h = this.height || 1; |
|
|
|
x *= l; y *= l; |
|
|
|
x1 = 0.5 - x; |
|
x2 = 0.5 + x; |
|
y1 = 0.5 - y; |
|
y2 = 0.5 + y; |
|
this._fillTransform = new Transform(w, 0, 0, h); |
|
} else { |
|
this._fillTransform = null; |
|
} |
|
if (this._pendingFill) this._pendingFill(); |
|
var gradient = genericContext.createLinearGradient(x1, y1, x2, y2); |
|
this._addColors(gradient, stops); |
|
this._fill = gradient; |
|
return this.invalidate(); |
|
}, |
|
|
|
fillImage: function(url, width, height, left, top, color1, color2){ |
|
if (this._pendingFill) this._pendingFill(); |
|
var img = url; |
|
if (!(img instanceof Image)){ |
|
img = new Image(); |
|
img.src = url; |
|
} |
|
if (img.width && img.height){ |
|
return this._fillImage(img, width, height, left || 0, top || 0, color1, color2); |
|
} |
|
|
|
// Not yet loaded |
|
this._fill = null; |
|
var self = this, |
|
callback = function(){ |
|
cancel(); |
|
self._fillImage(img, width, height, left || 0, top || 0, color1, color2); |
|
}, |
|
cancel = function(){ |
|
img.removeEventListener('load', callback, false); |
|
self._pendingFill = null; |
|
}; |
|
this._pendingFill = cancel; |
|
img.addEventListener('load', callback, false); |
|
return this; |
|
}, |
|
|
|
_fillImage: function(img, width, height, left, top, color1, color2){ |
|
var w = width ? width / img.width : 1, |
|
h = height ? height / img.height : 1; |
|
if (color1 != null) img = recolorImage(img, color1, color2); |
|
this._fill = genericContext.createPattern(img, 'repeat'); |
|
this._fillTransform = new Transform(w, 0, 0, h, left || 0, top || 0); |
|
return this.invalidate(); |
|
}, |
|
|
|
stroke: function(color, width, cap, join, dash){ |
|
this._stroke = color ? new Color(color).toString() : null; |
|
this._strokeWidth = (width != null) ? width : 1; |
|
this._strokeCap = (cap != null) ? cap : 'round'; |
|
this._strokeJoin = (join != null) ? join : 'round'; |
|
this._strokeDash = dash; |
|
return this.invalidate(); |
|
}, |
|
|
|
// Rendering |
|
|
|
element_renderTo: Node.prototype.renderTo, |
|
|
|
renderTo: function(context, xx, yx, xy, yy, x, y){ |
|
var opacity = this._opacity; |
|
if (opacity == null || opacity >= 1){ |
|
return this.renderLayerTo(context, xx, yx, xy, yy, x, y); |
|
} |
|
if (this._fill && this._stroke){ |
|
return this.element_renderTo(context, xx, yx, xy, yy, x, y); |
|
} |
|
context.globalAlpha = opacity; |
|
var r = this.renderLayerTo(context, xx, yx, xy, yy, x, y); |
|
context.globalAlpha = 1; |
|
return r; |
|
}, |
|
|
|
renderLayerTo: function(context, xx, yx, xy, yy, x, y){ |
|
context.setTransform(xx, yx, xy, yy, x, y); |
|
this.renderShapeTo(context); |
|
} |
|
|
|
}); |
|
|
|
Base._genericContext = genericContext; |
|
|
|
module.exports = Base;
|
|
|