[TASK] Implement new router
This commit is contained in:
parent
5acf135d8e
commit
ecd5aee769
@ -9,6 +9,7 @@ Meshviewer is an online visualization app to represent nodes and links on a map
|
|||||||
#### Main differences to https://github.com/ffnord/meshviewer
|
#### Main differences to https://github.com/ffnord/meshviewer
|
||||||
_Some similar features might have been implemented/merged_
|
_Some similar features might have been implemented/merged_
|
||||||
|
|
||||||
|
- Replaced router - including language, mode, node, link, location
|
||||||
- Leaflet upgraded to v1 - faster on mobile
|
- Leaflet upgraded to v1 - faster on mobile
|
||||||
- Forcegraph rewrite with d3.js v4
|
- Forcegraph rewrite with d3.js v4
|
||||||
- Map layer modes (Allow to set a default layer based on time combined with a stylesheet)
|
- Map layer modes (Allow to set a default layer based on time combined with a stylesheet)
|
||||||
|
4
app.js
4
app.js
@ -57,6 +57,7 @@ require.config({
|
|||||||
baseUrl: 'lib',
|
baseUrl: 'lib',
|
||||||
paths: {
|
paths: {
|
||||||
'polyglot': '../node_modules/node-polyglot/build/polyglot',
|
'polyglot': '../node_modules/node-polyglot/build/polyglot',
|
||||||
|
'Navigo': '../node_modules/navigo/lib/navigo',
|
||||||
'leaflet': '../node_modules/leaflet/dist/leaflet',
|
'leaflet': '../node_modules/leaflet/dist/leaflet',
|
||||||
'moment': '../node_modules/moment/moment',
|
'moment': '../node_modules/moment/moment',
|
||||||
// d3 modules indirect dependencies
|
// d3 modules indirect dependencies
|
||||||
@ -78,8 +79,7 @@ require.config({
|
|||||||
'd3-drag': '../node_modules/d3-drag/build/d3-drag',
|
'd3-drag': '../node_modules/d3-drag/build/d3-drag',
|
||||||
'virtual-dom': '../node_modules/virtual-dom/dist/virtual-dom',
|
'virtual-dom': '../node_modules/virtual-dom/dist/virtual-dom',
|
||||||
'rbush': '../node_modules/rbush/rbush',
|
'rbush': '../node_modules/rbush/rbush',
|
||||||
'helper': 'utils/helper',
|
'helper': 'utils/helper'
|
||||||
'language': 'utils/language'
|
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
'd3-drag': ['d3-selection'],
|
'd3-drag': ['d3-selection'],
|
||||||
|
@ -46,13 +46,12 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'utils/math', 'forcegr
|
|||||||
var n = force.find(e[0], e[1], NODE_RADIUS_SELECT);
|
var n = force.find(e[0], e[1], NODE_RADIUS_SELECT);
|
||||||
|
|
||||||
if (n !== undefined) {
|
if (n !== undefined) {
|
||||||
router.node(n.o.node)();
|
router.fullUrl({ node: n.o.node.nodeinfo.node_id });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = { x: e[0], y: e[1] };
|
e = { x: e[0], y: e[1] };
|
||||||
|
|
||||||
|
|
||||||
var closedLink;
|
var closedLink;
|
||||||
var radius = LINK_RADIUS_SELECT;
|
var radius = LINK_RADIUS_SELECT;
|
||||||
intLinks
|
intLinks
|
||||||
@ -65,7 +64,7 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'utils/math', 'forcegr
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (closedLink !== undefined) {
|
if (closedLink !== undefined) {
|
||||||
router.link(closedLink.o)();
|
router.fullUrl({ link: closedLink.o.id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +225,11 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'utils/math', 'forcegr
|
|||||||
redraw();
|
redraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
self.gotoLocation = function gotoLocation() {
|
||||||
|
// ignore
|
||||||
|
};
|
||||||
|
|
||||||
self.destroy = function destroy() {
|
self.destroy = function destroy() {
|
||||||
force.stop();
|
force.stop();
|
||||||
canvas.remove();
|
canvas.remove();
|
||||||
|
12
lib/gui.js
12
lib/gui.js
@ -66,11 +66,13 @@ define(['d3-interpolate', 'map', 'sidebar', 'tabs', 'container', 'legend',
|
|||||||
buttonToggle.classList.add('ion-eye', 'shadow');
|
buttonToggle.classList.add('ion-eye', 'shadow');
|
||||||
buttonToggle.setAttribute('data-tooltip', _.t('button.switchView'));
|
buttonToggle.setAttribute('data-tooltip', _.t('button.switchView'));
|
||||||
buttonToggle.onclick = function onclick() {
|
buttonToggle.onclick = function onclick() {
|
||||||
|
var data;
|
||||||
if (content.constructor === Map) {
|
if (content.constructor === Map) {
|
||||||
router.view('g');
|
data = { view: 'graph', lat: undefined, lng: undefined, zoom: undefined };
|
||||||
} else {
|
} else {
|
||||||
router.view('m');
|
data = { view: 'map' };
|
||||||
}
|
}
|
||||||
|
router.fullUrl(data, false, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
buttons.appendChild(buttonToggle);
|
buttons.appendChild(buttonToggle);
|
||||||
@ -119,10 +121,8 @@ define(['d3-interpolate', 'map', 'sidebar', 'tabs', 'container', 'legend',
|
|||||||
router.addTarget(title);
|
router.addTarget(title);
|
||||||
router.addTarget(infobox);
|
router.addTarget(infobox);
|
||||||
|
|
||||||
router.addView('m', mkView(Map));
|
router.addView('map', mkView(Map));
|
||||||
router.addView('g', mkView(ForceGraph));
|
router.addView('graph', mkView(ForceGraph));
|
||||||
|
|
||||||
router.view('m');
|
|
||||||
|
|
||||||
self.setData = fanoutUnfiltered.setData;
|
self.setData = fanoutUnfiltered.setData;
|
||||||
|
|
||||||
|
@ -18,8 +18,7 @@ define(['helper'], function (helper) {
|
|||||||
var a1;
|
var a1;
|
||||||
if (!unknown) {
|
if (!unknown) {
|
||||||
a1 = document.createElement('a');
|
a1 = document.createElement('a');
|
||||||
a1.href = router.getUrl({ n: d.source.node_id });
|
a1.href = router.generateLink({ node: d.source.node_id });
|
||||||
a1.onclick = router.node(d.source.node);
|
|
||||||
} else {
|
} else {
|
||||||
a1 = document.createElement('span');
|
a1 = document.createElement('span');
|
||||||
}
|
}
|
||||||
@ -31,8 +30,7 @@ define(['helper'], function (helper) {
|
|||||||
h2.appendChild(arrow);
|
h2.appendChild(arrow);
|
||||||
|
|
||||||
var a2 = document.createElement('a');
|
var a2 = document.createElement('a');
|
||||||
a2.href = router.getUrl({ n: d.target.node_id });
|
a2.href = router.generateLink({ node: d.target.node_id });
|
||||||
a2.onclick = router.node(d.target.node);
|
|
||||||
a2.textContent = d.target.node.nodeinfo.hostname;
|
a2.textContent = d.target.node.nodeinfo.hostname;
|
||||||
h2.appendChild(a2);
|
h2.appendChild(a2);
|
||||||
el.appendChild(h2);
|
el.appendChild(h2);
|
||||||
|
@ -28,35 +28,21 @@ define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, nod
|
|||||||
var closeButton = document.createElement('button');
|
var closeButton = document.createElement('button');
|
||||||
closeButton.classList.add('close');
|
closeButton.classList.add('close');
|
||||||
closeButton.classList.add('ion-close');
|
closeButton.classList.add('ion-close');
|
||||||
closeButton.onclick = router.reset;
|
closeButton.onclick = function () {
|
||||||
el.appendChild(closeButton);
|
router.fullUrl();
|
||||||
}
|
};
|
||||||
|
|
||||||
function clear() {
|
|
||||||
var closeButton = el.firstChild;
|
|
||||||
while (el.firstChild) {
|
|
||||||
el.removeChild(el.firstChild);
|
|
||||||
}
|
|
||||||
el.appendChild(closeButton);
|
el.appendChild(closeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.resetView = destroy;
|
self.resetView = destroy;
|
||||||
|
|
||||||
self.gotoNode = function gotoNode(d, update) {
|
self.gotoNode = function gotoNode(d) {
|
||||||
if (update !== true) {
|
create();
|
||||||
create();
|
|
||||||
} else {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
node(config, el, router, d);
|
node(config, el, router, d);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.gotoLink = function gotoLink(d, update) {
|
self.gotoLink = function gotoLink(d) {
|
||||||
if (update !== true) {
|
create();
|
||||||
create();
|
|
||||||
} else {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
link(config, el, router, d);
|
link(config, el, router, d);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,7 +191,12 @@ define(['sorttable', 'virtual-dom', 'd3-interpolate', 'moment', 'helper'],
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!unknown) {
|
if (!unknown) {
|
||||||
name.push(V.h('a', { href: router.getUrl({ n: n.node.nodeinfo.node_id }), onclick: router.node(n.node), className: 'online' }, n.node.nodeinfo.hostname));
|
name.push(V.h('a', {
|
||||||
|
href: router.generateLink({ node: n.node.nodeinfo.node_id }),
|
||||||
|
onclick: function (e) {
|
||||||
|
router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
|
||||||
|
}, className: 'online'
|
||||||
|
}, n.node.nodeinfo.hostname));
|
||||||
} else {
|
} else {
|
||||||
name.push(n.link.id);
|
name.push(n.link.id);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,12 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
|
|||||||
table.el.classList.add('link-list');
|
table.el.classList.add('link-list');
|
||||||
|
|
||||||
function renderRow(d) {
|
function renderRow(d) {
|
||||||
var td1Content = [V.h('a', { href: router.getUrl({ l: d.id }), onclick: router.link(d) }, linkName(d))];
|
var td1Content = [V.h('a', {
|
||||||
|
href: router.generateLink({ link: d.id }),
|
||||||
|
onclick: function (e) {
|
||||||
|
router.fullUrl({ link: d.id }, e);
|
||||||
|
}
|
||||||
|
}, linkName(d))];
|
||||||
|
|
||||||
var td1 = V.h('td', td1Content);
|
var td1 = V.h('td', td1Content);
|
||||||
var td2 = V.h('td', { style: { color: linkScale(1 / d.tq) } }, helper.showTq(d));
|
var td2 = V.h('td', { style: { color: linkScale(1 / d.tq) } }, helper.showTq(d));
|
||||||
|
12
lib/main.js
12
lib/main.js
@ -1,5 +1,5 @@
|
|||||||
define(['polyglot', 'moment', 'router', 'leaflet', 'gui', 'helper', 'language'],
|
define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||||
function (Polyglot, moment, Router, L, GUI, helper, Language) {
|
function (moment, Router, L, GUI, helper, Language) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
return function (config) {
|
return function (config) {
|
||||||
@ -117,7 +117,6 @@ define(['polyglot', 'moment', 'router', 'leaflet', 'gui', 'helper', 'language'],
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
links.sort(function (a, b) {
|
links.sort(function (a, b) {
|
||||||
return b.tq - a.tq;
|
return b.tq - a.tq;
|
||||||
});
|
});
|
||||||
@ -138,8 +137,7 @@ define(['polyglot', 'moment', 'router', 'leaflet', 'gui', 'helper', 'language'],
|
|||||||
}
|
}
|
||||||
|
|
||||||
var language = new Language(config);
|
var language = new Language(config);
|
||||||
|
var router = new Router(language);
|
||||||
var router = new Router();
|
|
||||||
|
|
||||||
var urls = [];
|
var urls = [];
|
||||||
|
|
||||||
@ -153,6 +151,7 @@ define(['polyglot', 'moment', 'router', 'leaflet', 'gui', 'helper', 'language'],
|
|||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
language.init(router);
|
||||||
return Promise.all(urls.map(helper.getJSON))
|
return Promise.all(urls.map(helper.getJSON))
|
||||||
.then(handleData);
|
.then(handleData);
|
||||||
}
|
}
|
||||||
@ -162,13 +161,12 @@ define(['polyglot', 'moment', 'router', 'leaflet', 'gui', 'helper', 'language'],
|
|||||||
var gui = new GUI(config, router, language);
|
var gui = new GUI(config, router, language);
|
||||||
gui.setData(d);
|
gui.setData(d);
|
||||||
router.setData(d);
|
router.setData(d);
|
||||||
router.start();
|
router.resolve();
|
||||||
|
|
||||||
window.setInterval(function () {
|
window.setInterval(function () {
|
||||||
update().then(function (n) {
|
update().then(function (n) {
|
||||||
gui.setData(n);
|
gui.setData(n);
|
||||||
router.setData(n);
|
router.setData(n);
|
||||||
router.update();
|
|
||||||
});
|
});
|
||||||
}, 60000);
|
}, 60000);
|
||||||
})
|
})
|
||||||
|
27
lib/map.js
27
lib/map.js
@ -76,7 +76,9 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm
|
|||||||
m.setStyle(iconFunc(d));
|
m.setStyle(iconFunc(d));
|
||||||
};
|
};
|
||||||
|
|
||||||
m.on('click', router.node(d));
|
m.on('click', function () {
|
||||||
|
router.fullUrl({ node: d.nodeinfo.node_id });
|
||||||
|
});
|
||||||
m.bindTooltip(d.nodeinfo.hostname);
|
m.bindTooltip(d.nodeinfo.hostname);
|
||||||
|
|
||||||
dict[d.nodeinfo.node_id] = m;
|
dict[d.nodeinfo.node_id] = m;
|
||||||
@ -105,7 +107,9 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm
|
|||||||
};
|
};
|
||||||
|
|
||||||
line.bindTooltip(d.source.node.nodeinfo.hostname + ' – ' + d.target.node.nodeinfo.hostname + '<br><strong>' + helper.showDistance(d) + ' / ' + helper.showTq(d) + '</strong>');
|
line.bindTooltip(d.source.node.nodeinfo.hostname + ' – ' + d.target.node.nodeinfo.hostname + '<br><strong>' + helper.showDistance(d) + ' / ' + helper.showTq(d) + '</strong>');
|
||||||
line.on('click', router.link(d));
|
line.on('click', function () {
|
||||||
|
router.fullUrl({ link: d.id });
|
||||||
|
});
|
||||||
|
|
||||||
dict[d.id] = line;
|
dict[d.id] = line;
|
||||||
|
|
||||||
@ -230,7 +234,7 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showCoordinates(e) {
|
function showCoordinates(e) {
|
||||||
router.gotoLocation(e.latlng);
|
router.fullUrl({ zoom: map.getZoom(), lat: e.latlng.lat, lng: e.latlng.lng });
|
||||||
disableCoords();
|
disableCoords();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,8 +349,8 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setView(bounds) {
|
function setView(bounds, zoom) {
|
||||||
map.fitBounds(bounds, { paddingTopLeft: [sidebar(), 0], maxZoom: config.nodeZoom });
|
map.fitBounds(bounds, { paddingTopLeft: [sidebar(), 0], maxZoom: (zoom ? zoom : config.nodeZoom) });
|
||||||
}
|
}
|
||||||
|
|
||||||
function goto(m) {
|
function goto(m) {
|
||||||
@ -479,20 +483,21 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm
|
|||||||
updateView();
|
updateView();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.gotoNode = function gotoNode(d, update) {
|
self.gotoNode = function gotoNode(d) {
|
||||||
disableTracking();
|
disableTracking();
|
||||||
highlight = { type: 'node', o: d };
|
highlight = { type: 'node', o: d };
|
||||||
updateView(update);
|
updateView();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.gotoLink = function gotoLink(d, update) {
|
self.gotoLink = function gotoLink(d) {
|
||||||
disableTracking();
|
disableTracking();
|
||||||
highlight = { type: 'link', o: d };
|
highlight = { type: 'link', o: d };
|
||||||
updateView(update);
|
updateView();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.gotoLocation = function gotoLocation() {
|
self.gotoLocation = function gotoLocation(d) {
|
||||||
// ignore
|
disableTracking();
|
||||||
|
map.setView([d.lat, d.lng], d.zoom);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.destroy = function destroy() {
|
self.destroy = function destroy() {
|
||||||
|
@ -65,8 +65,10 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
|
|||||||
|
|
||||||
td1Content.push(V.h('a', {
|
td1Content.push(V.h('a', {
|
||||||
className: aClass.join(' '),
|
className: aClass.join(' '),
|
||||||
onclick: router.node(d),
|
href: router.generateLink({ node: d.nodeinfo.node_id }),
|
||||||
href: router.getUrl({ n: d.nodeinfo.node_id })
|
onclick: function (e) {
|
||||||
|
router.fullUrl({ node: d.nodeinfo.node_id }, e);
|
||||||
|
}
|
||||||
}, d.nodeinfo.hostname));
|
}, d.nodeinfo.hostname));
|
||||||
if (helper.hasLocation(d)) {
|
if (helper.hasLocation(d)) {
|
||||||
td0Content.push(V.h('span', { className: 'icon ion-location' }));
|
td0Content.push(V.h('span', { className: 'icon ion-location' }));
|
||||||
|
242
lib/router.js
242
lib/router.js
@ -1,242 +0,0 @@
|
|||||||
define(['helper'], function (helper) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
var self = this;
|
|
||||||
var objects = { nodes: {}, links: {} };
|
|
||||||
var targets = [];
|
|
||||||
var views = {};
|
|
||||||
var currentView;
|
|
||||||
var currentObject;
|
|
||||||
var running = false;
|
|
||||||
|
|
||||||
function saveState() {
|
|
||||||
var e = '#!';
|
|
||||||
|
|
||||||
e += 'v:' + currentView;
|
|
||||||
|
|
||||||
if (currentObject) {
|
|
||||||
if ('node' in currentObject) {
|
|
||||||
e += ';n:' + encodeURIComponent(currentObject.node.nodeinfo.node_id);
|
|
||||||
} else if ('link' in currentObject) {
|
|
||||||
e += ';l:' + encodeURIComponent(currentObject.link.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.history.pushState(e, undefined, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetView(push) {
|
|
||||||
push = helper.trueDefault(push);
|
|
||||||
|
|
||||||
targets.forEach(function (t) {
|
|
||||||
t.resetView();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (push) {
|
|
||||||
currentObject = undefined;
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotoNode(d, update) {
|
|
||||||
if (!d) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.forEach(function (t) {
|
|
||||||
t.gotoNode(d, update);
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotoLink(d, update) {
|
|
||||||
if (!d) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.forEach(function (t) {
|
|
||||||
t.gotoLink(d, update);
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadState(s, update) {
|
|
||||||
if (!s) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = decodeURIComponent(s);
|
|
||||||
|
|
||||||
if (!s.startsWith('#!')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var targetSet = false;
|
|
||||||
|
|
||||||
s.slice(2).split(';').forEach(function (d) {
|
|
||||||
var args = d.split(':');
|
|
||||||
|
|
||||||
if (update !== true && args[0] === 'v' && args[1] in views) {
|
|
||||||
currentView = args[1];
|
|
||||||
views[args[1]]();
|
|
||||||
}
|
|
||||||
|
|
||||||
var id;
|
|
||||||
|
|
||||||
if (args[0] === 'n') {
|
|
||||||
id = args[1];
|
|
||||||
if (id in objects.nodes) {
|
|
||||||
currentObject = { node: objects.nodes[id] };
|
|
||||||
gotoNode(objects.nodes[id], update);
|
|
||||||
targetSet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args[0] === 'l') {
|
|
||||||
id = args[1];
|
|
||||||
if (id in objects.links) {
|
|
||||||
currentObject = { link: objects.links[id] };
|
|
||||||
gotoLink(objects.links[id], update);
|
|
||||||
targetSet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return targetSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.getUrl = function getUrl(data) {
|
|
||||||
var e = '#!';
|
|
||||||
|
|
||||||
if (data.n) {
|
|
||||||
e += 'n:' + encodeURIComponent(data.n);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.l) {
|
|
||||||
e += 'l:' + encodeURIComponent(data.l);
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.start = function start() {
|
|
||||||
running = true;
|
|
||||||
|
|
||||||
if (!loadState(window.location.hash)) {
|
|
||||||
resetView(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onpopstate = function onpopstate(d) {
|
|
||||||
if (!loadState(d.state)) {
|
|
||||||
resetView(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
self.view = function view(d) {
|
|
||||||
if (d in views) {
|
|
||||||
views[d]();
|
|
||||||
|
|
||||||
if (!currentView || running) {
|
|
||||||
currentView = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!running) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveState();
|
|
||||||
|
|
||||||
if (!currentObject) {
|
|
||||||
resetView(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('node' in currentObject) {
|
|
||||||
gotoNode(currentObject.node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('link' in currentObject) {
|
|
||||||
gotoLink(currentObject.link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.node = function node(d) {
|
|
||||||
return function () {
|
|
||||||
if (gotoNode(d)) {
|
|
||||||
currentObject = { node: d };
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
self.link = function link(d) {
|
|
||||||
return function () {
|
|
||||||
if (gotoLink(d)) {
|
|
||||||
currentObject = { link: d };
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
self.gotoLocation = function gotoLocation(d) {
|
|
||||||
if (!d) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.forEach(function (t) {
|
|
||||||
if (!t.gotoLocation) {
|
|
||||||
console.warn('has no gotoLocation', t);
|
|
||||||
}
|
|
||||||
t.gotoLocation(d);
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.reset = function reset() {
|
|
||||||
resetView();
|
|
||||||
};
|
|
||||||
|
|
||||||
self.addTarget = function addTarget(d) {
|
|
||||||
targets.push(d);
|
|
||||||
};
|
|
||||||
|
|
||||||
self.removeTarget = function removeTarget(d) {
|
|
||||||
targets = targets.filter(function (e) {
|
|
||||||
return d !== e;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
self.addView = function addView(k, d) {
|
|
||||||
views[k] = d;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.setData = function setData(data) {
|
|
||||||
objects.nodes = {};
|
|
||||||
objects.links = {};
|
|
||||||
|
|
||||||
data.nodes.all.forEach(function (d) {
|
|
||||||
objects.nodes[d.nodeinfo.node_id] = d;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.graph.links.forEach(function (d) {
|
|
||||||
objects.links[d.id] = d;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
self.update = function update() {
|
|
||||||
loadState(window.location.hash, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return self;
|
|
||||||
};
|
|
||||||
});
|
|
@ -41,8 +41,10 @@ define(['moment', 'virtual-dom', 'helper'], function (moment, V, helper) {
|
|||||||
|
|
||||||
td1Content.push(V.h('a', {
|
td1Content.push(V.h('a', {
|
||||||
className: aClass.join(' '),
|
className: aClass.join(' '),
|
||||||
onclick: router.node(d),
|
href: router.generateLink({ node: d.nodeinfo.node_id }),
|
||||||
href: router.getUrl({ n: d.nodeinfo.node_id })
|
onclick: function (e) {
|
||||||
|
router.fullUrl({ node: d.nodeinfo.node_id }, e);
|
||||||
|
}
|
||||||
}, d.nodeinfo.hostname));
|
}, d.nodeinfo.hostname));
|
||||||
|
|
||||||
if (helper.hasLocation(d)) {
|
if (helper.hasLocation(d)) {
|
||||||
|
@ -17,15 +17,11 @@ define(function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.gotoNode = function gotoNode(d) {
|
this.gotoNode = function gotoNode(d) {
|
||||||
if (d) {
|
setTitle(d.nodeinfo.hostname);
|
||||||
setTitle(d.nodeinfo.hostname);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.gotoLink = function gotoLink(d) {
|
this.gotoLink = function gotoLink(d) {
|
||||||
if (d) {
|
setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + ' – ' + d.target.node.nodeinfo.hostname);
|
||||||
setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + ' – ' + d.target.node.nodeinfo.hostname);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.gotoLocation = function gotoLocation() {
|
this.gotoLocation = function gotoLocation() {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
define(['polyglot', 'moment', 'helper'], function (Polyglot, moment, helper) {
|
define(['polyglot', 'moment', 'helper'], function (Polyglot, moment, helper) {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function (config) {
|
return function (config) {
|
||||||
|
var router;
|
||||||
|
|
||||||
function languageSelect(el) {
|
function languageSelect(el) {
|
||||||
var select = document.createElement('select');
|
var select = document.createElement('select');
|
||||||
select.className = 'language-switch';
|
select.className = 'language-switch';
|
||||||
select.addEventListener('change', setLocale);
|
select.addEventListener('change', setSelectLocale);
|
||||||
el.appendChild(select);
|
el.appendChild(select);
|
||||||
|
|
||||||
// Keep english
|
// Keep english
|
||||||
@ -14,8 +16,12 @@ define(['polyglot', 'moment', 'helper'], function (Polyglot, moment, helper) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLocale(event) {
|
function setSelectLocale(event) {
|
||||||
localStorage.setItem('language', getLocale(event.target.value));
|
router.fullUrl({ lang: event.target.value }, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLocale(lang) {
|
||||||
|
localStorage.setItem('language', getLocale(lang));
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +57,16 @@ define(['polyglot', 'moment', 'helper'], function (Polyglot, moment, helper) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window._ = new Polyglot({ locale: getLocale(), allowMissing: true });
|
function init(r) {
|
||||||
helper.getJSON('locale/' + _.locale() + '.json?' + config.cacheBreaker).then(setTranslation);
|
router = r;
|
||||||
|
window._ = new Polyglot({ locale: getLocale(router.getLang()), allowMissing: true });
|
||||||
|
helper.getJSON('locale/' + _.locale() + '.json?' + config.cacheBreaker).then(setTranslation);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
init: init,
|
||||||
|
getLocale: getLocale,
|
||||||
|
setLocale: setLocale,
|
||||||
languageSelect: languageSelect
|
languageSelect: languageSelect
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
156
lib/utils/router.js
Normal file
156
lib/utils/router.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
define(['Navigo'], function (Navigo) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return function (language) {
|
||||||
|
var init = false;
|
||||||
|
var objects = { nodes: {}, links: {} };
|
||||||
|
var targets = [];
|
||||||
|
var views = {};
|
||||||
|
var current = {};
|
||||||
|
var state = { lang: language.getLocale(), view: 'map' };
|
||||||
|
|
||||||
|
function resetView() {
|
||||||
|
targets.forEach(function (t) {
|
||||||
|
t.resetView();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoNode(d) {
|
||||||
|
if (d.nodeId in objects.nodes) {
|
||||||
|
targets.forEach(function (t) {
|
||||||
|
t.gotoNode(objects.nodes[d.nodeId]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoLink(d) {
|
||||||
|
if (d.linkId in objects.links) {
|
||||||
|
targets.forEach(function (t) {
|
||||||
|
t.gotoLink(objects.links[d.linkId]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function view(d) {
|
||||||
|
if (d.view in views) {
|
||||||
|
views[d.view]();
|
||||||
|
state.view = d.view;
|
||||||
|
resetView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function customRoute(lang, viewValue, node, link, zoom, lat, lng) {
|
||||||
|
current = {
|
||||||
|
lang: lang,
|
||||||
|
view: viewValue,
|
||||||
|
node: node,
|
||||||
|
link: link,
|
||||||
|
zoom: zoom,
|
||||||
|
lat: lat,
|
||||||
|
lng: lng
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lang && lang !== state.lang && lang === language.getLocale(lang)) {
|
||||||
|
language.setLocale(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init || viewValue && viewValue !== state.view) {
|
||||||
|
if (!viewValue) {
|
||||||
|
viewValue = state.view;
|
||||||
|
}
|
||||||
|
view({ view: viewValue });
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
gotoNode({ nodeId: node });
|
||||||
|
} else if (link) {
|
||||||
|
gotoLink({ linkId: link });
|
||||||
|
} else if (lat) {
|
||||||
|
targets.forEach(function (t) {
|
||||||
|
t.gotoLocation({
|
||||||
|
zoom: parseInt(zoom, 10),
|
||||||
|
lat: parseFloat(lat),
|
||||||
|
lng: parseFloat(lng)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resetView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var router = new Navigo(null, true);
|
||||||
|
|
||||||
|
router
|
||||||
|
.on(/^\/?#?\/([\w]{2})?\/?(map|graph)?\/?([a-f\d]{12})?([a-f\d\-]{25})?\/?(?:(\d+)\/([\d.]+)\/([\d.]+))?$/, customRoute)
|
||||||
|
.on({
|
||||||
|
'*': function () {
|
||||||
|
router.fullUrl();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.generateLink = function generateLink(data, full, deep) {
|
||||||
|
var result = '#';
|
||||||
|
|
||||||
|
if (full) {
|
||||||
|
data = Object.assign({}, state, data);
|
||||||
|
} else if (deep) {
|
||||||
|
data = Object.assign({}, current, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in data) {
|
||||||
|
if (!data.hasOwnProperty(key) || data[key] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result += '/' + data[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
router.fullUrl = function fullUrl(data, e, deep) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
router.navigate(router.generateLink(data, !deep, deep));
|
||||||
|
};
|
||||||
|
|
||||||
|
router.getLang = function getLang() {
|
||||||
|
var lang = location.hash.match(/^\/?#\/([\w]{2})\//);
|
||||||
|
if (lang) {
|
||||||
|
state.lang = language.getLocale(lang[1]);
|
||||||
|
return lang[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
router.addTarget = function addTarget(d) {
|
||||||
|
targets.push(d);
|
||||||
|
};
|
||||||
|
|
||||||
|
router.removeTarget = function removeTarget(d) {
|
||||||
|
targets = targets.filter(function (e) {
|
||||||
|
return d !== e;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
router.addView = function addView(k, d) {
|
||||||
|
views[k] = d;
|
||||||
|
};
|
||||||
|
|
||||||
|
router.setData = function setData(data) {
|
||||||
|
objects.nodes = {};
|
||||||
|
objects.links = {};
|
||||||
|
|
||||||
|
data.nodes.all.forEach(function (d) {
|
||||||
|
objects.nodes[d.nodeinfo.node_id] = d;
|
||||||
|
});
|
||||||
|
|
||||||
|
data.graph.links.forEach(function (d) {
|
||||||
|
objects.links[d.id] = d;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
|
});
|
@ -48,6 +48,7 @@
|
|||||||
"d3-zoom": "^1.1.3",
|
"d3-zoom": "^1.1.3",
|
||||||
"leaflet": "^1.0.3",
|
"leaflet": "^1.0.3",
|
||||||
"moment": "^2.17.1",
|
"moment": "^2.17.1",
|
||||||
|
"navigo": "^4.6.0",
|
||||||
"node-polyglot": "^2.2.2",
|
"node-polyglot": "^2.2.2",
|
||||||
"promise-polyfill": "^6.0.2",
|
"promise-polyfill": "^6.0.2",
|
||||||
"rbush": "^2.0.1",
|
"rbush": "^2.0.1",
|
||||||
|
@ -3259,6 +3259,10 @@ natural-compare@^1.4.0:
|
|||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||||
|
|
||||||
|
navigo@^4.6.0:
|
||||||
|
version "4.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/navigo/-/navigo-4.6.0.tgz#212cf08e1658874243a4acaea041aee42c30480a"
|
||||||
|
|
||||||
ncname@1.0.x:
|
ncname@1.0.x:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c"
|
resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c"
|
||||||
|
Loading…
Reference in New Issue
Block a user