Compare commits

..

1 commit

Author SHA1 Message Date
Milan Pässler e8b6be29a2 [WIP] show advanced airtime stats 2017-03-19 22:49:10 +01:00
20 changed files with 183 additions and 3558 deletions

View file

@ -1,7 +1,7 @@
language: node_js language: node_js
node_js: before_install:
- "lts/*" - gem install sass
- "node" - npm install -g grunt-cli
install: install:
- yarn - npm install
script: node_modules/.bin/grunt script: grunt

View file

@ -17,7 +17,7 @@ module.exports = function (grunt) {
grunt.loadTasks("tasks") grunt.loadTasks("tasks")
grunt.registerTask("default", ["lint", "saveRevision", "copy", "sass", "postcss", "requirejs"]) grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"])
grunt.registerTask("lint", ["eslint"]) grunt.registerTask("lint", ["eslint"])
grunt.registerTask("dev", ["default", "connect:server", "watch"]) grunt.registerTask("dev", ["default", "connect:server", "watch"])
} }

View file

@ -1,8 +1,8 @@
[![Build Status](https://travis-ci.org/hopglass/hopglass.svg?branch=master)](https://travis-ci.org/hopglass/hopglass) [![Build Status](https://travis-ci.org/plumpudding/hopglass.svg?branch=master)](https://travis-ci.org/plumpudding/hopglass)
# HopGlass # HopGlass
HopGlass is a frontend for the [HopGlass Server](https://github.com/hopglass/hopglass-server). HopGlass is a frontend for the [HopGlass Server](https://github.com/plumpudding/hopglass-server).
# Screenshots # Screenshots
@ -14,32 +14,29 @@ HopGlass is a frontend for the [HopGlass Server](https://github.com/hopglass/hop
# Dependencies # Dependencies
- NodeJS - npm
- yarn (recommended) or npm - bower
- grunt-cli
- Sass (>= 3.2)
# Installing dependencies # Installing dependencies
Install npm package-manager. On Debian-like systems run: Install npm package-manager. On Debian-like systems run:
sudo apt-get install nodejs sudo apt-get install npm
**Note:** The official Debian packages for NodeJS are quite old, you might want to check at [NodeSource](https://github.com/nodesource/distributions/blob/master/README.md) for current binaries installable with your distribution's package manager. On Mac you have to install only npm via brew and sass
On Mac you can install nodejs and yarn via brew:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install node brew install node
brew install yarn npm install node-sass
On Arch Linux you can install nodejs and yarn via pacman:
sudo pacman -S nodejs yarn
Execute these commands on your server as a normal user to prepare the dependencies: Execute these commands on your server as a normal user to prepare the dependencies:
git clone https://github.com/hopglass/hopglass git clone https://github.com/plumpudding/hopglass
cd hopglass cd hopglass
yarn install # or `npm install` npm install
npm install grunt-cli
# Building # Building
@ -55,7 +52,7 @@ Copy `config.json.example` to `build/config.json` and change it to match your co
## dataPath (string/array) ## dataPath (string/array)
`dataPath` can be either a string containing the address of a [HopGlass Server](https://github.com/hopglass/hopglass-server) or an array containing multiple addresses. `dataPath` can be either a string containing the address of a [HopGlass Server](https://github.com/plumpudding/hopglass-server) or an array containing multiple addresses.
Don't forget the trailing slash! Don't forget the trailing slash!
Also, proxying the data through a webserver will allow GZip and thus will greatly reduce bandwidth consumption. Also, proxying the data through a webserver will allow GZip and thus will greatly reduce bandwidth consumption.
It may help with firewall problems too. It may help with firewall problems too.

26
app.js
View file

@ -1,20 +1,20 @@
require.config({ require.config({
baseUrl: "lib", baseUrl: "lib",
paths: { paths: {
"leaflet": "../node_modules/leaflet/dist/leaflet", "leaflet": "../bower_components/leaflet/dist/leaflet",
"leaflet.label": "../node_modules/leaflet-label/dist/leaflet.label", "leaflet.label": "../bower_components/Leaflet.label/dist/leaflet.label",
"leaflet.providers": "../node_modules/leaflet-providers/leaflet-providers", "leaflet.providers": "../bower_components/leaflet-providers/leaflet-providers",
"chroma-js": "../node_modules/chroma-js/chroma.min", "chroma-js": "../bower_components/chroma-js/chroma.min",
"moment": "../node_modules/moment/min/moment-with-locales.min", "moment": "../bower_components/moment/min/moment-with-locales.min",
"tablesort": "../node_modules/tablesort/tablesort.min", "tablesort": "../bower_components/tablesort/tablesort.min",
"tablesort.numeric": "../node_modules/tablesort/src/sorts/tablesort.numeric", "tablesort.numeric": "../bower_components/tablesort/src/sorts/tablesort.numeric",
"d3": "../node_modules/d3/d3.min", "d3": "../bower_components/d3/d3.min",
"numeral": "../node_modules/numeraljs/min/numeral.min", "numeral": "../bower_components/numeraljs/min/numeral.min",
"numeral-intl": "../node_modules/numeraljs/min/languages.min", "numeral-intl": "../bower_components/numeraljs/min/languages.min",
"virtual-dom": "../node_modules/virtual-dom/dist/virtual-dom", "virtual-dom": "../bower_components/virtual-dom/dist/virtual-dom",
"rbush": "../node_modules/rbush/rbush", "rbush": "../bower_components/rbush/rbush",
"helper": "../helper", "helper": "../helper",
"jshashes": "../node_modules/jshashes/hashes" "jshashes": "../bower_components/jshashes/hashes"
}, },
shim: { shim: {
"leaflet.label": ["leaflet"], "leaflet.label": ["leaflet"],

36
bower.json Normal file
View file

@ -0,0 +1,36 @@
{
"name": "HopGlass",
"ignore": [
"node_modules",
"bower_components",
"**/.*",
"test",
"tests"
],
"dependencies": {
"Leaflet.label": "~0.2.1",
"chroma-js": "~0.6.1",
"leaflet": "~0.7.3",
"ionicons": "~2.0.1",
"moment": "~2.9.0",
"requirejs": "~2.1.16",
"tablesort": "https://github.com/tristen/tablesort.git#v3.0.2",
"roboto-slab-fontface": "*",
"es6-shim": "~0.27.1",
"almond": "~0.3.1",
"r.js": "~2.1.16",
"d3": "~3.5.5",
"numeraljs": "~1.5.3",
"roboto-fontface": "~0.3.0",
"virtual-dom": "~2.0.1",
"leaflet-providers": "~1.0.27",
"rbush": "https://github.com/mourner/rbush.git#~1.3.5",
"jshashes": "~1.0.5"
},
"authors": [
"Milan Pässler <me@petabyteboy.de>",
"Nils Schneider <nils@nilsschneider.net>"
],
"license": "AGPL3",
"private": true
}

View file

@ -1,6 +1,6 @@
({ ({
baseUrl: "lib", baseUrl: "lib",
name: "../node_modules/almond/almond", name: "../bower_components/almond/almond",
mainConfigFile: "app.js", mainConfigFile: "app.js",
include: "../app", include: "../app",
wrap: true, wrap: true,

View file

@ -5,25 +5,11 @@
"showContact": true, "showContact": true,
"maxAge": 14, "maxAge": 14,
"mapLayers": [ "mapLayers": [
{ "name": "CartoDB",
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
"config": {
"maxZoom": 18,
"attribution": "&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>, &copy; | <a href=\"https://carto.com/attribution\">CARTO</a>"
}
},
{ {
"name": "OpenStreetMap.HOT" "name": "OpenStreetMap.HOT"
}, },
{ {
"name": "Luftbilder NRW", "name": "Stamen.TonerLite"
"url": "https://www.wms.nrw.de/geobasis/wms_nw_dop?",
"config": {
"maxZoom": 20,
"attribution": "<a href=\"http://www.bezreg-koeln.nrw.de/brk_internet/geobasis/luftbilderzeugnisse/digitale_orthophotos/index.html\">DOP20</a>, Land NRW (2017), Datenlizenz Deutschland - Namensnennung - Version 2.0 (<a href=\"https://www.govdata.de/dl-de/by-2-0\">www.govdata.de/dl-de/by-2-0</a>)",
"format": "image/jpeg",
"layers": "nw_dop_rgb"
}
} }
], ],
"nodeInfos": [ "nodeInfos": [

View file

@ -4,8 +4,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" href="css/ionicons.min.css"> <link rel="stylesheet" href="css/ionicons.min.css">
<link rel="stylesheet" href="css/roboto-slab/roboto-slab-fontface.css"> <link rel="stylesheet" href="roboto-slab-fontface.css">
<link rel="stylesheet" href="css/roboto/roboto-fontface.css"> <link rel="stylesheet" href="roboto-fontface.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="vendor/es6-shim/es6-shim.min.js"></script> <script src="vendor/es6-shim/es6-shim.min.js"></script>
<script src="app.js"></script> <script src="app.js"></script>

View file

@ -3,14 +3,14 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto-slab/roboto-slab-fontface.css"> <link rel="stylesheet" href="bower_components/roboto-slab-fontface/roboto-slab-fontface.css">
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto/roboto-fontface.css"> <link rel="stylesheet" href="bower_components/roboto-fontface/roboto-fontface.css">
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css"> <link rel="stylesheet" href="bower_components/leaflet/dist/leaflet.css">
<link rel="stylesheet" href="node_modules/leaflet-label/dist/leaflet.label.css"> <link rel="stylesheet" href="bower_components/Leaflet.label/dist/leaflet.label.css">
<link rel="stylesheet" href="node_modules/ionicons/css/ionicons.min.css"> <link rel="stylesheet" href="bower_components/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="bower_components/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/requirejs/require.js" data-main="app"></script> <script src="bower_components/requirejs/require.js" data-main="app"></script>
</head> </head>
<body> <body>
</body> </body>

View file

@ -29,8 +29,8 @@ define(function () {
s += "https://www.gnu.org/licenses/</a>.</p>" s += "https://www.gnu.org/licenses/</a>.</p>"
s += "<p>The source code is available at " s += "<p>The source code is available at "
s += "<a href=\"https://github.com/hopglass/hopglass\">" s += "<a href=\"https://github.com/plumpudding/hopglass\">"
s += "https://github.com/hopglass/hopglass</a>." s += "https://github.com/plumpudding/hopglass</a>."
el.innerHTML = s el.innerHTML = s
} }

View file

@ -271,6 +271,40 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
return span return span
} }
function showAirtimeBar(className, v) {
var span = document.createElement("span")
span.classList.add("bar")
span.classList.add(className)
var waitbar = document.createElement("span")
waitbar.style.width = (v.wait * 100) + "%"
span.appendChild(waitbar)
waitbar.style.background = "rgba(221, 44, 0, 1)"
var waitlabel = document.createElement("span")
waitlabel.textContent = (Math.round(v.wait * 100)) + " % wait"
waitbar.appendChild(waitlabel)
var rxbar = document.createElement("span")
rxbar.style.width = (v.rx * 100) + "%"
span.appendChild(rxbar)
rxbar.style.background = "rgba(0, 145, 234, 1)"
var rxlabel = document.createElement("span")
rxlabel.textContent = (Math.round(v.rx * 100)) + " % rx"
rxbar.appendChild(rxlabel)
var txbar = document.createElement("span")
txbar.style.width = (v.tx * 100) + "%"
span.appendChild(txbar)
txbar.style.background = "rgba(0, 191, 165, 1)"
var txlabel = document.createElement("span")
txlabel.textContent = (Math.round(v.tx * 100)) + " % tx"
txbar.appendChild(txlabel)
var label = document.createElement("label")
label.textContent = (Math.round(v.free * 100)) + " % frei"
span.appendChild(label)
return span
}
function showLoad(d) { function showLoad(d) {
if (!("loadavg" in d.statistics)) if (!("loadavg" in d.statistics))
return undefined return undefined
@ -292,10 +326,14 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
function showAirtime(band, val) { function showAirtime(band, val) {
if (!val) if (!val)
return undefined return undefined
if (!isNaN(val))
return function (el) { return function (el) {
el.appendChild(showBar("airtime" + band.toString(), val)) el.appendChild(showBar("airtime" + band.toString(), val))
} }
return function (el) {
el.appendChild(showAirtimeBar("airtime" + band.toString(), val))
}
} }
function createLink(target, router) { function createLink(target, router) {

View file

@ -286,7 +286,7 @@ define(["map/clientlayer", "map/labelslayer",
var layers = config.mapLayers.map( function (d) { var layers = config.mapLayers.map( function (d) {
return { return {
"name": d.name, "name": d.name,
"layer": "url" in d ? "layers" in d.config ? L.tileLayer.wms(d.url, d.config) : L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name) "layer": "url" in d ? L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name)
} }
}) })

View file

@ -1,12 +1,15 @@
define(["leaflet"], define(["leaflet", "jshashes"],
function (L) { function (L, jsHashes) {
var MD5 = new jsHashes.MD5()
return L.TileLayer.Canvas.extend({ return L.TileLayer.Canvas.extend({
setData: function (d) { setData: function (d) {
this.data = d this.data = d
//pre-calculate start angles //pre-calculate start angles
this.data.all().forEach(function (d) { this.data.all().forEach(function (d) {
d.startAngle = (parseInt(d.node.nodeinfo.node_id.substr(10, 2), 16) / 255) * 2 * Math.PI var hash = MD5.hex(d.node.nodeinfo.node_id)
d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI
}) })
this.redraw() this.redraw()
}, },

View file

@ -1,41 +1,24 @@
{ {
"name": "hopglass", "name": "hopglass",
"version": "1.0.0",
"scripts": { "scripts": {
"test": "node -e \"require('grunt').cli()\" '' clean lint" "test": "node -e \"require('grunt').cli()\" '' clean lint"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^6.3.3", "autoprefixer": "^6.3.3",
"dart-sass": "^1.16.1", "grunt": "^0.4.5",
"grunt": "^1.0.3",
"grunt-check-dependencies": "^0.6.0", "grunt-check-dependencies": "^0.6.0",
"grunt-contrib-clean": "^0.6.0", "grunt-contrib-clean": "^0.6.0",
"grunt-contrib-connect": "^0.8.0", "grunt-contrib-connect": "^0.8.0",
"grunt-contrib-copy": "^0.5.0", "grunt-contrib-copy": "^0.5.0",
"grunt-contrib-cssmin": "^0.12.2", "grunt-contrib-cssmin": "^0.12.2",
"grunt-contrib-requirejs": "^0.4.4", "grunt-contrib-requirejs": "^0.4.4",
"grunt-sass": "^1.1.0",
"grunt-postcss": "^0.7.2",
"grunt-contrib-uglify": "^0.5.1", "grunt-contrib-uglify": "^0.5.1",
"grunt-contrib-watch": "^0.6.1", "grunt-contrib-watch": "^0.6.1",
"grunt-eslint": "^10.0.0", "grunt-eslint": "^10.0.0",
"grunt-git-describe": "^2.3.2", "grunt-bower-install-simple": "^1.1.2",
"grunt-postcss": "^0.7.2", "grunt-git-describe": "^2.3.2"
"grunt-sass": "^3.0.2"
},
"dependencies": {
"almond": "^0.3.3",
"chroma-js": "^0.7.8",
"d3": "^3.5.17",
"ionicons": "^2.0.1",
"leaflet": "^0.7.7",
"leaflet-label": "^0.2.1-0",
"leaflet-providers": "^1.5.0",
"moment": "^2.23.0",
"numeraljs": "^1.5.6",
"rbush": "^1.4.3",
"requirejs": "^2.3.2",
"roboto-fontface": "^0.10.0",
"tablesort": "3.0.2",
"virtual-dom": "^2.1.1"
}, },
"eslintConfig": { "eslintConfig": {
"env": { "env": {

View file

@ -1 +1 @@
../node_modules/leaflet-label/dist/leaflet.label.css ../bower_components/Leaflet.label/dist/leaflet.label.css

View file

@ -1 +1 @@
../node_modules/leaflet/dist/leaflet.css ../bower_components/leaflet/dist/leaflet.css

View file

@ -70,7 +70,7 @@ $buttondistance: 12pt;
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: 'Roboto-Slab', serif; font-family: 'Roboto Slab', serif;
font-size: 11pt; font-size: 11pt;
color: #333; color: #333;
} }
@ -409,6 +409,7 @@ table {
display: inline-block; display: inline-block;
height: 1.4em; height: 1.4em;
background: rgba(85, 128, 32, 0.8); background: rgba(85, 128, 32, 0.8);
overflow: hidden;
} }
label { label {
@ -421,6 +422,14 @@ table {
} }
} }
.bar > span > span {
left: 0.5em;
font-weight: bold;
color: white;
white-space: nowrap;
background: none !important;
}
.proportion th { .proportion th {
font-weight: normal !important; font-weight: normal !important;
text-align: right !important; text-align: right !important;

View file

@ -1,6 +1,6 @@
module.exports = function(grunt) { module.exports = function(grunt) {
grunt.config.merge({ grunt.config.merge({
nodedir: "node_modules", bowerdir: "bower_components",
copy: { copy: {
html: { html: {
options: { options: {
@ -22,18 +22,24 @@ module.exports = function(grunt) {
src: ["es6-shim/es6-shim.min.js", src: ["es6-shim/es6-shim.min.js",
"es6-shim/es6-shim.map"], "es6-shim/es6-shim.map"],
expand: true, expand: true,
cwd: "node_modules/", cwd: "bower_components/",
dest: "build/vendor/" dest: "build/vendor/"
}, },
roboto: { robotoSlab: {
src: [ "fonts/roboto/*", src: [ "fonts/*",
"fonts/roboto-slab/*", "roboto-slab-fontface.css"
"css/roboto/roboto-fontface.css",
"css/roboto-slab/roboto-slab-fontface.css"
], ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/roboto-fontface/" cwd: "bower_components/roboto-slab-fontface"
},
roboto: {
src: [ "fonts/*",
"roboto-fontface.css"
],
expand: true,
dest: "build/",
cwd: "bower_components/roboto-fontface"
}, },
ionicons: { ionicons: {
src: [ "fonts/*", src: [ "fonts/*",
@ -41,20 +47,19 @@ module.exports = function(grunt) {
], ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/ionicons/" cwd: "bower_components/ionicons/"
}, },
leafletImages: { leafletImages: {
src: [ "images/*" ], src: [ "images/*" ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/leaflet/dist/" cwd: "bower_components/leaflet/dist/"
} }
}, },
sass: { sass: {
options: { options: {
sourceMap: true, sourceMap: true,
outputStyle: "compressed", outputStyle: "compressed"
implementation: require("dart-sass")
}, },
dist: { dist: {
files: { files: {
@ -78,18 +83,31 @@ module.exports = function(grunt) {
cssmin: { cssmin: {
target: { target: {
files: { files: {
"build/style.css": [ "node_modules/leaflet/dist/leaflet.css", "build/style.css": [ "bower_components/leaflet/dist/leaflet.css",
"node_modules/leaflet-label/dist/leaflet.label.css", "bower_components/Leaflet.label/dist/leaflet.label.css",
"style.css" "style.css"
] ]
} }
} }
}, },
"bower-install-simple": {
options: {
directory: "<%=bowerdir%>",
color: true,
interactive: false,
production: true
},
"prod": {
options: {
production: true
}
}
},
requirejs: { requirejs: {
compile: { compile: {
options: { options: {
baseUrl: "lib", baseUrl: "lib",
name: "../node_modules/almond/almond", name: "../bower_components/almond/almond",
mainConfigFile: "app.js", mainConfigFile: "app.js",
include: "../app", include: "../app",
wrap: true, wrap: true,
@ -100,6 +118,7 @@ module.exports = function(grunt) {
} }
}) })
grunt.loadNpmTasks("grunt-bower-install-simple")
grunt.loadNpmTasks("grunt-contrib-copy") grunt.loadNpmTasks("grunt-contrib-copy")
grunt.loadNpmTasks("grunt-contrib-requirejs") grunt.loadNpmTasks("grunt-contrib-requirejs")
grunt.loadNpmTasks("grunt-sass") grunt.loadNpmTasks("grunt-sass")

View file

@ -4,6 +4,11 @@ module.exports = function (grunt) {
options: { options: {
install: true install: true
}, },
bower: {
options: {
packageManager: "bower"
}
},
npm: {} npm: {}
}, },
eslint: { eslint: {

3451
yarn.lock

File diff suppressed because it is too large Load diff