diff --git a/README.md b/README.md index 78f27e6..62a3447 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Preview ------- ![Screenshot](https://cloud.githubusercontent.com/assets/4989256/20325678/5efeecde-ab8e-11e6-8d8d-f4955a1afa4d.png) +![Screenshot](https://cloud.githubusercontent.com/assets/4989256/20610106/becaeac6-b29d-11e6-987b-670998ac048e.png) Usage ----- @@ -39,3 +40,13 @@ gulp ``` Then, open `build/static/index.html` file. + +To install test REST client, run the following: + +```bash +import +``` + +This will put `src/cls/EntityBrowser/Router.cls` class into your Caché (change the `import.*` +script), and after you set up a web application, go to configure app settings by clicking setting +button in the top right corner. \ No newline at end of file diff --git a/package.json b/package.json index a7ac777..eee4e74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iknow-entity-browser", - "version": "0.0.8", + "version": "0.1.0", "description": "Visualizer for iKnow entities", "main": "gulpfile.babel.js", "scripts": { diff --git a/src/cls/EntityBrowser/Router.cls b/src/cls/EntityBrowser/Router.cls index f8e64b5..cc6a9ae 100644 --- a/src/cls/EntityBrowser/Router.cls +++ b/src/cls/EntityBrowser/Router.cls @@ -312,7 +312,7 @@ ClassMethod AppendChildObjects(ByRef pObjects, ByRef pGraph, ByRef pEntityTokens } set tNodeObj = {"id": (tNodeID), "label": (pEntityTokens(tEntIDx)), "type": "entity", "entities": [ (tEntObj) ]} do pObjects.nodes.%Push(tNodeObj) - set tEdgeObj = {"origin": (pParentNodeID), "destination": (tNodeID), "type": (tEdgeType)} + set tEdgeObj = {"source": (pParentNodeID), "target": (tNodeID), "type": (tEdgeType)} do pObjects.edges.%Push(tEdgeObj) set tSC = ..AppendChildObjects(.pObjects, .pGraph, .pEntityTokens, tNodeID, pLevel+1) diff --git a/src/static/index.html b/src/static/index.html index b566b57..0c9e887 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -70,6 +70,22 @@

Selected Nodes

+

General Settings

+
+
+ Data source: + + : + / + /domain/ + / + + / +
+
diff --git a/src/static/js/graph/index.js b/src/static/js/graph/index.js index 358bcc6..ef89252 100644 --- a/src/static/js/graph/index.js +++ b/src/static/js/graph/index.js @@ -2,43 +2,27 @@ import { updateSelectedNodes } from "../tabular"; import { getGraphData } from "../model"; import { updateSelection, setLastSelectedNode } from "../selection"; -export function update () { - - var graph = getGraphData(); - - var shiftKey, ctrlKey, - width = window.innerWidth, - height = window.innerHeight; - - var zoomer = d3.zoom() - .scaleExtent([1/4, 40]) +let shiftKey, ctrlKey, + width = window.innerWidth, + height = window.innerHeight, + foreverUniq = 0; + +let svg = null, + brush = null, + node, + link, + links, + nodes, + zoomer = d3.zoom() + .scaleExtent([1/4, 100]) .on("zoom", () => { view.attr("transform", d3.event.transform); - }); - - var dragger = d3.drag() + }), + dragger = d3.drag() .on("start", dragstarted) .on("drag", dragged) - .on("end", dragended); - - d3.select(window) - .on("keydown", keyDown) - .on("keyup", keyUp); - - var svg = d3.select("#graph") - .call(zoomer); - - var view = svg - .append("g") - .attr("class", "view"); - - var brush = view.append("g") - .datum(() => { return { selected: false, previouslySelected: false }; }) - .attr("class", "brush"); - - // var color = d3.scaleOrdinal(d3.schemeCategory20); - - var simulation = d3.forceSimulation() + .on("end", dragended), + simulation = d3.forceSimulation() .force("link", d3.forceLink() .distance(d => 50 + (d.source.radius + d.target.radius) * 2) @@ -48,13 +32,114 @@ export function update () { d3.forceManyBody() .strength(d => { return -10 * d.radius; }) ) - .force("center", d3.forceCenter(width / 2, height / 2)); + .force("center", d3.forceCenter(width / 2, height / 2)), + brusher = d3.brush() + .extent([[-9999999, -9999999], [9999999, 9999999]]) + .on("start.brush", () => { + if (!d3.event.sourceEvent) return; + node.each((d) => { + d.previouslySelected = ctrlKey && d.selected; + }); + }) + .on("brush.brush", () => { + if (!d3.event.sourceEvent) return; + let extent = d3.event.selection; + if (!extent) + return; + node.classed("selected", (d) => { + let selected = (extent[0][0] <= d.x && d.x < extent[1][0] + && extent[0][1] <= d.y && d.y < extent[1][1]); + if (selected) setLastSelectedNode(d); + return d.selected = d.previouslySelected ^ selected; + }); + }) + .on("end.brush", () => { + if (!d3.event.sourceEvent) return; + setTimeout(() => { + brush.call(brusher.move, null); + updateSelection(); + }, 25); + }), + view = null; + +function ticked () { + link + .attr("x1", d => d.source.x) + .attr("y1", d => d.source.y) + .attr("x2", d => d.target.x) + .attr("y2", d => d.target.y); + node + .attr("transform", (d) => `translate(${ d.x },${ d.y })`) +} + +function dragstarted (d) { + if (!d3.event.active) simulation.alphaTarget(0.3).restart(); + d.fx = d.x; + d.fy = d.y; +} + +function dragged (d) { + d.fx = d3.event.x; + d.fy = d3.event.y; +} + +function dragended (d) { + if (!d3.event.active) simulation.alphaTarget(0); + d.fx = null; + d.fy = null; +} + +function keyDown () { + shiftKey = d3.event.shiftKey || d3.event.metaKey; + ctrlKey = d3.event.ctrlKey; + + if (d3.event.keyCode == 67) { // the 'c' key + // do stuff + } + + if (ctrlKey) { + brush.select('.overlay').style('cursor', 'crosshair'); + brush.call(brusher); + d3.event.preventDefault(); + } +} + +function keyUp () { + shiftKey = d3.event.shiftKey || d3.event.metaKey; + ctrlKey = d3.event.ctrlKey; - var link = view.append("g") - .attr("class", "links") - .selectAll("line") - .data(graph.edges) - .enter().append("line") + brush.call(brusher) + .on(".brush", null); + + brush.select('.overlay').style('cursor', 'auto'); +} + +export function init () { + svg = d3.select("#graph") + .call(zoomer); + view = svg + .append("g") + .attr("class", "view"); + brush = view.append("g") + .datum(() => { return { selected: false, previouslySelected: false }; }) + .attr("class", "brush"); + links = view.append("g").attr("class", "links"); + nodes = view.append("g").attr("class", "nodes"); + link = links.selectAll("line"); + node = nodes.selectAll(".node"); + d3.select(window) + .on("keydown", keyDown) + .on("keyup", keyUp); +} + +export function update () { + + let graph = getGraphData(); + + link = link + .data(graph.edges, (d) => foreverUniq++); + link.exit().remove(); + link = link.enter().append("line") .attr("class", d => d.type === "similar" ? "similar" : d.type === "related" @@ -62,11 +147,10 @@ export function update () { : "other" ); - var node = view.append("g") - .attr("class", "nodes") - .selectAll(".node") - .data(graph.nodes) - .enter().append("g") + node = node + .data(graph.nodes, (d) => foreverUniq++); + node.exit().remove(); + node = node.enter().append("g") .attr("class", "node") .call(dragger) .on("dblclick", () => d3.event.stopPropagation()) @@ -80,7 +164,7 @@ export function update () { updateSelection(); }); - var circle = node.append("circle") + node.append("circle") .attr("r", d => d.radius); node.append("text") @@ -88,6 +172,9 @@ export function update () { .attr("style", d => `font-size:${ Math.round(d.radius / 2) }px`) .text(d => d.label); + node.exit().remove(); + link.exit().remove(); + simulation .nodes(graph.nodes) .on("tick", ticked); @@ -95,91 +182,13 @@ export function update () { simulation.force("link") .links(graph.edges); - var brusher = d3.brush() - .extent([[-9999999, -9999999], [9999999, 9999999]]) - .on("start.brush", () => { - if (!d3.event.sourceEvent) return; - node.each((d) => { - d.previouslySelected = ctrlKey && d.selected; - }); - }) - .on("brush.brush", () => { - if (!d3.event.sourceEvent) return; - var extent = d3.event.selection; - if (!extent) - return; - node.classed("selected", (d) => { - let selected = (extent[0][0] <= d.x && d.x < extent[1][0] - && extent[0][1] <= d.y && d.y < extent[1][1]); - if (selected) setLastSelectedNode(d); - return d.selected = d.previouslySelected ^ selected; - }); - }) - .on("end.brush", () => { - if (!d3.event.sourceEvent) return; - setTimeout(() => { - brush.call(brusher.move, null); - updateSelection(); - }, 25); - }); + simulation.restart(); brush.call(brusher) .on(".brush", null); brush.select('.overlay').style('cursor', 'auto'); - for (var i = 100; i > 0; --i) simulation.tick(); - - function ticked () { - link - .attr("x1", d => d.source.x) - .attr("y1", d => d.source.y) - .attr("x2", d => d.target.x) - .attr("y2", d => d.target.y); - node - .attr("transform", (d) => `translate(${ d.x },${ d.y })`) - } - - function dragstarted (d) { - if (!d3.event.active) simulation.alphaTarget(0.3).restart(); - d.fx = d.x; - d.fy = d.y; - } - - function dragged (d) { - d.fx = d3.event.x; - d.fy = d3.event.y; - } - - function dragended (d) { - if (!d3.event.active) simulation.alphaTarget(0); - d.fx = null; - d.fy = null; - } - - function keyDown () { - shiftKey = d3.event.shiftKey || d3.event.metaKey; - ctrlKey = d3.event.ctrlKey; - - if (d3.event.keyCode == 67) { // the 'c' key - // do stuff - } - - if (ctrlKey) { - brush.select('.overlay').style('cursor', 'crosshair'); - brush.call(brusher); - d3.event.preventDefault(); - } - } - - function keyUp () { - shiftKey = d3.event.shiftKey || d3.event.metaKey; - ctrlKey = d3.event.ctrlKey; - - brush.call(brusher) - .on(".brush", null); - - brush.select('.overlay').style('cursor', 'auto'); - } + for (let i = 100; i > 0; --i) simulation.tick(); } \ No newline at end of file diff --git a/src/static/js/index.js b/src/static/js/index.js index 790ff61..d10ef12 100644 --- a/src/static/js/index.js +++ b/src/static/js/index.js @@ -1,13 +1,17 @@ -import { update } from "./graph"; +import * as graph from "./graph"; import * as tabular from "./tabular"; import * as details from "./details"; import * as settings from "./settings"; +import * as source from "./source"; +import * as model from "./model"; window.init = () => { - update(); tabular.init(); details.init(); settings.init(); + source.init(); + graph.init(); + model.update(() => graph.update()); }; \ No newline at end of file diff --git a/src/static/js/model/index.js b/src/static/js/model/index.js index e7bda0c..b0ef18d 100644 --- a/src/static/js/model/index.js +++ b/src/static/js/model/index.js @@ -1,17 +1,50 @@ import sampleData from "../sample_output2.json"; +import { getData, getOption } from "../source"; +import { toggleLoader } from "../utils"; function preprocess (graph) { + let zeroID = null; + graph.nodes.forEach(node => { if (!zeroID && node.id === 0) zeroID = node; }); + if (!zeroID) { + graph.nodes.push({ + id: 0, + label: getOption("seed"), + type: "entity", + entities: [{ + id: -1, + value: getOption("seed") + }] + }); + } graph.nodes.forEach(node => node.radius = 5 + Math.sqrt(node.entities[0].frequency / 4 || 25)); + console.log(graph); return graph; } -var graph = preprocess(sampleData.graph); +let graph = preprocess(sampleData.graph); + +/** + * Updates the data from a server. + * @param callback + */ +export function update (callback) { + toggleLoader(); + getData(data => { + toggleLoader(false); + if (data.error || !data.graph) { + alert(data.error || `No graph data returned`); + } else { + graph = preprocess(data.graph); + } + callback(); + }); +} export function getGraphData () { return graph; } -export var uiState = { +export let uiState = { tabularToggled: false, detailsToggled: false, settingsToggled: false diff --git a/src/static/js/sample_output3.json b/src/static/js/sample_output3.json new file mode 100644 index 0000000..a6cf55f --- /dev/null +++ b/src/static/js/sample_output3.json @@ -0,0 +1,3466 @@ +{ + "graph": { + "nodes": [ + { + "id": 1, + "label": "airplane", + "type": "entity", + "entities": [ + { + "frequency": 6338, + "id": 11142, + "score": 510, + "spread": 983, + "value": "airplane" + } + ] + }, + { + "id": 2, + "label": "airplane's nose gear steering assembly", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 11602, + "score": 51, + "spread": 1, + "value": "airplane's nose gear steering assembly" + } + ] + }, + { + "id": 3, + "label": "information", + "type": "entity", + "entities": [ + { + "frequency": 137, + "id": 39164, + "score": 170, + "spread": 95, + "value": "information" + } + ] + }, + { + "id": 4, + "label": "personnel", + "type": "entity", + "entities": [ + { + "frequency": 47, + "id": 54332, + "score": 170, + "spread": 34, + "value": "personnel" + } + ] + }, + { + "id": 5, + "label": "company operations personnel", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 23635, + "score": 19, + "spread": 1, + "value": "company operations personnel" + } + ] + }, + { + "id": 6, + "label": "taxi", + "type": "entity", + "entities": [ + { + "frequency": 62, + "id": 67285, + "score": 166, + "spread": 47, + "value": "taxi" + } + ] + }, + { + "id": 7, + "label": "ground taxi", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 35646, + "score": 85, + "spread": 1, + "value": "ground taxi" + } + ] + }, + { + "id": 8, + "label": "items", + "type": "entity", + "entities": [ + { + "frequency": 13, + "id": 40449, + "score": 151, + "spread": 11, + "value": "items" + } + ] + }, + { + "id": 9, + "label": "accident", + "type": "entity", + "entities": [ + { + "frequency": 1663, + "id": 9433, + "score": 136, + "spread": 765, + "value": "accident" + } + ] + }, + { + "id": 10, + "label": "accident helicopter", + "type": "entity", + "entities": [ + { + "frequency": 39, + "id": 9516, + "score": 32, + "spread": 18, + "value": "accident helicopter" + } + ] + }, + { + "id": 11, + "label": "accident site", + "type": "entity", + "entities": [ + { + "frequency": 677, + "id": 9567, + "score": 9, + "spread": 342, + "value": "accident site" + } + ] + }, + { + "id": 12, + "label": "fire", + "type": "entity", + "entities": [ + { + "frequency": 292, + "id": 31788, + "score": 128, + "spread": 104, + "value": "fire" + } + ] + }, + { + "id": 13, + "label": "wildland fire", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 79758, + "score": 42, + "spread": 1, + "value": "wildland fire" + } + ] + }, + { + "id": 14, + "label": "power", + "type": "entity", + "entities": [ + { + "frequency": 370, + "id": 55761, + "score": 128, + "spread": 258, + "value": "power" + } + ] + }, + { + "id": 15, + "label": "airport", + "type": "entity", + "entities": [ + { + "frequency": 527, + "id": 11711, + "score": 106, + "spread": 306, + "value": "airport" + } + ] + }, + { + "id": 16, + "label": "fairbanks international airport", + "type": "entity", + "entities": [ + { + "frequency": 7, + "id": 31048, + "score": 64, + "spread": 3, + "value": "fairbanks international airport" + } + ] + }, + { + "id": 17, + "label": "cape may county airport", + "type": "entity", + "entities": [ + { + "frequency": 6, + "id": 21729, + "score": 23, + "spread": 1, + "value": "cape may county airport" + } + ] + }, + { + "id": 18, + "label": "nosewheel", + "type": "entity", + "entities": [ + { + "frequency": 9, + "id": 50649, + "score": 106, + "spread": 6, + "value": "nosewheel" + } + ] + }, + { + "id": 20, + "label": "10:33:14", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 1864, + "score": 85, + "spread": 1, + "value": "10:33:14" + } + ] + }, + { + "id": 21, + "label": "30 seconds later", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 5893, + "score": 85, + "spread": 3, + "value": "30 seconds later" + } + ] + }, + { + "id": 22, + "label": "about 09:11:54", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 9221, + "score": 85, + "spread": 1, + "value": "about 09:11:54" + } + ] + }, + { + "id": 23, + "label": "atlantic ocean", + "type": "entity", + "entities": [ + { + "frequency": 5, + "id": 17676, + "score": 85, + "spread": 5, + "value": "atlantic ocean" + } + ] + }, + { + "id": 24, + "label": "coast guard helicopter", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 23177, + "score": 85, + "spread": 2, + "value": "coast guard helicopter" + } + ] + }, + { + "id": 26, + "label": "helitack", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 37416, + "score": 85, + "spread": 1, + "value": "helitack" + } + ] + }, + { + "id": 27, + "label": "landing", + "type": "entity", + "entities": [ + { + "frequency": 579, + "id": 41773, + "score": 85, + "spread": 416, + "value": "landing" + } + ] + }, + { + "id": 28, + "label": "first landing attempt", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 31938, + "score": 64, + "spread": 2, + "value": "first landing attempt" + } + ] + }, + { + "id": 29, + "label": "landing gear", + "type": "entity", + "entities": [ + { + "frequency": 249, + "id": 41810, + "score": 64, + "spread": 168, + "value": "landing gear" + } + ] + }, + { + "id": 30, + "label": "landing checklist", + "type": "entity", + "entities": [ + { + "frequency": 7, + "id": 41789, + "score": 42, + "spread": 7, + "value": "landing checklist" + } + ] + }, + { + "id": 32, + "label": "ramp space limitations", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 57401, + "score": 85, + "spread": 1, + "value": "ramp space limitations" + } + ] + }, + { + "id": 33, + "label": "sar", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 61297, + "score": 85, + "spread": 1, + "value": "sar" + } + ] + }, + { + "id": 34, + "label": "seat", + "type": "entity", + "entities": [ + { + "frequency": 31, + "id": 61575, + "score": 85, + "spread": 21, + "value": "seat" + } + ] + }, + { + "id": 36, + "label": "right seat pilot", + "type": "entity", + "entities": [ + { + "frequency": 40, + "id": 59726, + "score": 25, + "spread": 4, + "value": "right seat pilot" + } + ] + }, + { + "id": 37, + "label": "right seat pilot states", + "type": "entity", + "entities": [ + { + "frequency": 35, + "id": 59728, + "score": 87, + "spread": 1, + "value": "right seat pilot states" + } + ] + }, + { + "id": 38, + "label": "oxford", + "type": "entity", + "entities": [ + { + "frequency": 13, + "id": 53520, + "score": 81, + "spread": 3, + "value": "oxford" + } + ] + }, + { + "id": 39, + "label": "university-oxford", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 71937, + "score": 43, + "spread": 1, + "value": "university-oxford" + } + ] + }, + { + "id": 40, + "label": "location", + "type": "entity", + "entities": [ + { + "frequency": 79, + "id": 43823, + "score": 80, + "spread": 57, + "value": "location" + } + ] + }, + { + "id": 41, + "label": "first location", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 31942, + "score": 85, + "spread": 1, + "value": "first location" + } + ] + }, + { + "id": 42, + "label": "newly assigned location", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 49079, + "score": 42, + "spread": 1, + "value": "newly assigned location" + } + ] + }, + { + "id": 43, + "label": "second interim location", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 61696, + "score": 42, + "spread": 1, + "value": "second interim location" + } + ] + }, + { + "id": 44, + "label": "final parking location", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 31736, + "score": 36, + "spread": 1, + "value": "final parking location" + } + ] + }, + { + "id": 45, + "label": "about 09:17:52", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 9222, + "score": 76, + "spread": 1, + "value": "about 09:17:52" + } + ] + }, + { + "id": 46, + "label": "mississippi", + "type": "entity", + "entities": [ + { + "frequency": 40, + "id": 46630, + "score": 71, + "spread": 17, + "value": "mississippi" + } + ] + }, + { + "id": 47, + "label": "takeoff checklists", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 67153, + "score": 68, + "spread": 1, + "value": "takeoff checklists" + } + ] + }, + { + "id": 48, + "label": "#5 passenger", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 53, + "score": 64, + "spread": 1, + "value": "#5 passenger" + } + ] + }, + { + "id": 51, + "label": "360-degree", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 6334, + "score": 64, + "spread": 2, + "value": "360-degree" + } + ] + }, + { + "id": 52, + "label": "aircraft", + "type": "entity", + "entities": [ + { + "frequency": 679, + "id": 10841, + "score": 64, + "spread": 268, + "value": "aircraft" + } + ] + }, + { + "id": 53, + "label": "sportstar aircraft operating instructions", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 65116, + "score": 42, + "spread": 1, + "value": "sportstar aircraft operating instructions" + } + ] + }, + { + "id": 54, + "label": "both separated wings", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 20281, + "score": 64, + "spread": 1, + "value": "both separated wings" + } + ] + }, + { + "id": 55, + "label": "cabin", + "type": "entity", + "entities": [ + { + "frequency": 67, + "id": 21359, + "score": 64, + "spread": 49, + "value": "cabin" + } + ] + }, + { + "id": 58, + "label": "departure", + "type": "entity", + "entities": [ + { + "frequency": 132, + "id": 26518, + "score": 64, + "spread": 109, + "value": "departure" + } + ] + }, + { + "id": 59, + "label": "directional control", + "type": "entity", + "entities": [ + { + "frequency": 59, + "id": 27423, + "score": 64, + "spread": 55, + "value": "directional control" + } + ] + }, + { + "id": 60, + "label": "emergency", + "type": "entity", + "entities": [ + { + "frequency": 40, + "id": 29094, + "score": 64, + "spread": 35, + "value": "emergency" + } + ] + }, + { + "id": 61, + "label": "federal aviation administration", + "type": "entity", + "entities": [ + { + "frequency": 347, + "id": 31454, + "score": 64, + "spread": 332, + "value": "federal aviation administration" + } + ] + }, + { + "id": 62, + "label": "first", + "type": "entity", + "entities": [ + { + "frequency": 92, + "id": 31865, + "score": 64, + "spread": 74, + "value": "first" + } + ] + }, + { + "id": 63, + "label": "first sighting", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 31984, + "score": 36, + "spread": 1, + "value": "first sighting" + } + ] + }, + { + "id": 64, + "label": "fuel", + "type": "entity", + "entities": [ + { + "frequency": 598, + "id": 33854, + "score": 64, + "spread": 268, + "value": "fuel" + } + ] + }, + { + "id": 65, + "label": "fuel volume", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 34185, + "score": 64, + "spread": 1, + "value": "fuel volume" + } + ] + }, + { + "id": 66, + "label": "go-around", + "type": "entity", + "entities": [ + { + "frequency": 101, + "id": 35111, + "score": 64, + "spread": 70, + "value": "go-around" + } + ] + }, + { + "id": 67, + "label": "halt", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 36718, + "score": 64, + "spread": 2, + "value": "halt" + } + ] + }, + { + "id": 68, + "label": "initial attack", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 39211, + "score": 64, + "spread": 1, + "value": "initial attack" + } + ] + }, + { + "id": 69, + "label": "3-person helicopter initial attack", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 5804, + "score": 64, + "spread": 1, + "value": "3-person helicopter initial attack" + } + ] + }, + { + "id": 70, + "label": "instructions", + "type": "entity", + "entities": [ + { + "frequency": 17, + "id": 39502, + "score": 64, + "spread": 17, + "value": "instructions" + } + ] + }, + { + "id": 73, + "label": "longer", + "type": "entity", + "entities": [ + { + "frequency": 11, + "id": 43947, + "score": 64, + "spread": 10, + "value": "longer" + } + ] + }, + { + "id": 74, + "label": "lower altitude", + "type": "entity", + "entities": [ + { + "frequency": 8, + "id": 44281, + "score": 64, + "spread": 7, + "value": "lower altitude" + } + ] + }, + { + "id": 75, + "label": "maximum weight", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 45559, + "score": 64, + "spread": 3, + "value": "maximum weight" + } + ] + }, + { + "id": 76, + "label": "medical equipment", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 46083, + "score": 64, + "spread": 1, + "value": "medical equipment" + } + ] + }, + { + "id": 77, + "label": "one", + "type": "entity", + "entities": [ + { + "frequency": 104, + "id": 52120, + "score": 64, + "spread": 70, + "value": "one" + } + ] + }, + { + "id": 78, + "label": "one hour flight", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 52198, + "score": 85, + "spread": 1, + "value": "one hour flight" + } + ] + }, + { + "id": 79, + "label": "cones vor", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 23934, + "score": 64, + "spread": 1, + "value": "cones vor" + } + ] + }, + { + "id": 80, + "label": "less than one mile", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 43134, + "score": 42, + "spread": 1, + "value": "less than one mile" + } + ] + }, + { + "id": 81, + "label": "component", + "type": "entity", + "entities": [ + { + "frequency": 13, + "id": 23763, + "score": 36, + "spread": 12, + "value": "component" + } + ] + }, + { + "id": 82, + "label": "passengers", + "type": "entity", + "entities": [ + { + "frequency": 31, + "id": 54022, + "score": 64, + "spread": 25, + "value": "passengers" + } + ] + }, + { + "id": 83, + "label": "rear", + "type": "entity", + "entities": [ + { + "frequency": 27, + "id": 57645, + "score": 64, + "spread": 24, + "value": "rear" + } + ] + }, + { + "id": 84, + "label": "rescue", + "type": "entity", + "entities": [ + { + "frequency": 5, + "id": 58838, + "score": 64, + "spread": 5, + "value": "rescue" + } + ] + }, + { + "id": 85, + "label": "local rescuers", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 43750, + "score": 64, + "spread": 1, + "value": "local rescuers" + } + ] + }, + { + "id": 87, + "label": "single pilot", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 63618, + "score": 64, + "spread": 1, + "value": "single pilot" + } + ] + }, + { + "id": 88, + "label": "things", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 68476, + "score": 64, + "spread": 4, + "value": "things" + } + ] + }, + { + "id": 89, + "label": "unfamiliar", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 71842, + "score": 64, + "spread": 4, + "value": "unfamiliar" + } + ] + }, + { + "id": 90, + "label": "weather", + "type": "entity", + "entities": [ + { + "frequency": 204, + "id": 77053, + "score": 64, + "spread": 120, + "value": "weather" + } + ] + }, + { + "id": 91, + "label": "weather conditions", + "type": "entity", + "entities": [ + { + "frequency": 38, + "id": 77062, + "score": 32, + "spread": 34, + "value": "weather conditions" + } + ] + }, + { + "id": 92, + "label": "1 minute", + "type": "entity", + "entities": [ + { + "frequency": 7, + "id": 828, + "score": 51, + "spread": 7, + "value": "1 minute" + } + ] + }, + { + "id": 93, + "label": "2143", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 4840, + "score": 51, + "spread": 1, + "value": "2143" + } + ] + }, + { + "id": 94, + "label": "elliott bay", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 29034, + "score": 51, + "spread": 1, + "value": "elliott bay" + } + ] + }, + { + "id": 95, + "label": "faa", + "type": "entity", + "entities": [ + { + "frequency": 584, + "id": 30668, + "score": 51, + "spread": 368, + "value": "faa" + } + ] + }, + { + "id": 97, + "label": "flying", + "type": "entity", + "entities": [ + { + "frequency": 76, + "id": 32776, + "score": 51, + "spread": 69, + "value": "flying" + } + ] + }, + { + "id": 98, + "label": "navigation", + "type": "entity", + "entities": [ + { + "frequency": 15, + "id": 48689, + "score": 51, + "spread": 13, + "value": "navigation" + } + ] + }, + { + "id": 99, + "label": "observation 2330 zulu", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 51291, + "score": 51, + "spread": 1, + "value": "observation 2330 zulu" + } + ] + }, + { + "id": 100, + "label": "right", + "type": "entity", + "entities": [ + { + "frequency": 351, + "id": 59420, + "score": 51, + "spread": 238, + "value": "right" + } + ] + }, + { + "id": 101, + "label": "runway 13 right", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 60636, + "score": 64, + "spread": 1, + "value": "runway 13 right" + } + ] + }, + { + "id": 102, + "label": "right side overwing exit", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 59742, + "score": 42, + "spread": 1, + "value": "right side overwing exit" + } + ] + }, + { + "id": 103, + "label": "wreckage", + "type": "entity", + "entities": [ + { + "frequency": 618, + "id": 80734, + "score": 51, + "spread": 288, + "value": "wreckage" + } + ] + }, + { + "id": 104, + "label": "0837", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 642, + "score": 42, + "spread": 1, + "value": "0837" + } + ] + }, + { + "id": 105, + "label": "500 feet", + "type": "entity", + "entities": [ + { + "frequency": 47, + "id": 7372, + "score": 42, + "spread": 38, + "value": "500 feet" + } + ] + }, + { + "id": 106, + "label": "500-foot callout", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 7398, + "score": 42, + "spread": 1, + "value": "500-foot callout" + } + ] + }, + { + "id": 107, + "label": "air traffic control", + "type": "entity", + "entities": [ + { + "frequency": 40, + "id": 10770, + "score": 42, + "spread": 39, + "value": "air traffic control" + } + ] + }, + { + "id": 108, + "label": "all efforts", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 12046, + "score": 42, + "spread": 1, + "value": "all efforts" + } + ] + }, + { + "id": 109, + "label": "approach", + "type": "entity", + "entities": [ + { + "frequency": 222, + "id": 15634, + "score": 42, + "spread": 137, + "value": "approach" + } + ] + }, + { + "id": 110, + "label": "missed approach", + "type": "entity", + "entities": [ + { + "frequency": 10, + "id": 46597, + "score": 42, + "spread": 7, + "value": "missed approach" + } + ] + }, + { + "id": 111, + "label": "baggage weight", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 18631, + "score": 42, + "spread": 1, + "value": "baggage weight" + } + ] + }, + { + "id": 112, + "label": "beacon", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 18928, + "score": 42, + "spread": 3, + "value": "beacon" + } + ] + }, + { + "id": 114, + "label": "cockpit", + "type": "entity", + "entities": [ + { + "frequency": 158, + "id": 23201, + "score": 42, + "spread": 113, + "value": "cockpit" + } + ] + }, + { + "id": 115, + "label": "cockpit crew", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 23217, + "score": 21, + "spread": 1, + "value": "cockpit crew" + } + ] + }, + { + "id": 116, + "label": "descending turn", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 26639, + "score": 42, + "spread": 4, + "value": "descending turn" + } + ] + }, + { + "id": 117, + "label": "flight", + "type": "entity", + "entities": [ + { + "frequency": 1457, + "id": 32384, + "score": 42, + "spread": 695, + "value": "flight" + } + ] + }, + { + "id": 118, + "label": "flight nurse", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 32528, + "score": 51, + "spread": 2, + "value": "flight nurse" + } + ] + }, + { + "id": 119, + "label": "millville flight service station", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 46458, + "score": 42, + "spread": 1, + "value": "millville flight service station" + } + ] + }, + { + "id": 120, + "label": "in-flight hydraulics failure", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 38789, + "score": 19, + "spread": 1, + "value": "in-flight hydraulics failure" + } + ] + }, + { + "id": 121, + "label": "marshal", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 45376, + "score": 42, + "spread": 3, + "value": "marshal" + } + ] + }, + { + "id": 122, + "label": "n106ln", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 47615, + "score": 42, + "spread": 1, + "value": "n106ln" + } + ] + }, + { + "id": 123, + "label": "no warning lights", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 49971, + "score": 42, + "spread": 1, + "value": "no warning lights" + } + ] + }, + { + "id": 124, + "label": "normal", + "type": "entity", + "entities": [ + { + "frequency": 140, + "id": 50210, + "score": 42, + "spread": 124, + "value": "normal" + } + ] + }, + { + "id": 125, + "label": "operation", + "type": "entity", + "entities": [ + { + "frequency": 81, + "id": 52689, + "score": 42, + "spread": 59, + "value": "operation" + } + ] + }, + { + "id": 126, + "label": "road", + "type": "entity", + "entities": [ + { + "frequency": 79, + "id": 59948, + "score": 42, + "spread": 53, + "value": "road" + } + ] + }, + { + "id": 128, + "label": "search", + "type": "entity", + "entities": [ + { + "frequency": 32, + "id": 61559, + "score": 42, + "spread": 30, + "value": "search" + } + ] + }, + { + "id": 129, + "label": "series", + "type": "entity", + "entities": [ + { + "frequency": 37, + "id": 62489, + "score": 42, + "spread": 32, + "value": "series" + } + ] + }, + { + "id": 130, + "label": "system", + "type": "entity", + "entities": [ + { + "frequency": 50, + "id": 66836, + "score": 42, + "spread": 43, + "value": "system" + } + ] + }, + { + "id": 131, + "label": "helicopter's hydraulic systems", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 37380, + "score": 25, + "spread": 1, + "value": "helicopter's hydraulic systems" + } + ] + }, + { + "id": 132, + "label": "uc5100 system", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 71616, + "score": 25, + "spread": 1, + "value": "uc5100 system" + } + ] + }, + { + "id": 133, + "label": "trouble-shooting", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 70707, + "score": 42, + "spread": 1, + "value": "trouble-shooting" + } + ] + }, + { + "id": 134, + "label": "vicinity", + "type": "entity", + "entities": [ + { + "frequency": 126, + "id": 72966, + "score": 42, + "spread": 96, + "value": "vicinity" + } + ] + }, + { + "id": 135, + "label": "wait", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 73259, + "score": 42, + "spread": 2, + "value": "wait" + } + ] + }, + { + "id": 136, + "label": "2212 utc", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 4955, + "score": 36, + "spread": 1, + "value": "2212 utc" + } + ] + }, + { + "id": 137, + "label": "3 minutes", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 5590, + "score": 36, + "spread": 3, + "value": "3 minutes" + } + ] + }, + { + "id": 138, + "label": "fss", + "type": "entity", + "entities": [ + { + "frequency": 15, + "id": 33845, + "score": 36, + "spread": 13, + "value": "fss" + } + ] + }, + { + "id": 139, + "label": "paramedic", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 53767, + "score": 36, + "spread": 3, + "value": "paramedic" + } + ] + }, + { + "id": 140, + "label": "problem", + "type": "entity", + "entities": [ + { + "frequency": 55, + "id": 56527, + "score": 36, + "spread": 50, + "value": "problem" + } + ] + }, + { + "id": 141, + "label": "south", + "type": "entity", + "entities": [ + { + "frequency": 113, + "id": 64675, + "score": 36, + "spread": 78, + "value": "south" + } + ] + }, + { + "id": 142, + "label": "way", + "type": "entity", + "entities": [ + { + "frequency": 48, + "id": 77015, + "score": 36, + "spread": 38, + "value": "way" + } + ] + }, + { + "id": 143, + "label": "runway 09r", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 60614, + "score": 42, + "spread": 1, + "value": "runway 09r" + } + ] + }, + { + "id": 144, + "label": "runway 14", + "type": "entity", + "entities": [ + { + "frequency": 23, + "id": 60641, + "score": 25, + "spread": 16, + "value": "runway 14" + } + ] + }, + { + "id": 145, + "label": "aspen ridge", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 17425, + "score": 32, + "spread": 1, + "value": "aspen ridge" + } + ] + }, + { + "id": 146, + "label": "assertive", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 17449, + "score": 32, + "spread": 1, + "value": "assertive" + } + ] + }, + { + "id": 147, + "label": "better position", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 19572, + "score": 32, + "spread": 1, + "value": "better position" + } + ] + }, + { + "id": 148, + "label": "descent", + "type": "entity", + "entities": [ + { + "frequency": 121, + "id": 26641, + "score": 32, + "spread": 95, + "value": "descent" + } + ] + }, + { + "id": 149, + "label": "door open", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 27843, + "score": 32, + "spread": 2, + "value": "door open" + } + ] + }, + { + "id": 150, + "label": "essential", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 29946, + "score": 32, + "spread": 3, + "value": "essential" + } + ] + }, + { + "id": 151, + "label": "fl 350", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 32168, + "score": 32, + "spread": 1, + "value": "fl 350" + } + ] + }, + { + "id": 152, + "label": "flaps", + "type": "entity", + "entities": [ + { + "frequency": 180, + "id": 32265, + "score": 32, + "spread": 131, + "value": "flaps" + } + ] + }, + { + "id": 153, + "label": "further clearance", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 34423, + "score": 32, + "spread": 1, + "value": "further clearance" + } + ] + }, + { + "id": 154, + "label": "hangar 3", + "type": "entity", + "entities": [ + { + "frequency": 6, + "id": 36782, + "score": 32, + "spread": 1, + "value": "hangar 3" + } + ] + }, + { + "id": 155, + "label": "hover tests", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 38001, + "score": 32, + "spread": 1, + "value": "hover tests" + } + ] + }, + { + "id": 156, + "label": "logo lights", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 43898, + "score": 32, + "spread": 1, + "value": "logo lights" + } + ] + }, + { + "id": 157, + "label": "november 12, 2003", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 50834, + "score": 32, + "spread": 1, + "value": "november 12, 2003" + } + ] + }, + { + "id": 158, + "label": "purpose", + "type": "entity", + "entities": [ + { + "frequency": 74, + "id": 57061, + "score": 32, + "spread": 68, + "value": "purpose" + } + ] + }, + { + "id": 159, + "label": "radar altimeter", + "type": "entity", + "entities": [ + { + "frequency": 5, + "id": 57244, + "score": 32, + "spread": 2, + "value": "radar altimeter" + } + ] + }, + { + "id": 160, + "label": "section 6.3", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 61825, + "score": 32, + "spread": 1, + "value": "section 6.3" + } + ] + }, + { + "id": 161, + "label": "sound", + "type": "entity", + "entities": [ + { + "frequency": 54, + "id": 64659, + "score": 32, + "spread": 33, + "value": "sound" + } + ] + }, + { + "id": 162, + "label": "popping sounds", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 55529, + "score": 18, + "spread": 3, + "value": "popping sounds" + } + ] + }, + { + "id": 163, + "label": "vor", + "type": "entity", + "entities": [ + { + "frequency": 10, + "id": 73205, + "score": 32, + "spread": 10, + "value": "vor" + } + ] + }, + { + "id": 164, + "label": "time stamp", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 68959, + "score": 30, + "spread": 3, + "value": "time stamp" + } + ] + }, + { + "id": 165, + "label": "1032:52", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 1773, + "score": 28, + "spread": 1, + "value": "1032:52" + } + ] + }, + { + "id": 166, + "label": "efc", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 28633, + "score": 28, + "spread": 1, + "value": "efc" + } + ] + }, + { + "id": 167, + "label": "floating debris", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 32679, + "score": 28, + "spread": 3, + "value": "floating debris" + } + ] + }, + { + "id": 168, + "label": "n509am", + "type": "entity", + "entities": [ + { + "frequency": 5, + "id": 48088, + "score": 28, + "spread": 1, + "value": "n509am" + } + ] + }, + { + "id": 169, + "label": "notams", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 50706, + "score": 28, + "spread": 4, + "value": "notams" + } + ] + }, + { + "id": 170, + "label": "rochester", + "type": "entity", + "entities": [ + { + "frequency": 19, + "id": 59997, + "score": 28, + "spread": 4, + "value": "rochester" + } + ] + }, + { + "id": 171, + "label": "t-33", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 66867, + "score": 28, + "spread": 1, + "value": "t-33" + } + ] + }, + { + "id": 172, + "label": "1000", + "type": "entity", + "entities": [ + { + "frequency": 16, + "id": 1638, + "score": 25, + "spread": 14, + "value": "1000" + } + ] + }, + { + "id": 173, + "label": "cessna 500", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 22321, + "score": 25, + "spread": 1, + "value": "cessna 500" + } + ] + }, + { + "id": 174, + "label": "full", + "type": "entity", + "entities": [ + { + "frequency": 63, + "id": 34215, + "score": 25, + "spread": 48, + "value": "full" + } + ] + }, + { + "id": 175, + "label": "issuance", + "type": "entity", + "entities": [ + { + "frequency": 12, + "id": 40420, + "score": 25, + "spread": 9, + "value": "issuance" + } + ] + }, + { + "id": 176, + "label": "minnesota", + "type": "entity", + "entities": [ + { + "frequency": 30, + "id": 46523, + "score": 25, + "spread": 11, + "value": "minnesota" + } + ] + }, + { + "id": 177, + "label": "no. 3 engine", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 50041, + "score": 25, + "spread": 1, + "value": "no. 3 engine" + } + ] + }, + { + "id": 178, + "label": "permitted payload range table", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 54289, + "score": 25, + "spread": 1, + "value": "permitted payload range table" + } + ] + }, + { + "id": 179, + "label": "touchdown", + "type": "entity", + "entities": [ + { + "frequency": 111, + "id": 70162, + "score": 25, + "spread": 94, + "value": "touchdown" + } + ] + }, + { + "id": 180, + "label": "1630", + "type": "entity", + "entities": [ + { + "frequency": 11, + "id": 3287, + "score": 23, + "spread": 11, + "value": "1630" + } + ] + }, + { + "id": 181, + "label": "1630 local", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 3288, + "score": 64, + "spread": 1, + "value": "1630 local" + } + ] + }, + { + "id": 182, + "label": "747", + "type": "entity", + "entities": [ + { + "frequency": 12, + "id": 8265, + "score": 23, + "spread": 1, + "value": "747" + } + ] + }, + { + "id": 183, + "label": "credit card receipt", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 25251, + "score": 23, + "spread": 2, + "value": "credit card receipt" + } + ] + }, + { + "id": 184, + "label": "family", + "type": "entity", + "entities": [ + { + "frequency": 22, + "id": 31112, + "score": 21, + "spread": 20, + "value": "family" + } + ] + }, + { + "id": 185, + "label": "increased background noise", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 38963, + "score": 21, + "spread": 1, + "value": "increased background noise" + } + ] + }, + { + "id": 186, + "label": "zurich", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 80993, + "score": 21, + "spread": 1, + "value": "zurich" + } + ] + }, + { + "id": 187, + "label": "527 gallons", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 7451, + "score": 19, + "spread": 1, + "value": "527 gallons" + } + ] + }, + { + "id": 188, + "label": "controller", + "type": "entity", + "entities": [ + { + "frequency": 331, + "id": 24448, + "score": 19, + "spread": 75, + "value": "controller" + } + ] + }, + { + "id": 189, + "label": "local controller", + "type": "entity", + "entities": [ + { + "frequency": 20, + "id": 43691, + "score": 64, + "spread": 9, + "value": "local controller" + } + ] + }, + { + "id": 190, + "label": "center controller", + "type": "entity", + "entities": [ + { + "frequency": 2, + "id": 22065, + "score": 42, + "spread": 2, + "value": "center controller" + } + ] + }, + { + "id": 191, + "label": "alert notification", + "type": "entity", + "entities": [ + { + "frequency": 6, + "id": 11944, + "score": 18, + "spread": 6, + "value": "alert notification" + } + ] + }, + { + "id": 192, + "label": "thrust reverser", + "type": "entity", + "entities": [ + { + "frequency": 4, + "id": 68873, + "score": 18, + "spread": 2, + "value": "thrust reverser" + } + ] + }, + { + "id": 193, + "label": "alnot", + "type": "entity", + "entities": [ + { + "frequency": 13, + "id": 12534, + "score": 17, + "spread": 12, + "value": "alnot" + } + ] + }, + { + "id": 194, + "label": "jet", + "type": "entity", + "entities": [ + { + "frequency": 7, + "id": 40734, + "score": 17, + "spread": 5, + "value": "jet" + } + ] + }, + { + "id": 195, + "label": "citationjet", + "type": "entity", + "entities": [ + { + "frequency": 3, + "id": 22801, + "score": 64, + "spread": 1, + "value": "citationjet" + } + ] + }, + { + "id": 196, + "label": "0846", + "type": "entity", + "entities": [ + { + "frequency": 1, + "id": 646, + "score": 12, + "spread": 1, + "value": "0846" + } + ] + } + ], + "edges": [ + { + "source": 0, + "target": 1, + "type": "related" + }, + { + "source": 1, + "target": 2, + "type": "similar" + }, + { + "source": 0, + "target": 3, + "type": "related" + }, + { + "source": 0, + "target": 4, + "type": "related" + }, + { + "source": 4, + "target": 5, + "type": "similar" + }, + { + "source": 0, + "target": 6, + "type": "related" + }, + { + "source": 6, + "target": 7, + "type": "similar" + }, + { + "source": 0, + "target": 8, + "type": "related" + }, + { + "source": 0, + "target": 9, + "type": "related" + }, + { + "source": 9, + "target": 10, + "type": "similar" + }, + { + "source": 9, + "target": 11, + "type": "similar" + }, + { + "source": 0, + "target": 12, + "type": "related" + }, + { + "source": 12, + "target": 13, + "type": "similar" + }, + { + "source": 0, + "target": 14, + "type": "related" + }, + { + "source": 0, + "target": 15, + "type": "related" + }, + { + "source": 15, + "target": 16, + "type": "similar" + }, + { + "source": 15, + "target": 17, + "type": "similar" + }, + { + "source": 0, + "target": 18, + "type": "related" + }, + { + "source": 0, + "target": 20, + "type": "related" + }, + { + "source": 0, + "target": 21, + "type": "related" + }, + { + "source": 0, + "target": 22, + "type": "related" + }, + { + "source": 0, + "target": 23, + "type": "related" + }, + { + "source": 0, + "target": 24, + "type": "related" + }, + { + "source": 0, + "target": 26, + "type": "related" + }, + { + "source": 0, + "target": 27, + "type": "related" + }, + { + "source": 27, + "target": 28, + "type": "similar" + }, + { + "source": 27, + "target": 29, + "type": "similar" + }, + { + "source": 27, + "target": 30, + "type": "similar" + }, + { + "source": 0, + "target": 32, + "type": "related" + }, + { + "source": 0, + "target": 33, + "type": "related" + }, + { + "source": 0, + "target": 34, + "type": "related" + }, + { + "source": 34, + "target": 36, + "type": "similar" + }, + { + "source": 36, + "target": 37, + "type": "similar" + }, + { + "source": 0, + "target": 38, + "type": "related" + }, + { + "source": 38, + "target": 39, + "type": "similar" + }, + { + "source": 0, + "target": 40, + "type": "related" + }, + { + "source": 40, + "target": 41, + "type": "similar" + }, + { + "source": 40, + "target": 42, + "type": "similar" + }, + { + "source": 40, + "target": 43, + "type": "similar" + }, + { + "source": 40, + "target": 44, + "type": "similar" + }, + { + "source": 0, + "target": 45, + "type": "related" + }, + { + "source": 0, + "target": 46, + "type": "related" + }, + { + "source": 0, + "target": 47, + "type": "related" + }, + { + "source": 0, + "target": 48, + "type": "related" + }, + { + "source": 0, + "target": 51, + "type": "related" + }, + { + "source": 0, + "target": 52, + "type": "related" + }, + { + "source": 52, + "target": 53, + "type": "similar" + }, + { + "source": 0, + "target": 54, + "type": "related" + }, + { + "source": 0, + "target": 55, + "type": "related" + }, + { + "source": 0, + "target": 58, + "type": "related" + }, + { + "source": 0, + "target": 59, + "type": "related" + }, + { + "source": 0, + "target": 60, + "type": "related" + }, + { + "source": 0, + "target": 61, + "type": "related" + }, + { + "source": 0, + "target": 62, + "type": "related" + }, + { + "source": 62, + "target": 63, + "type": "similar" + }, + { + "source": 0, + "target": 64, + "type": "related" + }, + { + "source": 64, + "target": 65, + "type": "similar" + }, + { + "source": 0, + "target": 66, + "type": "related" + }, + { + "source": 0, + "target": 67, + "type": "related" + }, + { + "source": 0, + "target": 68, + "type": "related" + }, + { + "source": 68, + "target": 69, + "type": "similar" + }, + { + "source": 0, + "target": 70, + "type": "related" + }, + { + "source": 0, + "target": 73, + "type": "related" + }, + { + "source": 0, + "target": 74, + "type": "related" + }, + { + "source": 0, + "target": 75, + "type": "related" + }, + { + "source": 0, + "target": 76, + "type": "related" + }, + { + "source": 0, + "target": 77, + "type": "related" + }, + { + "source": 77, + "target": 78, + "type": "similar" + }, + { + "source": 77, + "target": 79, + "type": "similar" + }, + { + "source": 77, + "target": 80, + "type": "similar" + }, + { + "source": 77, + "target": 81, + "type": "similar" + }, + { + "source": 0, + "target": 82, + "type": "related" + }, + { + "source": 0, + "target": 83, + "type": "related" + }, + { + "source": 0, + "target": 84, + "type": "related" + }, + { + "source": 84, + "target": 85, + "type": "similar" + }, + { + "source": 0, + "target": 87, + "type": "related" + }, + { + "source": 0, + "target": 88, + "type": "related" + }, + { + "source": 0, + "target": 89, + "type": "related" + }, + { + "source": 0, + "target": 90, + "type": "related" + }, + { + "source": 90, + "target": 91, + "type": "similar" + }, + { + "source": 0, + "target": 92, + "type": "related" + }, + { + "source": 0, + "target": 93, + "type": "related" + }, + { + "source": 0, + "target": 94, + "type": "related" + }, + { + "source": 0, + "target": 95, + "type": "related" + }, + { + "source": 0, + "target": 97, + "type": "related" + }, + { + "source": 0, + "target": 98, + "type": "related" + }, + { + "source": 0, + "target": 99, + "type": "related" + }, + { + "source": 0, + "target": 100, + "type": "related" + }, + { + "source": 100, + "target": 101, + "type": "similar" + }, + { + "source": 100, + "target": 102, + "type": "similar" + }, + { + "source": 0, + "target": 103, + "type": "related" + }, + { + "source": 0, + "target": 104, + "type": "related" + }, + { + "source": 0, + "target": 105, + "type": "related" + }, + { + "source": 0, + "target": 106, + "type": "related" + }, + { + "source": 0, + "target": 107, + "type": "related" + }, + { + "source": 0, + "target": 108, + "type": "related" + }, + { + "source": 0, + "target": 109, + "type": "related" + }, + { + "source": 109, + "target": 110, + "type": "similar" + }, + { + "source": 0, + "target": 111, + "type": "related" + }, + { + "source": 0, + "target": 112, + "type": "related" + }, + { + "source": 0, + "target": 114, + "type": "related" + }, + { + "source": 114, + "target": 115, + "type": "similar" + }, + { + "source": 0, + "target": 116, + "type": "related" + }, + { + "source": 0, + "target": 117, + "type": "related" + }, + { + "source": 117, + "target": 118, + "type": "similar" + }, + { + "source": 117, + "target": 119, + "type": "similar" + }, + { + "source": 117, + "target": 120, + "type": "similar" + }, + { + "source": 0, + "target": 121, + "type": "related" + }, + { + "source": 0, + "target": 122, + "type": "related" + }, + { + "source": 0, + "target": 123, + "type": "related" + }, + { + "source": 0, + "target": 124, + "type": "related" + }, + { + "source": 0, + "target": 125, + "type": "related" + }, + { + "source": 0, + "target": 126, + "type": "related" + }, + { + "source": 0, + "target": 128, + "type": "related" + }, + { + "source": 0, + "target": 129, + "type": "related" + }, + { + "source": 0, + "target": 130, + "type": "related" + }, + { + "source": 130, + "target": 131, + "type": "similar" + }, + { + "source": 130, + "target": 132, + "type": "similar" + }, + { + "source": 0, + "target": 133, + "type": "related" + }, + { + "source": 0, + "target": 134, + "type": "related" + }, + { + "source": 0, + "target": 135, + "type": "related" + }, + { + "source": 0, + "target": 136, + "type": "related" + }, + { + "source": 0, + "target": 137, + "type": "related" + }, + { + "source": 0, + "target": 138, + "type": "related" + }, + { + "source": 0, + "target": 139, + "type": "related" + }, + { + "source": 0, + "target": 140, + "type": "related" + }, + { + "source": 0, + "target": 141, + "type": "related" + }, + { + "source": 0, + "target": 142, + "type": "related" + }, + { + "source": 142, + "target": 143, + "type": "similar" + }, + { + "source": 142, + "target": 144, + "type": "similar" + }, + { + "source": 0, + "target": 145, + "type": "related" + }, + { + "source": 0, + "target": 146, + "type": "related" + }, + { + "source": 0, + "target": 147, + "type": "related" + }, + { + "source": 0, + "target": 148, + "type": "related" + }, + { + "source": 0, + "target": 149, + "type": "related" + }, + { + "source": 0, + "target": 150, + "type": "related" + }, + { + "source": 0, + "target": 151, + "type": "related" + }, + { + "source": 0, + "target": 152, + "type": "related" + }, + { + "source": 0, + "target": 153, + "type": "related" + }, + { + "source": 0, + "target": 154, + "type": "related" + }, + { + "source": 0, + "target": 155, + "type": "related" + }, + { + "source": 0, + "target": 156, + "type": "related" + }, + { + "source": 0, + "target": 157, + "type": "related" + }, + { + "source": 0, + "target": 158, + "type": "related" + }, + { + "source": 0, + "target": 159, + "type": "related" + }, + { + "source": 0, + "target": 160, + "type": "related" + }, + { + "source": 0, + "target": 161, + "type": "related" + }, + { + "source": 161, + "target": 162, + "type": "similar" + }, + { + "source": 0, + "target": 163, + "type": "related" + }, + { + "source": 0, + "target": 164, + "type": "related" + }, + { + "source": 0, + "target": 165, + "type": "related" + }, + { + "source": 0, + "target": 166, + "type": "related" + }, + { + "source": 0, + "target": 167, + "type": "related" + }, + { + "source": 0, + "target": 168, + "type": "related" + }, + { + "source": 0, + "target": 169, + "type": "related" + }, + { + "source": 0, + "target": 170, + "type": "related" + }, + { + "source": 0, + "target": 171, + "type": "related" + }, + { + "source": 0, + "target": 172, + "type": "related" + }, + { + "source": 0, + "target": 173, + "type": "related" + }, + { + "source": 0, + "target": 174, + "type": "related" + }, + { + "source": 0, + "target": 175, + "type": "related" + }, + { + "source": 0, + "target": 176, + "type": "related" + }, + { + "source": 0, + "target": 177, + "type": "related" + }, + { + "source": 0, + "target": 178, + "type": "related" + }, + { + "source": 0, + "target": 179, + "type": "related" + }, + { + "source": 0, + "target": 180, + "type": "related" + }, + { + "source": 180, + "target": 181, + "type": "similar" + }, + { + "source": 0, + "target": 182, + "type": "related" + }, + { + "source": 0, + "target": 183, + "type": "related" + }, + { + "source": 0, + "target": 184, + "type": "related" + }, + { + "source": 0, + "target": 185, + "type": "related" + }, + { + "source": 0, + "target": 186, + "type": "related" + }, + { + "source": 0, + "target": 187, + "type": "related" + }, + { + "source": 0, + "target": 188, + "type": "related" + }, + { + "source": 188, + "target": 189, + "type": "similar" + }, + { + "source": 188, + "target": 190, + "type": "similar" + }, + { + "source": 0, + "target": 191, + "type": "related" + }, + { + "source": 0, + "target": 192, + "type": "related" + }, + { + "source": 0, + "target": 193, + "type": "related" + }, + { + "source": 0, + "target": 194, + "type": "related" + }, + { + "source": 194, + "target": 195, + "type": "similar" + }, + { + "source": 0, + "target": 196, + "type": "related" + } + ] + } +} \ No newline at end of file diff --git a/src/static/js/settings/index.js b/src/static/js/settings/index.js index d31e1af..ac92298 100644 --- a/src/static/js/settings/index.js +++ b/src/static/js/settings/index.js @@ -1,9 +1,13 @@ import * as model from "../model"; +import * as graph from "../graph"; function toggleSettings (uiStateModel) { uiStateModel.settingsToggled = !uiStateModel.settingsToggled; d3.select("#settings").classed("active", uiStateModel.settingsToggled); d3.select("#windows").classed("offScreen", uiStateModel.settingsToggled); + if (!uiStateModel.settingsToggled) { + model.update(() => graph.update()); + } } export function init () { @@ -16,4 +20,30 @@ export function init () { .data([model.uiState]) .on("click", toggleSettings); + // make inputs auto-sizable + [].slice.call(document.querySelectorAll(`input[autosize]`)).forEach((input) => { + + function updateInput () { + let style = window.getComputedStyle(input), + ghost = document.createElement(`span`); + ghost.style.cssText = `box-sizing:content-box;display:inline-block;height:0;` + + `overflow:hidden;position:absolute;top:0;visibility:hidden;white-space:nowrap;` + + `font-family:${ style.fontFamily };font-size:${ style.fontSize };` + + `padding:${ style.padding }`; + ghost.textContent = input.value; + document.body.appendChild(ghost); + input.style.width = ghost.offsetWidth + 4 + + (input.getAttribute("type") === "number" ? 20 : 0) + "px"; + document.body.removeChild(ghost); + } + + input.style.minWidth = "30px"; + input.style.maxWidth = "90%"; + input.addEventListener(`input`, () => updateInput()); + updateInput(); + + return input; + + }); + } \ No newline at end of file diff --git a/src/static/js/source/index.js b/src/static/js/source/index.js new file mode 100644 index 0000000..c830fa0 --- /dev/null +++ b/src/static/js/source/index.js @@ -0,0 +1,49 @@ +import { httpGet } from "../utils"; + +let settings = { + +}; + +export function getOption (opt) { + return settings[opt]; +} + +export function init () { + + bind([ + "settings.host", + "settings.port", + "settings.domain", + "settings.queryType", + "settings.seed", + "settings.webAppName" + ]); + +} + +export function getData (callback) { + let https = (settings["host"] || "").indexOf("https://") === 0; + httpGet(`${ settings["host"] }${ + settings["port"] === (https ? 443 : 80) ? "" : ":" + settings["port"] + }/${ settings["webAppName"] }/domain/${ encodeURIComponent(settings["domain"]) }/${ + encodeURIComponent(settings["queryType"]) + }/${ + encodeURIComponent(settings["seed"]) + }`, callback); +} + +function bind (elements) { + elements.forEach(e => { + setValue(document.getElementById(e)).addEventListener(`change`, setValue) + }); +} + +function setValue (e = {}) { + let id, el = e instanceof HTMLElement ? e : (e.target || e.srcElement); + if (!el) + return e; + if ((id = el.getAttribute(`id`)).indexOf(`settings.`) === 0) { + settings[id.replace(/^settings\./, ``)] = el.value; + } + return e; +} \ No newline at end of file diff --git a/src/static/js/utils.js b/src/static/js/utils.js new file mode 100644 index 0000000..eddd861 --- /dev/null +++ b/src/static/js/utils.js @@ -0,0 +1,91 @@ +/** + * @see https://github.com/ZitRos/domUtils + * @author ZitRo + * @licence MIT + * Creates an element. + * @param {string} element - Tag Name + * @param {string|object} [className] - CSS class name + * @param {string} [textContent] - Optional content + * @param {Array} [children] - Optional array of children, which are attached to the block. + * @returns {Element} + */ +export function block (element = "div", className, textContent, children) { + + let el = document.createElement(element || "div"), + c = children || []; + + if (className instanceof Array) { + c = className; + } else if (typeof className === "string") { + el.className = className; + } else if (typeof className === "object") { + if (className.style) el.setAttribute("style", className.style); + if (className.class) el.className = className.class; + if (className.textContent) el.textContent = className.textContent; + if (typeof className["onClick"] === "function") + el.addEventListener("click", className["onClick"]); + } + + if (textContent instanceof Array) { + c = textContent; + } else if (typeof textContent === "string") + el.textContent = textContent; + + c.forEach(a => { if (a) el.appendChild(a) }); + + return el; +} + +let loader = block(`div`, { + class: `central loading`, + style: `position:fixed` +}, [ + block(`div`, [ + block(`div`, [ + block(`div`, `loader`, [ + block(`div`, `inner one`), + block(`div`, `inner two`), + block(`div`, `inner three`) + ]) + ]) + ]) +]); + +/** + * @param {string} theUrl + * @param {function} callback + */ +export function httpGet (theUrl, callback) { + let xmlHttp = new XMLHttpRequest(); + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState === 4) { + let data; + if (xmlHttp.status !== 200) { + callback({ error: `Request to ${ theUrl } returned status ${ xmlHttp.status }` }); + return; + } + try { + data = JSON.parse(xmlHttp.responseText); + } catch (e) { + console.error(e, xmlHttp.responseText); + callback({ error: e }); + return; + } + callback(data); + } + }; + xmlHttp.open("GET", theUrl, true); + xmlHttp.send(null); +} + +/** + * Show the loader over the page. + * @param {boolean} [on] + */ +export function toggleLoader (on = true) { + if (on) { + document.body.appendChild(loader); + } else if (loader && loader.parentNode) { + loader.parentNode.removeChild(loader); + } +} \ No newline at end of file diff --git a/src/static/scss/basic.scss b/src/static/scss/basic.scss index e01c2cf..9e5096b 100644 --- a/src/static/scss/basic.scss +++ b/src/static/scss/basic.scss @@ -1,4 +1,5 @@ @import "const"; +@import "mixins"; table { @@ -27,6 +28,112 @@ table { } +input[type=text], input[type=number] { + border: 0; + border-bottom: gray; +} + +.central { + + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + display: table; + + > div { + + display: table-cell; + vertical-align: middle; + text-align: center; + + > div { + display: inline-block; + } + + } + +} + h1, h2, h3, h4, h5, h6 { margin: 0 0 .3em 0; +} + +.loading { + + background: rgba(255, 255, 255, 0.8); + z-index: $zIndexOnTop + 1; + + .loader { + + position: fixed; + top: calc(50% - 32px); + left: calc(50% - 32px); + width: 64px; + height: 64px; + border-radius: 50%; + perspective: 800px; + + > .inner { + + position: absolute; + box-sizing: border-box; + width: 100%; + height: 100%; + border-radius: 50%; + box-shadow: 0 0 3px $colorA; + + &.one { + left: 0; + top: 0; + animation: rotate-one 1s linear infinite; + border-bottom: 3px solid $colorB; + } + + &.two { + right: 0; + top: 0; + animation: rotate-two 1s linear infinite; + border-right: 3px solid $colorC; + } + + &.three { + right: 0; + bottom: 0; + animation: rotate-three 1s linear infinite; + border-top: 3px solid $colorA; + } + + } + + } + +} + +@include keyframes(rotate-one) { + 0% { + transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg); + } + 100% { + transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg); + } +} + +@include keyframes(rotate-two) { + 0% { + transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg); + } + 100% { + transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg); + } +} + +@include keyframes(rotate-three) { + 0% { + transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg); + } + 100% { + transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg); + } } \ No newline at end of file diff --git a/src/static/scss/const.scss b/src/static/scss/const.scss index 28a869f..947434c 100644 --- a/src/static/scss/const.scss +++ b/src/static/scss/const.scss @@ -3,5 +3,8 @@ $defaultPadding: 10px; $defaultShadow: 0 0 2px gray; $colorA: #02ad8b; +$colorB: #e08f00; +$colorC: #4c79c1; -$zIndexInterface: 100; \ No newline at end of file +$zIndexInterface: 100; +$zIndexOnTop: 200; \ No newline at end of file