Compare commits
42 commits
Author | SHA1 | Date | |
---|---|---|---|
d70d3d7c5f | |||
fe17e32886 | |||
420be21fa5 | |||
a971dcfeed | |||
0a05523dd1 | |||
f416c33498 | |||
93e0a9c758 | |||
d231cbd5bc | |||
11368e60de | |||
587740af80 | |||
1235d8cb46 | |||
100268f3b7 | |||
35589eabef | |||
8f7c63bbce | |||
b2c2627d73 | |||
a7756c44e8 | |||
5f98da2717 | |||
1a6a4329b5 | |||
ccc5f0f526 | |||
5cb88e8d06 | |||
44bb8e9d3d | |||
7e6d054e98 | |||
94662cb3dc | |||
2ca2604403 | |||
0171ebe7e1 | |||
9e7049c9e3 | |||
7d145141c1 | |||
5a5ce1d346 | |||
224240c1c4 | |||
7eb0675be0 | |||
1641bc2437 | |||
84aee48229 | |||
e9711c6efc | |||
5599be5cd6 | |||
808b8c1986 | |||
00a8e5117d | |||
cb065d8d07 | |||
bf2e858c24 | |||
46de672dc9 | |||
07d5e3f636 | |||
cfd778dadb | |||
8f7b1e15ce |
10
.travis.yml
10
.travis.yml
|
@ -1,7 +1,7 @@
|
|||
language: node_js
|
||||
before_install:
|
||||
- gem install sass
|
||||
- npm install -g grunt-cli
|
||||
node_js:
|
||||
- "lts/*"
|
||||
- "node"
|
||||
install:
|
||||
- npm install
|
||||
script: grunt
|
||||
- yarn
|
||||
script: node_modules/.bin/grunt
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.loadTasks("tasks")
|
||||
|
||||
grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"])
|
||||
grunt.registerTask("default", ["lint", "saveRevision", "copy", "sass", "postcss", "requirejs"])
|
||||
grunt.registerTask("lint", ["eslint"])
|
||||
grunt.registerTask("dev", ["default", "connect:server", "watch"])
|
||||
}
|
||||
|
|
29
README.md
29
README.md
|
@ -1,8 +1,8 @@
|
|||
[![Build Status](https://travis-ci.org/plumpudding/hopglass.svg?branch=master)](https://travis-ci.org/plumpudding/hopglass)
|
||||
[![Build Status](https://travis-ci.org/hopglass/hopglass.svg?branch=master)](https://travis-ci.org/hopglass/hopglass)
|
||||
|
||||
# HopGlass
|
||||
|
||||
HopGlass is a frontend for the [HopGlass Server](https://github.com/plumpudding/hopglass-server).
|
||||
HopGlass is a frontend for the [HopGlass Server](https://github.com/hopglass/hopglass-server).
|
||||
|
||||
# Screenshots
|
||||
|
||||
|
@ -14,29 +14,32 @@ HopGlass is a frontend for the [HopGlass Server](https://github.com/plumpudding/
|
|||
|
||||
# Dependencies
|
||||
|
||||
- npm
|
||||
- bower
|
||||
- grunt-cli
|
||||
- Sass (>= 3.2)
|
||||
- NodeJS
|
||||
- yarn (recommended) or npm
|
||||
|
||||
# Installing dependencies
|
||||
|
||||
Install npm package-manager. On Debian-like systems run:
|
||||
|
||||
sudo apt-get install npm
|
||||
sudo apt-get install nodejs
|
||||
|
||||
On Mac you have to install only npm via brew and sass
|
||||
**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 can install nodejs and yarn via brew:
|
||||
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
brew install node
|
||||
sudo gem install sass
|
||||
brew install yarn
|
||||
|
||||
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:
|
||||
|
||||
git clone https://github.com/plumpudding/hopglass
|
||||
git clone https://github.com/hopglass/hopglass
|
||||
cd hopglass
|
||||
npm install
|
||||
npm install grunt-cli
|
||||
yarn install # or `npm install`
|
||||
|
||||
# Building
|
||||
|
||||
|
@ -52,7 +55,7 @@ Copy `config.json.example` to `build/config.json` and change it to match your co
|
|||
|
||||
## dataPath (string/array)
|
||||
|
||||
`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.
|
||||
`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.
|
||||
Don't forget the trailing slash!
|
||||
Also, proxying the data through a webserver will allow GZip and thus will greatly reduce bandwidth consumption.
|
||||
It may help with firewall problems too.
|
||||
|
|
26
app.js
26
app.js
|
@ -1,20 +1,20 @@
|
|||
require.config({
|
||||
baseUrl: "lib",
|
||||
paths: {
|
||||
"leaflet": "../bower_components/leaflet/dist/leaflet",
|
||||
"leaflet.label": "../bower_components/Leaflet.label/dist/leaflet.label",
|
||||
"leaflet.providers": "../bower_components/leaflet-providers/leaflet-providers",
|
||||
"chroma-js": "../bower_components/chroma-js/chroma.min",
|
||||
"moment": "../bower_components/moment/min/moment-with-locales.min",
|
||||
"tablesort": "../bower_components/tablesort/tablesort.min",
|
||||
"tablesort.numeric": "../bower_components/tablesort/src/sorts/tablesort.numeric",
|
||||
"d3": "../bower_components/d3/d3.min",
|
||||
"numeral": "../bower_components/numeraljs/min/numeral.min",
|
||||
"numeral-intl": "../bower_components/numeraljs/min/languages.min",
|
||||
"virtual-dom": "../bower_components/virtual-dom/dist/virtual-dom",
|
||||
"rbush": "../bower_components/rbush/rbush",
|
||||
"leaflet": "../node_modules/leaflet/dist/leaflet",
|
||||
"leaflet.label": "../node_modules/leaflet-label/dist/leaflet.label",
|
||||
"leaflet.providers": "../node_modules/leaflet-providers/leaflet-providers",
|
||||
"chroma-js": "../node_modules/chroma-js/chroma.min",
|
||||
"moment": "../node_modules/moment/min/moment-with-locales.min",
|
||||
"tablesort": "../node_modules/tablesort/tablesort.min",
|
||||
"tablesort.numeric": "../node_modules/tablesort/src/sorts/tablesort.numeric",
|
||||
"d3": "../node_modules/d3/d3.min",
|
||||
"numeral": "../node_modules/numeraljs/min/numeral.min",
|
||||
"numeral-intl": "../node_modules/numeraljs/min/languages.min",
|
||||
"virtual-dom": "../node_modules/virtual-dom/dist/virtual-dom",
|
||||
"rbush": "../node_modules/rbush/rbush",
|
||||
"helper": "../helper",
|
||||
"jshashes": "../bower_components/jshashes/hashes"
|
||||
"jshashes": "../node_modules/jshashes/hashes"
|
||||
},
|
||||
shim: {
|
||||
"leaflet.label": ["leaflet"],
|
||||
|
|
36
bower.json
36
bower.json
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"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
|
||||
}
|
2
build.js
2
build.js
|
@ -1,6 +1,6 @@
|
|||
({
|
||||
baseUrl: "lib",
|
||||
name: "../bower_components/almond/almond",
|
||||
name: "../node_modules/almond/almond",
|
||||
mainConfigFile: "app.js",
|
||||
include: "../app",
|
||||
wrap: true,
|
||||
|
|
|
@ -1,21 +1,62 @@
|
|||
{
|
||||
"dataPath": "https://map.luebeck.freifunk.net/data/",
|
||||
"siteName": "Freifunk Lübeck",
|
||||
"dataPath": "https://map.ffdus.de/data/",
|
||||
"siteName": "Freifunk Flingern",
|
||||
"mapSigmaScale": 0.5,
|
||||
"showContact": true,
|
||||
"showContact": true,
|
||||
"maxAge": 14,
|
||||
"mapLayers": [
|
||||
{ "name": "CartoDB",
|
||||
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
|
||||
"config": {
|
||||
"maxZoom": 18,
|
||||
"attribution": "© <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>, © | <a href=\"https://carto.com/attribution\">CARTO</a>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OpenStreetMap.HOT"
|
||||
},
|
||||
{
|
||||
"name": "Stamen.TonerLite"
|
||||
"name": "Luftbilder NRW",
|
||||
"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": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=1&theme=light&width=600&height=300&var-nodeid={NODE_ID}"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=2&theme=light&width=600&height=500&var-nodeid={NODE_ID}"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=3&theme=light&width=600&height=200&var-nodeid={NODE_ID}"
|
||||
}
|
||||
],
|
||||
"globalInfos": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=1&&theme=light&width=800&height=600&var-job=dus"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=8&&theme=light&width=800&height=600&var-job=dus"
|
||||
}
|
||||
],
|
||||
"linkInfos": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/links?var-source={SOURCE}&var-target={TARGET}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/links?panelId=1&&theme=light&width=800&height=600&var-source={SOURCE}&var-target={TARGET}"
|
||||
}
|
||||
],
|
||||
"siteNames": [
|
||||
{ "site": "ffhl", "name": "Lübeck" },
|
||||
{ "site": "ffeh", "name": "Entenhausen" },
|
||||
{ "site": "ffgt", "name": "Gothamcity" },
|
||||
{ "site": "ffal", "name": "Atlantis" }
|
||||
{ "site": "dus", "name": "Flingern" }
|
||||
],
|
||||
"hwImg": [
|
||||
{ "thumbnail": "https://cdn.rawgit.com/Moorviper/meshviewer_hwpics/master/nodes/{MODELHASH}.svg",
|
||||
"caption": "Knoten {MODELHASH}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -132,9 +132,10 @@ function attributeEntry(el, label, value) {
|
|||
var th = document.createElement("th")
|
||||
if (typeof label === "string")
|
||||
th.textContent = label
|
||||
|
||||
else
|
||||
else {
|
||||
th.appendChild(label)
|
||||
tr.className = "routerpic"
|
||||
}
|
||||
|
||||
tr.appendChild(th)
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="stylesheet" href="css/ionicons.min.css">
|
||||
<link rel="stylesheet" href="roboto-slab-fontface.css">
|
||||
<link rel="stylesheet" href="roboto-fontface.css">
|
||||
<link rel="stylesheet" href="css/roboto-slab/roboto-slab-fontface.css">
|
||||
<link rel="stylesheet" href="css/roboto/roboto-fontface.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="vendor/es6-shim/es6-shim.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
|
@ -14,5 +14,15 @@
|
|||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="loader">
|
||||
<p>
|
||||
Lade<br />
|
||||
<span class="spinner"></span><br />
|
||||
Karte & Knoten...
|
||||
</p>
|
||||
<noscript>
|
||||
<strong>JavaScript required</strong>
|
||||
</noscript>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
14
index.html
14
index.html
|
@ -3,14 +3,14 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="stylesheet" href="bower_components/roboto-slab-fontface/roboto-slab-fontface.css">
|
||||
<link rel="stylesheet" href="bower_components/roboto-fontface/roboto-fontface.css">
|
||||
<link rel="stylesheet" href="bower_components/leaflet/dist/leaflet.css">
|
||||
<link rel="stylesheet" href="bower_components/Leaflet.label/dist/leaflet.label.css">
|
||||
<link rel="stylesheet" href="bower_components/ionicons/css/ionicons.min.css">
|
||||
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto-slab/roboto-slab-fontface.css">
|
||||
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto/roboto-fontface.css">
|
||||
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css">
|
||||
<link rel="stylesheet" href="node_modules/leaflet-label/dist/leaflet.label.css">
|
||||
<link rel="stylesheet" href="node_modules/ionicons/css/ionicons.min.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="bower_components/es6-shim/es6-shim.min.js"></script>
|
||||
<script src="bower_components/requirejs/require.js" data-main="app"></script>
|
||||
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
|
||||
<script src="node_modules/requirejs/require.js" data-main="app"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
|
|
@ -29,8 +29,8 @@ define(function () {
|
|||
s += "https://www.gnu.org/licenses/</a>.</p>"
|
||||
|
||||
s += "<p>The source code is available at "
|
||||
s += "<a href=\"https://github.com/plumpudding/hopglass\">"
|
||||
s += "https://github.com/plumpudding/hopglass</a>."
|
||||
s += "<a href=\"https://github.com/hopglass/hopglass\">"
|
||||
s += "https://github.com/hopglass/hopglass</a>."
|
||||
|
||||
el.innerHTML = s
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(["d3"], function (d3) {
|
||||
var margin = 200
|
||||
var NODE_RADIUS = 15
|
||||
var LINE_RADIUS = 12
|
||||
var LINE_RADIUS = 7
|
||||
|
||||
return function (config, linkScale, sidebar, router) {
|
||||
var self = this
|
||||
|
@ -242,7 +242,8 @@ define(["d3"], function (d3) {
|
|||
}
|
||||
|
||||
function visibleLinks(d) {
|
||||
return (d.source.x > screenRect.left && d.source.x < screenRect.right &&
|
||||
return (d.o.isVPN ||
|
||||
d.source.x > screenRect.left && d.source.x < screenRect.right &&
|
||||
d.source.y > screenRect.top && d.source.y < screenRect.bottom) ||
|
||||
(d.target.x > screenRect.left && d.target.x < screenRect.right &&
|
||||
d.target.y > screenRect.top && d.target.y < screenRect.bottom)
|
||||
|
@ -324,13 +325,16 @@ define(["d3"], function (d3) {
|
|||
links.forEach(function (d) {
|
||||
var dx = d.target.x - d.source.x
|
||||
var dy = d.target.y - d.source.y
|
||||
var a = Math.sqrt(dx * dx + dy * dy)
|
||||
var a = Math.sqrt(dx * dx + dy * dy) * 2
|
||||
dx /= a
|
||||
dy /= a
|
||||
|
||||
var distancex = d.target.x - d.source.x - (10 * dx)
|
||||
var distancey = d.target.y - d.source.y - (10 * dy)
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(d.source.x + dx * nodeRadius, d.source.y + dy * nodeRadius)
|
||||
ctx.lineTo(d.target.x - dx * nodeRadius, d.target.y - dy * nodeRadius)
|
||||
ctx.lineTo(d.target.x - (distancex / 2) - dx * nodeRadius, d.target.y - (distancey / 2) - dy * nodeRadius)
|
||||
ctx.strokeStyle = d.o.type === "Kabel" ? cableColor : d.color
|
||||
ctx.globalAlpha = d.o.isVPN ? 0.1 : 0.8
|
||||
ctx.lineWidth = d.o.isVPN ? 1.5 : 2.5
|
||||
|
@ -376,31 +380,32 @@ define(["d3"], function (d3) {
|
|||
// -- draw clients --
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
nodes.filter(visibleNodes).forEach(function (d) {
|
||||
var clients = d.o.node.statistics.clients
|
||||
if (clients === 0)
|
||||
return
|
||||
if (scale > 0.9)
|
||||
nodes.filter(visibleNodes).forEach(function (d) {
|
||||
var clients = d.o.node.statistics.clients
|
||||
if (clients === 0)
|
||||
return
|
||||
|
||||
var startDistance = 16
|
||||
var radius = 3
|
||||
var a = 1.2
|
||||
var startAngle = Math.PI
|
||||
var startDistance = 16
|
||||
var radius = 3
|
||||
var a = 1.2
|
||||
var startAngle = Math.PI
|
||||
|
||||
for (var orbit = 0, i = 0; i < clients; orbit++) {
|
||||
var distance = startDistance + orbit * 2 * radius * a
|
||||
var n = Math.floor((Math.PI * distance) / (a * radius))
|
||||
var delta = clients - i
|
||||
for (var orbit = 0, i = 0; i < clients; orbit++) {
|
||||
var distance = startDistance + orbit * 2 * radius * a
|
||||
var n = Math.floor((Math.PI * distance) / (a * radius))
|
||||
var delta = clients - i
|
||||
|
||||
for (var j = 0; j < Math.min(delta, n); i++, j++) {
|
||||
var angle = 2 * Math.PI / n * j
|
||||
var x = d.x + distance * Math.cos(angle + startAngle)
|
||||
var y = d.y + distance * Math.sin(angle + startAngle)
|
||||
for (var j = 0; j < Math.min(delta, n); i++, j++) {
|
||||
var angle = 2 * Math.PI / n * j
|
||||
var x = d.x + distance * Math.cos(angle + startAngle)
|
||||
var y = d.y + distance * Math.sin(angle + startAngle)
|
||||
|
||||
ctx.moveTo(x, y)
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI)
|
||||
ctx.moveTo(x, y)
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
ctx.fillStyle = clientColor
|
||||
ctx.fill()
|
||||
|
@ -470,32 +475,34 @@ define(["d3"], function (d3) {
|
|||
requestAnimationFrame(redraw)
|
||||
}
|
||||
|
||||
function distance(a, b) {
|
||||
return Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)
|
||||
function distance(ax, ay, bx, by) {
|
||||
return Math.pow(ax - bx, 2) + Math.pow(ay - by, 2)
|
||||
}
|
||||
|
||||
function distancePoint(a, b) {
|
||||
return Math.sqrt(distance(a, b))
|
||||
return Math.sqrt(distance(a.x, a.y, b.x, b.y))
|
||||
}
|
||||
|
||||
function distanceLink(p, a, b) {
|
||||
/* http://stackoverflow.com/questions/849211 */
|
||||
|
||||
var l2 = distance(a, b)
|
||||
var bx = b.x - ((b.x - a.x) / 2)
|
||||
var by = b.y - ((b.y - a.y) / 2)
|
||||
|
||||
var l2 = distance(a.x, a.y, bx, by)
|
||||
|
||||
if (l2 === 0)
|
||||
return distance(p, a)
|
||||
return distance(p.x, p.y, a.x, a.y)
|
||||
|
||||
var t = ((p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y)) / l2
|
||||
var t = ((p.x - a.x) * (bx - a.x) + (p.y - a.y) * (by - a.y)) / l2
|
||||
|
||||
if (t < 0)
|
||||
return distance(p, a)
|
||||
return distance(p.x, p.y, a.x, a.y)
|
||||
|
||||
if (t > 1)
|
||||
return distance(p, b)
|
||||
return distance(p.x, p.y, bx, by)
|
||||
|
||||
return Math.sqrt(distance(p, { x: a.x + t * (b.x - a.x),
|
||||
y: a.y + t * (b.y - a.y) }))
|
||||
return Math.sqrt(distance(p.x, p.y, a.x + t * (bx - a.x), a.y + t * (by - a.y) ))
|
||||
}
|
||||
|
||||
function translateXY(d) {
|
||||
|
@ -696,6 +703,15 @@ define(["d3"], function (d3) {
|
|||
linksDict[d.o.id] = d
|
||||
})
|
||||
|
||||
intLinks.forEach(function (d) {
|
||||
if (linksDict[d.target.o.node_id + "-" + d.source.o.node_id])
|
||||
return
|
||||
|
||||
var obj = { source: d.target, target: d.source, o: { isVPN: d.o.isVPN, type: "dead", id: d.target.o.node_id + "-" + d.source.o.node_id, tq: 1 }, color: "rgba(255, 255, 255, 0.6)" }
|
||||
intLinks.push(obj)
|
||||
linksDict[d.target.o.node_id + "-" + d.source.o.node_id] = obj
|
||||
})
|
||||
|
||||
intNodes.forEach(function (d) {
|
||||
d.neighbours = Object.keys(d.neighbours).map(function (k) {
|
||||
return d.neighbours[k]
|
||||
|
|
|
@ -48,6 +48,9 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
|||
}
|
||||
}
|
||||
|
||||
var loader = document.getElementsByClassName("loader")[0]
|
||||
loader.classList.add("hide")
|
||||
|
||||
contentDiv = document.createElement("div")
|
||||
contentDiv.classList.add("content")
|
||||
document.body.appendChild(contentDiv)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
define(function () {
|
||||
function showStatImg(o, source, target) {
|
||||
function showStatImg(o, d) {
|
||||
var subst = {}
|
||||
subst["{SOURCE}"] = source
|
||||
subst["{TARGET}"] = target
|
||||
subst["{SOURCE}"] = d.source.node_id
|
||||
subst["{SOURCE_NAME}"] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname : "unknown"
|
||||
subst["{TARGET}"] = d.target.node_id
|
||||
subst["{TARGET_NAME}"] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname : "unknown"
|
||||
return showStat(o, subst)
|
||||
}
|
||||
|
||||
|
@ -35,15 +37,12 @@ define(function () {
|
|||
attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt"))
|
||||
el.appendChild(attributes)
|
||||
|
||||
if (config.linkInfos) {
|
||||
var source = d.source.node_id
|
||||
var target = d.target.node_id
|
||||
if (config.linkInfos)
|
||||
config.linkInfos.forEach( function (linkInfo) {
|
||||
var h4 = document.createElement("h4")
|
||||
h4.textContent = linkInfo.name
|
||||
el.appendChild(h4)
|
||||
el.appendChild(showStatImg(linkInfo, source, target))
|
||||
el.appendChild(showStatImg(linkInfo, d))
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -133,14 +133,72 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
if (!d.flags.online)
|
||||
return undefined
|
||||
|
||||
var meshclients = getMeshClients(d)
|
||||
resetMeshClients(d)
|
||||
var before = " ("
|
||||
var after = " in der lokalen Wolke)"
|
||||
return function (el) {
|
||||
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"))
|
||||
el.appendChild(document.createTextNode(before))
|
||||
el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
|
||||
el.appendChild(document.createTextNode(after))
|
||||
el.appendChild(document.createElement("br"))
|
||||
|
||||
var span = document.createElement("span")
|
||||
span.classList.add("clients")
|
||||
span.textContent = " ".repeat(d.statistics.clients)
|
||||
el.appendChild(span)
|
||||
|
||||
var spanmesh = document.createElement("span")
|
||||
spanmesh.classList.add("clientsMesh")
|
||||
spanmesh.textContent = " ".repeat(meshclients - d.statistics.clients)
|
||||
el.appendChild(spanmesh)
|
||||
}
|
||||
}
|
||||
|
||||
function getMeshClients(node) {
|
||||
var meshclients = 0
|
||||
if (node.statistics && !isNaN(node.statistics.clients))
|
||||
meshclients = node.statistics.clients
|
||||
|
||||
if (!node)
|
||||
return 0
|
||||
|
||||
if (node.parsed)
|
||||
return 0
|
||||
|
||||
node.parsed = 1
|
||||
node.neighbours.forEach(function (neighbour) {
|
||||
if (!neighbour.link.isVPN && neighbour.node)
|
||||
meshclients += getMeshClients(neighbour.node)
|
||||
})
|
||||
|
||||
return meshclients
|
||||
}
|
||||
|
||||
function resetMeshClients(node) {
|
||||
if (!node.parsed)
|
||||
return
|
||||
|
||||
node.parsed = 0
|
||||
|
||||
node.neighbours.forEach(function (neighbour) {
|
||||
if (!neighbour.link.isVPN && neighbour.node)
|
||||
resetMeshClients(neighbour.node)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
function showMeshClients(d) {
|
||||
if (!d.flags.online)
|
||||
return undefined
|
||||
|
||||
var meshclients = getMeshClients(d)
|
||||
resetMeshClients(d)
|
||||
return function (el) {
|
||||
el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
|
||||
el.appendChild(document.createElement("br"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +218,10 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
|
||||
if (link) {
|
||||
var a = document.createElement("a")
|
||||
a.href = "http://[" + ip + "]/"
|
||||
if (ip.includes("."))
|
||||
a.href = "http://" + ip + "/"
|
||||
else
|
||||
a.href = "http://[" + ip + "]/"
|
||||
a.textContent = ip
|
||||
el.appendChild(a)
|
||||
} else
|
||||
|
@ -204,7 +265,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
}
|
||||
|
||||
var label = document.createElement("label")
|
||||
label.textContent = (v)
|
||||
label.textContent = +(Math.round(v + "e+2") + "e-2")
|
||||
span.appendChild(label)
|
||||
|
||||
return span
|
||||
|
@ -237,7 +298,22 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
}
|
||||
}
|
||||
|
||||
function showGateway(d) {
|
||||
function createLink(target, router) {
|
||||
if (!target) return document.createTextNode("unknown")
|
||||
var unknown = !(target.node)
|
||||
var text = unknown ? (target.id ? target.id : target) : target.node.nodeinfo.hostname
|
||||
if (!unknown) {
|
||||
var link = document.createElement("a")
|
||||
link.classList.add("hostname-link")
|
||||
link.href = "#"
|
||||
link.onclick = router.node(target.node)
|
||||
link.textContent = text
|
||||
return link
|
||||
}
|
||||
return document.createTextNode(text)
|
||||
}
|
||||
|
||||
function showGateway(d, router) {
|
||||
var nh
|
||||
if (dictGet(d.statistics, ["nexthop"]))
|
||||
nh = dictGet(d.statistics, ["nexthop"])
|
||||
|
@ -245,13 +321,31 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
nh = dictGet(d.statistics, ["gateway_nexthop"])
|
||||
var gw = dictGet(d.statistics, ["gateway"])
|
||||
|
||||
if (gw && !nh)
|
||||
return gw
|
||||
if (gw && nh)
|
||||
if (gw === nh)
|
||||
return gw
|
||||
else
|
||||
return nh + " -> ... -> " + gw
|
||||
if (!gw) return null
|
||||
return function (el) {
|
||||
var num = 0
|
||||
while (gw && nh && gw.id !== nh.id && num < 10) {
|
||||
if (num !== 0) el.appendChild(document.createTextNode(" -> "))
|
||||
el.appendChild(createLink(nh, router))
|
||||
num++
|
||||
if (!nh.node || !nh.node.statistics) break
|
||||
if (!dictGet(nh.node.statistics, ["gateway"]) || !dictGet(nh.node.statistics, ["gateway"]).id) break
|
||||
if (dictGet(nh.node.statistics, ["gateway"]).id !== gw.id) break
|
||||
if (dictGet(nh.node.statistics, ["gateway_nexthop"]))
|
||||
nh = dictGet(nh.node.statistics, ["gateway_nexthop"])
|
||||
else if (dictGet(nh.node.statistics, ["nexthop"]))
|
||||
nh = dictGet(nh.node.statistics, ["nexthop"])
|
||||
else
|
||||
break
|
||||
}
|
||||
if (gw && nh && gw.id !== nh.id) {
|
||||
if (num !== 0) el.appendChild(document.createTextNode(" -> "))
|
||||
num++
|
||||
el.appendChild(document.createTextNode("..."))
|
||||
}
|
||||
if (num !== 0) el.appendChild(document.createTextNode(" -> "))
|
||||
el.appendChild(createLink(gw, router))
|
||||
}
|
||||
}
|
||||
|
||||
function showPages(d) {
|
||||
|
@ -295,7 +389,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
|
||||
function showNodeImg(o, model) {
|
||||
if (!model)
|
||||
return undefined
|
||||
return document.createTextNode("Knotenname")
|
||||
|
||||
var content, caption
|
||||
var modelhash = model.split("").reduce(function(a, b) {
|
||||
|
@ -303,15 +397,12 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
return a & a
|
||||
}, 0)
|
||||
|
||||
if (o.thumbnail) {
|
||||
content = document.createElement("img")
|
||||
content.id = "routerpicture"
|
||||
content.classList.add("nodeImg")
|
||||
content.src = o.thumbnail.replace("{MODELHASH}", modelhash)
|
||||
content.onerror = function() {
|
||||
console.log("Router-Bild nicht vorhanden !!! create an issue @ https://github.com/Moorviper/Freifunk-Router-Anleitungen/issues")
|
||||
document.getElementById("routerpicdiv").outerHTML = "Knotenname"
|
||||
}
|
||||
content = document.createElement("img")
|
||||
content.id = "routerpicture"
|
||||
content.classList.add("nodeImg")
|
||||
content.src = o.thumbnail.replace("{MODELHASH}", modelhash)
|
||||
content.onerror = function() {
|
||||
document.getElementById("routerpicdiv").outerHTML = "Knotenname"
|
||||
}
|
||||
|
||||
if (o.caption) {
|
||||
|
@ -325,7 +416,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
p.appendChild(content)
|
||||
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
function showStatImg(o, d) {
|
||||
var subst = {}
|
||||
|
@ -335,44 +426,30 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
}
|
||||
|
||||
return function(config, el, router, d) {
|
||||
var top = document.createElement("div")
|
||||
top.id = "routerpicdiv"
|
||||
try {
|
||||
if (config.hwImg)
|
||||
config.hwImg.forEach(function(hwImg) {
|
||||
try {
|
||||
top.appendChild(showNodeImg(hwImg, d.nodeinfo.hardware.model))
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
})
|
||||
|
||||
else
|
||||
{
|
||||
var localpic = [] // create fallback-config-data
|
||||
localpic.push({
|
||||
thumbnail: "./nodes/{MODELHASH}.svg",
|
||||
caption: "Knoten {MODELHASH}"
|
||||
})
|
||||
localpic.forEach(function(localpic) {
|
||||
try {
|
||||
top.appendChild(showNodeImg(localpic, d.nodeinfo.hardware.model))
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
|
||||
var attributes = document.createElement("table")
|
||||
attributes.classList.add("attributes")
|
||||
|
||||
attributeEntry(attributes, top, d.nodeinfo.hostname)
|
||||
if (config.hwImg) {
|
||||
var top = document.createElement("div")
|
||||
top.id = "routerpicdiv"
|
||||
try {
|
||||
config.hwImg.forEach(function(hwImg) {
|
||||
try {
|
||||
top.appendChild(showNodeImg(hwImg, dictGet(d, ["nodeinfo", "hardware", "model"])))
|
||||
} catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
attributeEntry(attributes, top, d.nodeinfo.hostname)
|
||||
} else {
|
||||
var h2 = document.createElement("h2")
|
||||
h2.textContent = d.nodeinfo.hostname
|
||||
el.appendChild(h2)
|
||||
}
|
||||
|
||||
attributeEntry(attributes, "Status", showStatus(d))
|
||||
attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null)
|
||||
attributeEntry(attributes, "Koordinaten", showGeoURI(d))
|
||||
|
@ -395,9 +472,9 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
attributeEntry(attributes, "Arbeitsspeicher", showRAM(d))
|
||||
attributeEntry(attributes, "IP Adressen", showIPs(d))
|
||||
attributeEntry(attributes, "Webseite", showPages(d))
|
||||
attributeEntry(attributes, "Gewähltes Gateway", showGateway(d))
|
||||
attributeEntry(attributes, "Gewähltes Gateway", showGateway(d, router))
|
||||
attributeEntry(attributes, "Autom. Updates", showAutoupdate(d))
|
||||
attributeEntry(attributes, "Clients", showClients(d))
|
||||
attributeEntry(attributes, "Clients", showClients(d), showMeshClients(d))
|
||||
|
||||
el.appendChild(attributes)
|
||||
|
||||
|
@ -454,13 +531,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
|
|||
tr.appendChild(td1)
|
||||
|
||||
var td2 = document.createElement("td")
|
||||
var a1 = document.createElement("a")
|
||||
a1.classList.add("hostname")
|
||||
a1.textContent = unknown ? d.id : d.node.nodeinfo.hostname
|
||||
if (!unknown)
|
||||
a1.href = "#"
|
||||
a1.onclick = router.node(d.node)
|
||||
td2.appendChild(a1)
|
||||
td2.appendChild(createLink(d, router))
|
||||
|
||||
if (!unknown && has_location(d.node)) {
|
||||
var span = document.createElement("span")
|
||||
|
|
15
lib/main.js
15
lib/main.js
|
@ -123,10 +123,19 @@ function (moment, Router, L, GUI, numeral) {
|
|||
|
||||
nodes.forEach( function (d) {
|
||||
d.neighbours = []
|
||||
if (d.statistics) {
|
||||
/*eslint camelcase:0*/
|
||||
if ("gateway" in d.statistics && d.statistics.gateway in graphnodes)
|
||||
d.statistics.gateway = {"node": graphnodes[d.statistics.gateway], "id": d.statistics.gateway}
|
||||
if ("nexthop" in d.statistics && d.statistics.nexthop in graphnodes)
|
||||
d.statistics.nexthop = {"node": graphnodes[d.statistics.nexthop], "id": d.statistics.nexthop}
|
||||
if ("gateway_nexthop" in d.statistics && d.statistics.gateway_nexthop in graphnodes)
|
||||
d.statistics.gateway_nexthop = {"node": graphnodes[d.statistics.gateway_nexthop], "id": d.statistics.gateway_nexthop}
|
||||
}
|
||||
})
|
||||
|
||||
links.forEach( function (d) {
|
||||
if (d.type === "tunnel") {
|
||||
if (d.type === "tunnel" || d.vpn) {
|
||||
d.type = "VPN"
|
||||
d.isVPN = true
|
||||
} else if (d.type === "fastd") {
|
||||
|
@ -148,6 +157,10 @@ function (moment, Router, L, GUI, numeral) {
|
|||
d.type = "N/A"
|
||||
d.isVPN = false
|
||||
}
|
||||
|
||||
if (d.isVPN && d.target.node)
|
||||
d.target.node.flags.uplink = true
|
||||
|
||||
var unknown = (d.source.node === undefined)
|
||||
if (unknown) {
|
||||
d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true })
|
||||
|
|
|
@ -286,7 +286,7 @@ define(["map/clientlayer", "map/labelslayer",
|
|||
var layers = config.mapLayers.map( function (d) {
|
||||
return {
|
||||
"name": d.name,
|
||||
"layer": "url" in d ? L.tileLayer(d.url, d.config) : L.tileLayer.provider(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)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
define(["leaflet", "jshashes"],
|
||||
function (L, jsHashes) {
|
||||
var MD5 = new jsHashes.MD5()
|
||||
|
||||
define(["leaflet"],
|
||||
function (L) {
|
||||
return L.TileLayer.Canvas.extend({
|
||||
setData: function (d) {
|
||||
this.data = d
|
||||
|
||||
//pre-calculate start angles
|
||||
this.data.all().forEach(function (d) {
|
||||
var hash = MD5.hex(d.node.nodeinfo.node_id)
|
||||
d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI
|
||||
d.startAngle = (parseInt(d.node.nodeinfo.node_id.substr(10, 2), 16) / 255) * 2 * Math.PI
|
||||
})
|
||||
this.redraw()
|
||||
},
|
||||
|
|
|
@ -13,7 +13,7 @@ define(function () {
|
|||
return d.statistics.clients ? d.statistics.clients : 0
|
||||
}))
|
||||
var totalGateways = sum(Array.from(new Set(d.nodes.all.filter(online).map( function(d) {
|
||||
return d.statistics.gateway
|
||||
return ("gateway" in d.statistics && d.statistics.gateway.id) ? d.statistics.gateway.id : d.statistics.gateway
|
||||
}).concat(d.nodes.all.filter( function (d) {
|
||||
return d.flags.gateway
|
||||
})))).map(function(d) {
|
||||
|
|
|
@ -21,7 +21,11 @@ define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral)
|
|||
|
||||
var headings = [{ name: "Knoten",
|
||||
sort: function (a, b) {
|
||||
return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname)
|
||||
var aname = typeof a.nodeinfo.hostname === "string" ? a.nodeinfo.hostname : a.nodeinfo.node_id
|
||||
var bname = typeof b.nodeinfo.hostname === "string" ? b.nodeinfo.hostname : b.nodeinfo.node_id
|
||||
if (typeof aname === "string" && typeof bname === "string")
|
||||
return aname.localeCompare(bname)
|
||||
return typeof aname === "string" ? 1 : typeof bname === "string" ? -1 : 0
|
||||
},
|
||||
reverse: false
|
||||
},
|
||||
|
@ -52,7 +56,7 @@ define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral)
|
|||
|
||||
td1Content.push(V.h("a", { className: aClass.join(" "),
|
||||
onclick: router.node(d),
|
||||
href: "#"
|
||||
href: "#!n:" + d.nodeinfo.node_id
|
||||
}, d.nodeinfo.hostname))
|
||||
|
||||
if (has_location(d))
|
||||
|
|
|
@ -156,8 +156,11 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
|
|||
if (d === null)
|
||||
return null
|
||||
|
||||
if (d in nodeDict)
|
||||
return nodeDict[d].nodeinfo.hostname
|
||||
if (d.node)
|
||||
return d.node.nodeinfo.hostname
|
||||
|
||||
if (d.id)
|
||||
return d.id
|
||||
|
||||
return d
|
||||
})
|
||||
|
@ -166,8 +169,11 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
|
|||
if (d === null)
|
||||
return null
|
||||
|
||||
if (d in nodeDict)
|
||||
return nodeDict[d].nodeinfo.hostname
|
||||
if (d.node)
|
||||
return d.node.nodeinfo.hostname
|
||||
|
||||
if (d.id)
|
||||
return d.id
|
||||
|
||||
return d
|
||||
})
|
||||
|
@ -188,8 +194,8 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
|
|||
fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Uplink", uplinkTable, uplinkDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Nodes an Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Clients an Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
fillTable("Site", siteTable, siteDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ define(["moment", "virtual-dom"], function (moment, V) {
|
|||
|
||||
td1Content.push(V.h("a", { className: aClass.join(" "),
|
||||
onclick: router.node(d),
|
||||
href: "#"
|
||||
href: "#!n:" + d.nodeinfo.node_id
|
||||
}, d.nodeinfo.hostname))
|
||||
|
||||
if (has_location(d))
|
||||
|
|
27
package.json
27
package.json
|
@ -1,24 +1,41 @@
|
|||
{
|
||||
"name": "hopglass",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"test": "node -e \"require('grunt').cli()\" '' clean lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.3.3",
|
||||
"grunt": "^0.4.5",
|
||||
"dart-sass": "^1.16.1",
|
||||
"grunt": "^1.0.3",
|
||||
"grunt-check-dependencies": "^0.6.0",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
"grunt-contrib-connect": "^0.8.0",
|
||||
"grunt-contrib-copy": "^0.5.0",
|
||||
"grunt-contrib-cssmin": "^0.12.2",
|
||||
"grunt-contrib-requirejs": "^0.4.4",
|
||||
"grunt-sass": "^1.1.0",
|
||||
"grunt-postcss": "^0.7.2",
|
||||
"grunt-contrib-uglify": "^0.5.1",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-eslint": "^10.0.0",
|
||||
"grunt-bower-install-simple": "^1.1.2",
|
||||
"grunt-git-describe": "^2.3.2"
|
||||
"grunt-git-describe": "^2.3.2",
|
||||
"grunt-postcss": "^0.7.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": {
|
||||
"env": {
|
||||
|
|
|
@ -28,3 +28,7 @@ h5 {
|
|||
h6 {
|
||||
font-size: 0.67em;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
../bower_components/Leaflet.label/dist/leaflet.label.css
|
||||
../node_modules/leaflet-label/dist/leaflet.label.css
|
|
@ -1 +1 @@
|
|||
../bower_components/leaflet/dist/leaflet.css
|
||||
../node_modules/leaflet/dist/leaflet.css
|
23
scss/_loader.scss
Normal file
23
scss/_loader.scss
Normal file
|
@ -0,0 +1,23 @@
|
|||
.loader {
|
||||
color: #000000;
|
||||
font-size: 1.8em;
|
||||
line-height: 2;
|
||||
margin: 30vh auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
animation: .6s spinner ease-in-out infinite alternate;
|
||||
border-bottom: 2px solid #000000;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 64px;
|
||||
margin-top: 10px;
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
@keyframes spinner {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
|
@ -1,40 +1,36 @@
|
|||
.nodeheader {
|
||||
width: 90%;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.nodeheader img {
|
||||
width: 30%;
|
||||
max-height: 180px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
max-width: 128px;
|
||||
display: block;
|
||||
z-index: 2;
|
||||
width: 30%;
|
||||
max-height: 180px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
max-width: 128px;
|
||||
display: block;
|
||||
z-index: 2;
|
||||
}
|
||||
.nodeheader img .none{
|
||||
display: none;
|
||||
|
||||
.nodeheader img .none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nodeheader span {
|
||||
background-color: silver;
|
||||
background-color: hsla(0, 0%, 100%, 0.5);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
line-height: 1.5em;
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
font-size: large;
|
||||
z-index: 2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.limit {
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
background-color: silver;
|
||||
background-color: hsla(0, 0%, 100%, 0.5);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
line-height: 1.5em;
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
font-size: large;
|
||||
z-index: 2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
@import '_leaflet';
|
||||
@import '_leaflet.label';
|
||||
@import '_filters';
|
||||
@import '_loader';
|
||||
|
||||
$minscreenwidth: 630pt;
|
||||
$sidebarwidth: 420pt;
|
||||
|
@ -69,8 +70,9 @@ $buttondistance: 12pt;
|
|||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Roboto Slab', serif;
|
||||
font-family: 'Roboto-Slab', serif;
|
||||
font-size: 11pt;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
th.sort-header::selection {
|
||||
|
@ -101,11 +103,6 @@ table th.sort-up:after {
|
|||
content: '\f104';
|
||||
}
|
||||
|
||||
table.attributes {
|
||||
top: 1px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.attributes th {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
|
@ -121,7 +118,7 @@ table.attributes td {
|
|||
line-height: 1.41em;
|
||||
}
|
||||
|
||||
table.attributes tr:first-child {
|
||||
table.attributes tr.routerpic {
|
||||
max-height: 128px;
|
||||
max-width: 128px;
|
||||
min-width: 128px;
|
||||
|
@ -130,14 +127,14 @@ table.attributes tr:first-child {
|
|||
/*background-color: green;*/
|
||||
}
|
||||
|
||||
table.attributes tr:first-child td{
|
||||
table.attributes tr.routerpic td {
|
||||
font-weight: bold;
|
||||
/*background-color: red;*/
|
||||
font-size: large;
|
||||
vertical-align:bottom;
|
||||
}
|
||||
|
||||
table.attributes tr:first-child th{
|
||||
table.attributes tr.routerpic th {
|
||||
font-weight: bold;
|
||||
/*background-color: red;*/
|
||||
font-size: large;
|
||||
|
@ -158,7 +155,6 @@ table.attributes tr:first-child th{
|
|||
@include shadow(2);
|
||||
background: rgba(255, 255, 255, 0.97);
|
||||
border-radius: 2px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.container.hidden {
|
||||
|
@ -181,6 +177,13 @@ table.attributes tr:first-child th{
|
|||
white-space: normal;
|
||||
}
|
||||
|
||||
.infobox .clientsMesh {
|
||||
font-family: "ionicons";
|
||||
color: #dbdbdb;
|
||||
word-spacing: -0.2em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.infobox {
|
||||
position: relative;
|
||||
padding: 0.25em 0;
|
||||
|
@ -218,6 +221,7 @@ button {
|
|||
@include shadow(1);
|
||||
border-radius: 0.9em;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
color: #333;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
height: 1.8em;
|
||||
|
@ -257,6 +261,8 @@ button.close {
|
|||
border-radius: 0;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
font-family: "ionicons";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
&:hover {
|
||||
color: #dc0067;
|
||||
|
@ -358,7 +364,7 @@ table {
|
|||
position: absolute;
|
||||
top: $buttondistance;
|
||||
left: $buttondistance;
|
||||
margin-bottom: $buttondistance;
|
||||
padding-bottom: $buttondistance;
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = function(grunt) {
|
||||
grunt.config.merge({
|
||||
bowerdir: "bower_components",
|
||||
nodedir: "node_modules",
|
||||
copy: {
|
||||
html: {
|
||||
options: {
|
||||
|
@ -19,26 +19,21 @@ module.exports = function(grunt) {
|
|||
dest: "build/"
|
||||
},
|
||||
vendorjs: {
|
||||
src: [ "es6-shim/es6-shim.min.js" ],
|
||||
src: ["es6-shim/es6-shim.min.js",
|
||||
"es6-shim/es6-shim.map"],
|
||||
expand: true,
|
||||
cwd: "bower_components/",
|
||||
cwd: "node_modules/",
|
||||
dest: "build/vendor/"
|
||||
},
|
||||
robotoSlab: {
|
||||
src: [ "fonts/*",
|
||||
"roboto-slab-fontface.css"
|
||||
],
|
||||
expand: true,
|
||||
dest: "build/",
|
||||
cwd: "bower_components/roboto-slab-fontface"
|
||||
},
|
||||
roboto: {
|
||||
src: [ "fonts/*",
|
||||
"roboto-fontface.css"
|
||||
src: [ "fonts/roboto/*",
|
||||
"fonts/roboto-slab/*",
|
||||
"css/roboto/roboto-fontface.css",
|
||||
"css/roboto-slab/roboto-slab-fontface.css"
|
||||
],
|
||||
expand: true,
|
||||
dest: "build/",
|
||||
cwd: "bower_components/roboto-fontface"
|
||||
cwd: "node_modules/roboto-fontface/"
|
||||
},
|
||||
ionicons: {
|
||||
src: [ "fonts/*",
|
||||
|
@ -46,19 +41,20 @@ module.exports = function(grunt) {
|
|||
],
|
||||
expand: true,
|
||||
dest: "build/",
|
||||
cwd: "bower_components/ionicons/"
|
||||
cwd: "node_modules/ionicons/"
|
||||
},
|
||||
leafletImages: {
|
||||
src: [ "images/*" ],
|
||||
expand: true,
|
||||
dest: "build/",
|
||||
cwd: "bower_components/leaflet/dist/"
|
||||
cwd: "node_modules/leaflet/dist/"
|
||||
}
|
||||
},
|
||||
sass: {
|
||||
options: {
|
||||
sourceMap: true,
|
||||
outputStyle: "compressed"
|
||||
outputStyle: "compressed",
|
||||
implementation: require("dart-sass")
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
|
@ -82,31 +78,18 @@ module.exports = function(grunt) {
|
|||
cssmin: {
|
||||
target: {
|
||||
files: {
|
||||
"build/style.css": [ "bower_components/leaflet/dist/leaflet.css",
|
||||
"bower_components/Leaflet.label/dist/leaflet.label.css",
|
||||
"build/style.css": [ "node_modules/leaflet/dist/leaflet.css",
|
||||
"node_modules/leaflet-label/dist/leaflet.label.css",
|
||||
"style.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"bower-install-simple": {
|
||||
options: {
|
||||
directory: "<%=bowerdir%>",
|
||||
color: true,
|
||||
interactive: false,
|
||||
production: true
|
||||
},
|
||||
"prod": {
|
||||
options: {
|
||||
production: true
|
||||
}
|
||||
}
|
||||
},
|
||||
requirejs: {
|
||||
compile: {
|
||||
options: {
|
||||
baseUrl: "lib",
|
||||
name: "../bower_components/almond/almond",
|
||||
name: "../node_modules/almond/almond",
|
||||
mainConfigFile: "app.js",
|
||||
include: "../app",
|
||||
wrap: true,
|
||||
|
@ -117,7 +100,6 @@ module.exports = function(grunt) {
|
|||
}
|
||||
})
|
||||
|
||||
grunt.loadNpmTasks("grunt-bower-install-simple")
|
||||
grunt.loadNpmTasks("grunt-contrib-copy")
|
||||
grunt.loadNpmTasks("grunt-contrib-requirejs")
|
||||
grunt.loadNpmTasks("grunt-sass")
|
||||
|
|
|
@ -4,11 +4,6 @@ module.exports = function (grunt) {
|
|||
options: {
|
||||
install: true
|
||||
},
|
||||
bower: {
|
||||
options: {
|
||||
packageManager: "bower"
|
||||
}
|
||||
},
|
||||
npm: {}
|
||||
},
|
||||
eslint: {
|
||||
|
|
Loading…
Reference in a new issue