basic filter support
This commit is contained in:
parent
aeae866998
commit
09bdb7d61a
76
lib/datadistributor.js
Normal file
76
lib/datadistributor.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
define([], function () {
|
||||||
|
return function () {
|
||||||
|
var targets = []
|
||||||
|
var filterObservers = []
|
||||||
|
var filters = []
|
||||||
|
var filteredData
|
||||||
|
var data
|
||||||
|
|
||||||
|
function remove(d) {
|
||||||
|
targets = targets.filter( function (e) { return d !== e } )
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(d) {
|
||||||
|
targets.push(d)
|
||||||
|
|
||||||
|
if (filteredData !== undefined)
|
||||||
|
d.setData(filteredData)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setData(d) {
|
||||||
|
data = d
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
if (data === undefined)
|
||||||
|
return
|
||||||
|
|
||||||
|
filteredData = filters.reduce( function (a, f) {
|
||||||
|
return f.run(a)
|
||||||
|
}, data)
|
||||||
|
|
||||||
|
targets.forEach( function (t) {
|
||||||
|
t.setData(filteredData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function notifyObservers() {
|
||||||
|
filterObservers.forEach( function (d) {
|
||||||
|
d.filtersChanged(filters)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFilter(d) {
|
||||||
|
filters.push(d)
|
||||||
|
notifyObservers()
|
||||||
|
d.setRefresh(refresh)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFilter(d) {
|
||||||
|
filters = filters.filter( function (e) { return d !== e } )
|
||||||
|
notifyObservers()
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchFilters(d) {
|
||||||
|
filterObservers.push(d)
|
||||||
|
|
||||||
|
d.filtersChanged(filters)
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
filterObservers = filterObservers.filter( function (e) { return d !== e })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { add: add,
|
||||||
|
remove: remove,
|
||||||
|
setData: setData,
|
||||||
|
addFilter: addFilter,
|
||||||
|
removeFilter: removeFilter,
|
||||||
|
watchFilters: watchFilters,
|
||||||
|
refresh: refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
34
lib/filters/filtergui.js
Normal file
34
lib/filters/filtergui.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
define([], function () {
|
||||||
|
return function (distributor) {
|
||||||
|
var container = document.createElement("ul")
|
||||||
|
container.classList.add("filters")
|
||||||
|
|
||||||
|
function render(el) {
|
||||||
|
el.appendChild(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
function filtersChanged(filters) {
|
||||||
|
while (container.firstChild)
|
||||||
|
container.removeChild(container.firstChild)
|
||||||
|
|
||||||
|
filters.forEach( function (d) {
|
||||||
|
var li = document.createElement("li")
|
||||||
|
var div = document.createElement("div")
|
||||||
|
container.appendChild(li)
|
||||||
|
li.appendChild(div)
|
||||||
|
d.render(div)
|
||||||
|
|
||||||
|
var button = document.createElement("button")
|
||||||
|
button.textContent = ""
|
||||||
|
button.onclick = function () {
|
||||||
|
distributor.removeFilter(d)
|
||||||
|
}
|
||||||
|
li.appendChild(button)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { render: render,
|
||||||
|
filtersChanged: filtersChanged
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
32
lib/filters/genericnode.js
Normal file
32
lib/filters/genericnode.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
define(["filters/nodefilter"], function (nodefilter) {
|
||||||
|
return function (name, key, value, f) {
|
||||||
|
function run(d) {
|
||||||
|
var o = dictGet(d, key.slice(0))
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
o = f(o)
|
||||||
|
|
||||||
|
return o === value
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRefresh() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function render(el) {
|
||||||
|
var label = document.createElement("label")
|
||||||
|
label.textContent = name + " "
|
||||||
|
|
||||||
|
var strong = document.createElement("strong")
|
||||||
|
strong.textContent = value
|
||||||
|
|
||||||
|
label.appendChild(strong)
|
||||||
|
|
||||||
|
el.appendChild(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { run: nodefilter(run),
|
||||||
|
setRefresh: setRefresh,
|
||||||
|
render: render
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
33
lib/filters/nodefilter.js
Normal file
33
lib/filters/nodefilter.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
define([], function () {
|
||||||
|
return function (filter) {
|
||||||
|
return function (data) {
|
||||||
|
var n = Object.create(data)
|
||||||
|
n.nodes = {}
|
||||||
|
|
||||||
|
for (var key in data.nodes) {
|
||||||
|
n.nodes[key] = data.nodes[key].filter(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
var filteredIds = new Set()
|
||||||
|
|
||||||
|
n.graph = {}
|
||||||
|
n.graph.nodes = data.graph.nodes.filter( function (d) {
|
||||||
|
if (!d.node)
|
||||||
|
return true
|
||||||
|
|
||||||
|
var r = filter(d.node)
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
filteredIds.add(d.id)
|
||||||
|
|
||||||
|
return r
|
||||||
|
})
|
||||||
|
|
||||||
|
n.graph.links = data.graph.links.filter( function (d) {
|
||||||
|
return filteredIds.has(d.source.id) && filteredIds.has(d.target.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
46
lib/gui.js
46
lib/gui.js
|
@ -1,13 +1,13 @@
|
||||||
define([ "chroma-js", "map", "sidebar", "tabs", "container", "meshstats",
|
define([ "chroma-js", "map", "sidebar", "tabs", "container", "meshstats",
|
||||||
"legend", "linklist", "nodelist", "simplenodelist", "infobox/main",
|
"legend", "linklist", "nodelist", "simplenodelist", "infobox/main",
|
||||||
"proportions", "forcegraph", "title", "about" ],
|
"proportions", "forcegraph", "title", "about", "datadistributor",
|
||||||
|
"filters/filtergui" ],
|
||||||
function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
Nodelist, SimpleNodelist, Infobox, Proportions, ForceGraph,
|
Nodelist, SimpleNodelist, Infobox, Proportions, ForceGraph,
|
||||||
Title, About) {
|
Title, About, DataDistributor, FilterGUI) {
|
||||||
return function (config, router) {
|
return function (config, router) {
|
||||||
var self = this
|
var self = this
|
||||||
var dataTargets = []
|
var fanout = new DataDistributor()
|
||||||
var latestData
|
|
||||||
var content
|
var content
|
||||||
var contentDiv
|
var contentDiv
|
||||||
|
|
||||||
|
@ -17,16 +17,13 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
var buttons = document.createElement("div")
|
var buttons = document.createElement("div")
|
||||||
buttons.classList.add("buttons")
|
buttons.classList.add("buttons")
|
||||||
|
|
||||||
function dataTargetRemove(d) {
|
|
||||||
dataTargets = dataTargets.filter( function (e) { return d !== e })
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeContent() {
|
function removeContent() {
|
||||||
if (!content)
|
if (!content)
|
||||||
return
|
return
|
||||||
|
|
||||||
router.removeTarget(content)
|
router.removeTarget(content)
|
||||||
dataTargetRemove(content)
|
fanout.remove(content)
|
||||||
|
|
||||||
content.destroy()
|
content.destroy()
|
||||||
|
|
||||||
content = null
|
content = null
|
||||||
|
@ -38,10 +35,7 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
content = new K(config, linkScale, sidebar.getWidth, router, buttons)
|
content = new K(config, linkScale, sidebar.getWidth, router, buttons)
|
||||||
content.render(contentDiv)
|
content.render(contentDiv)
|
||||||
|
|
||||||
if (latestData)
|
fanout.add(content)
|
||||||
content.setData(latestData)
|
|
||||||
|
|
||||||
dataTargets.push(content)
|
|
||||||
router.addTarget(content)
|
router.addTarget(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,15 +76,15 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten")
|
var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten")
|
||||||
var nodelist = new Nodelist(router)
|
var nodelist = new Nodelist(router)
|
||||||
var linklist = new Linklist(linkScale, router)
|
var linklist = new Linklist(linkScale, router)
|
||||||
var statistics = new Proportions(config)
|
var statistics = new Proportions(config, fanout)
|
||||||
var about = new About()
|
var about = new About()
|
||||||
|
|
||||||
dataTargets.push(meshstats)
|
fanout.add(meshstats)
|
||||||
dataTargets.push(newnodeslist)
|
fanout.add(newnodeslist)
|
||||||
dataTargets.push(lostnodeslist)
|
fanout.add(lostnodeslist)
|
||||||
dataTargets.push(nodelist)
|
fanout.add(nodelist)
|
||||||
dataTargets.push(linklist)
|
fanout.add(linklist)
|
||||||
dataTargets.push(statistics)
|
fanout.add(statistics)
|
||||||
|
|
||||||
sidebar.add(header)
|
sidebar.add(header)
|
||||||
header.add(meshstats)
|
header.add(meshstats)
|
||||||
|
@ -99,6 +93,10 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
overview.add(newnodeslist)
|
overview.add(newnodeslist)
|
||||||
overview.add(lostnodeslist)
|
overview.add(lostnodeslist)
|
||||||
|
|
||||||
|
var filterGUI = new FilterGUI(fanout)
|
||||||
|
fanout.watchFilters(filterGUI)
|
||||||
|
header.add(filterGUI)
|
||||||
|
|
||||||
sidebar.add(tabs)
|
sidebar.add(tabs)
|
||||||
tabs.add("Aktuelles", overview)
|
tabs.add("Aktuelles", overview)
|
||||||
tabs.add("Knoten", nodelist)
|
tabs.add("Knoten", nodelist)
|
||||||
|
@ -114,13 +112,7 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
|
||||||
|
|
||||||
router.view("m")
|
router.view("m")
|
||||||
|
|
||||||
self.setData = function (data) {
|
self.setData = fanout.setData
|
||||||
latestData = data
|
|
||||||
|
|
||||||
dataTargets.forEach(function (d) {
|
|
||||||
d.setData(data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
define(["chroma-js", "virtual-dom", "numeral-intl", "vercomp" ],
|
define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "vercomp" ],
|
||||||
function (Chroma, V, numeral, vercomp) {
|
function (Chroma, V, numeral, Filter, vercomp) {
|
||||||
|
|
||||||
return function (config) {
|
return function (config, filterManager) {
|
||||||
var self = this
|
var self = this
|
||||||
var scale = Chroma.scale("YlGnBu").mode("lab")
|
var scale = Chroma.scale("YlGnBu").mode("lab")
|
||||||
|
|
||||||
|
@ -68,10 +68,18 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "vercomp" ],
|
||||||
dict[v] = 1 + (v in dict ? dict[v] : 0)
|
dict[v] = 1 + (v in dict ? dict[v] : 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
return Object.keys(dict).map(function (d) { return [d, dict[d]] })
|
return Object.keys(dict).map(function (d) { return [d, dict[d], key, f] })
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillTable(table, data) {
|
function addFilter(filter) {
|
||||||
|
return function () {
|
||||||
|
filterManager.addFilter(filter)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillTable(name, table, data) {
|
||||||
if (!table.last)
|
if (!table.last)
|
||||||
table.last = V.h("table")
|
table.last = V.h("table")
|
||||||
|
|
||||||
|
@ -86,7 +94,11 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "vercomp" ],
|
||||||
var c1 = Chroma.contrast(scale(v), "white")
|
var c1 = Chroma.contrast(scale(v), "white")
|
||||||
var c2 = Chroma.contrast(scale(v), "black")
|
var c2 = Chroma.contrast(scale(v), "black")
|
||||||
|
|
||||||
var th = V.h("th", d[0])
|
var filter = new Filter(name, d[2], d[0], d[3])
|
||||||
|
|
||||||
|
var a = V.h("a", { href: "#", onclick: addFilter(filter) }, d[0])
|
||||||
|
|
||||||
|
var th = V.h("th", a)
|
||||||
var td = V.h("td", V.h("span", {style: {
|
var td = V.h("td", V.h("span", {style: {
|
||||||
width: Math.round(v * 100) + "%",
|
width: Math.round(v * 100) + "%",
|
||||||
backgroundColor: scale(v).hex(),
|
backgroundColor: scale(v).hex(),
|
||||||
|
@ -127,11 +139,11 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "vercomp" ],
|
||||||
return "(deaktiviert)"
|
return "(deaktiviert)"
|
||||||
})
|
})
|
||||||
|
|
||||||
fillTable(statusTable, statusDict.sort(function (a, b) { return b[1] - a[1] }))
|
fillTable("Status", statusTable, statusDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||||
fillTable(fwTable, fwDict.sort(function (a, b) { return vercomp(b[0], a[0]) }))
|
fillTable("Firmware", fwTable, fwDict.sort(function (a, b) { return vercomp(b[0], a[0]) }))
|
||||||
fillTable(hwTable, hwDict.sort(function (a, b) { return b[1] - a[1] }))
|
fillTable("Hardware", hwTable, hwDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||||
fillTable(geoTable, geoDict.sort(function (a, b) { return b[1] - a[1] }))
|
fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||||
fillTable(autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
|
fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render = function (el) {
|
self.render = function (el) {
|
||||||
|
|
28
scss/_filters.scss
Normal file
28
scss/_filters.scss
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.filters {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 !important;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
padding: 6pt 0 6pt 12pt;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include shadow(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
box-shadow: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
font-size: 1.41em;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
@import '_base';
|
@import '_base';
|
||||||
@import '_leaflet';
|
@import '_leaflet';
|
||||||
@import '_leaflet.label';
|
@import '_leaflet.label';
|
||||||
|
@import '_filters';
|
||||||
|
|
||||||
$minscreenwidth: 630pt;
|
$minscreenwidth: 630pt;
|
||||||
$sidebarwidth: 420pt;
|
$sidebarwidth: 420pt;
|
||||||
|
|
Loading…
Reference in a new issue