Commit 69b4ba19 authored by Themousaillon's avatar Themousaillon

Merge branch 'maximilian/newGraph' into nicolas/feature

adding new feature frontend support into my branch
parents 76a3327c 79a23698
import { Graph2d } from "./2d-graphosaurus/graph";
import IdSet from "../misc/customTypes/IdSet";
export class Graph2D {
......@@ -14,8 +13,18 @@ export class Graph2D {
this.graph2d = new Graph2d(dbConnector, idList, cullList);
this.cy = null;
this.nodes = [];
this.expandedNodes = new IdSet();
setInterval(() => console.log(this.graph2d), 5000)
this.showClearMenu = true;
this.boxSelection = false;
}
toIso = (dateValue) => {
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
let [day, month, year] = dateValue.innerHTML.split(" ")
month = months.findIndex(x => x === month)
let date = new Date(year, month, day)
date.setFullYear(year)
return date
}
showGraph2D = () => {
......@@ -26,7 +35,6 @@ export class Graph2D {
container: document.getElementById('cy'),
wheelSensitivity: 0.1,
autounselectify: true,
style: [
{
selector: 'node',
......@@ -37,12 +45,12 @@ export class Graph2D {
'background-color': 'data(color)',
'text-background-color': 'white',
'text-background-opacity': 1,
'text-background-padding': '1px',
'text-background-padding': '5px',
'text-border-opacity': 1,
'text-border-color': 'white',
'text-border-width': '1px',
'text-border-style': 'solid',
'text-margin-y': '-2px'
'text-margin-y': '-6px'
}
},
{
......@@ -73,14 +81,28 @@ export class Graph2D {
layout.run();
this.filterByDate([document.getElementById('filter-date-start'), document.getElementById('filter-date-end')]);
this.filterGraph();
this.applyFilterToGraph();
this.cy.elements().nodes().on('cxttap', (e) => this.displayContextMenu(e));
this.cy.elements().nodes().on('mouseover', (e) => this.highlightNode(e));
this.cy.elements().nodes().on('mouseout', (e) => this.deEmphasizeNode(e));
this.cy.on('cxttap', this.displayGraphMenu);
this.cy.on('cxttap', 'node', this.displayContextMenu);
this.cy.on('mouseover', 'node', this.highlightNode);
this.cy.on('mouseout', 'node', this.deEmphasizeNode);
this.cy.on('boxselect', 'node', this.selectNode);
this.cy.on('boxend', () => this.boxSelection = true);
this.cy.on('tap', this.unselectNodes);
}
selectNode = (e) => {
const nodeId = e.target._private.data.id;
this.cy.getElementById(nodeId).style('backgroundColor', 'Navy');
}
this.cy.on('tapstart', this.hideContextMenu);
unselectNodes = () => {
this.cy.nodes().map(node => node.style('backgroundColor', node._private.data.color));
this.boxSelection = false;
}
showTooltip = () => {
......@@ -92,8 +114,12 @@ export class Graph2D {
highlightNode = (e) => {
this.selectedNodeId = parseInt(e.target._private.data.id);
this.selectedNodeColor = e.target._private.data.color;
let selectedNode = this.cy.getElementById(this.selectedNodeId);
this.cy.getElementById(this.selectedNodeId).style("backgroundColor", "yellow");
this.hoverTimeout = setTimeout(() => this.graph2d.notNeighbors([this.selectedNodeId]).map(id => this.cy.getElementById(id).style("opacity", "0.2")), 2000);
this.hoverTimeout = setTimeout(() => {
this.cy.elements().map(element => element.style("opacity", "0.2"));
selectedNode.closedNeighborhood().map(element => element.style("opacity", "1"));
}, 2000);
const associatedSearchRows = [...document.getElementsByTagName("tr")].filter(row => {
if ("data-id" in row.attributes) {
return parseInt(row.attributes["data-id"].value) === this.selectedNodeId;
......@@ -102,6 +128,8 @@ export class Graph2D {
});
associatedSearchRows.map(row => row.getElementsByTagName("td")[0].style.backgroundColor = "rgb(255, 255, 70)");
this.showTooltip();
this.showClearMenu = false;
}
hideTooltip = () => {
......@@ -112,9 +140,15 @@ export class Graph2D {
deEmphasizeNode = (e) => {
let highlightedNode = this.cy.getElementById(this.selectedNodeId);
highlightedNode.style("backgroundColor", this.selectedNodeColor);
if (highlightedNode.selected() && this.boxSelection) {
highlightedNode.style("backgroundColor", "Navy");
}
else {
highlightedNode.style("backgroundColor", this.selectedNodeColor);
highlightedNode.unselect();
}
clearTimeout(this.hoverTimeout);
this.cy.nodes().map(node => node.style("opacity", "1"));
this.cy.elements().map(element => element.style("opacity", "1"));
const associatedSearchRows = [...document.getElementsByTagName("tr")].filter(row => {
if ("data-id" in row.attributes) {
return parseInt(row.attributes["data-id"].value) === this.selectedNodeId;
......@@ -123,18 +157,30 @@ export class Graph2D {
});
associatedSearchRows.map(row => row.getElementsByTagName("td")[0].style.backgroundColor = this.selectedNodeColor + "aa");
this.hideTooltip();
this.showClearMenu = true;
}
deleteNode = () => {
this.hideContextMenu();
this.graph2d.removeComponents([this.selectedNodeId])((type, id) => {
if (type === "node") {
this.cy.remove('node[id = \'' + id + '\']')
}
});
this.graph2d.mutate().then(() => this.hideContextMenu());
}
displayNewElements = (type, element) => {
postProc = filterFn => node => {
if (filterFn(node)) {
return true;
}
else {
node.hide = true;
return false;
}
}
displayNewElements = postProc => (type, element) => {
if (this.cy.getElementById(element.id).length === 0) {
if (type === "node") {
const cX = this.cy.getElementById(this.selectedNodeId)._private.position.x;
......@@ -143,11 +189,12 @@ export class Graph2D {
this.cy.add({
group: 'nodes',
data: element,
position: { x: cX + 200 * Math.cos(a), y: cY + 200 * Math.sin(a) }
})
.on('cxttap', (e) => this.displayContextMenu(e))
.on('mouseover', (e) => this.highlightNode(e))
.on('mouseout', (e) => this.deEmphasizeNode(e));
position: { x: cX + 200 * Math.cos(a), y: cY + 200 * Math.sin(a) },
style:
{
display: postProc(element) ? 'element' : 'none'
}
});
} else {
this.cy.add({
group: 'edges',
......@@ -159,10 +206,13 @@ export class Graph2D {
expandNodes = (id, nodeType='all', relationType="all") => {
this.hideContextMenu();
this.graph2d.getRelated([id], nodeType, relationType)(this.displayNewElements);
this.graph2d.mutate().then(() => {
this.applyFilterToGraph();
});
const keywords = $("#filter-content").val().split(" ");
const startDate = this.toIso(document.getElementById('filter-date-start'));
const endDate = this.toIso(document.getElementById('filter-date-end'));
const filterFn = this.graph2d._filters.filterAllByNode(keywords, startDate, endDate);
this.graph2d.getRelated([id], nodeType, relationType)(this.displayNewElements(this.postProc(filterFn)));
this.graph2d.mutate();
}
collapseNodes = (id, nodeType='all', relationType="all") => {
......@@ -201,6 +251,8 @@ export class Graph2D {
}
displayContextMenu = (e) => {
$("#cytoRightClickOverlay").show();
let d = document.getElementById("contextMenu");
d.style.position = "absolute";
d.style.left = e.renderedPosition.x + 'px';
......@@ -215,11 +267,48 @@ export class Graph2D {
const nodeSummary = this.graph2d.getNodeSummary(this.selectedNodeId);
this.getContextSubMenu("Expand", nodeSummary, this.expandNodes, extraInfo);
this.getContextSubMenu("Collapse", nodeSummary, this.collapseNodes, extraInfo);
if (e.target._private.data.data.url) {
const url = e.target._private.data.data.url;
let newDiv = document.createElement("div");
newDiv.className = "menuItem";
newDiv.innerHTML = "<i class='fa fa-fw'></i>Inspect";
newDiv.addEventListener('click', () => window.open("http://www.regesta-imperii.de/id/" + url, "_blank"));
extraInfo.appendChild(newDiv);
}
}
clearGraph = () => {
this.graph2d = new Graph2d(this.dbConnector, [], []);
this.hideGraphMenu();
this.addNodeIds([]);
}
hideGraphMenu = () => {
let d = document.getElementById("graph2DMenu");
d.style.display = 'none';
$("#cytoRightClickOverlay").hide();
}
displayGraphMenu = (e) => {
if (this.showClearMenu) {
$("#cytoRightClickOverlay").show();
let d = document.getElementById("graph2DMenu");
d.style.position = "absolute";
d.style.left = e.renderedPosition.x + 'px';
d.style.top = e.renderedPosition.y + 'px';
d.style.display = 'inline-block';
document.getElementById("clear2DGraph").addEventListener("click", this.clearGraph);
}
}
hideContextMenu = () => {
let d = document.getElementById("contextMenu");
d.style.display = 'none';
$("#cytoRightClickOverlay").hide();
}
addNodeIds = (nodeIds) => {
......@@ -235,9 +324,10 @@ export class Graph2D {
this.graph2d.forEachCurrentNode(node => this.cy.getElementById(node.id).style("display", node.hide ? "none": "element"));
}
filterByDate = (dateValues) => {
const [startDate, endDate] = dateValues;
this.graph2d.filter([], startDate, endDate);
this.applyFilterToGraph();
filterGraph = () => {
const keywords = $("#filter-content").val().split(" ");
const startDate = this.toIso(document.getElementById('filter-date-start'));
const endDate = this.toIso(document.getElementById('filter-date-end'));
this.graph2d.filter(keywords, startDate, endDate);
}
}
\ No newline at end of file
......@@ -370,6 +370,14 @@ intergraph .tooltip-arrow {
border: 1px solid black;
background-color: white;
display: none;
z-index: 3;
}
#graph2DMenu {
border: 1px solid black;
background-color: white;
display: none;
z-index: 3;
}
#nodeId {
......@@ -393,11 +401,21 @@ intergraph .tooltip-arrow {
#load-autocompletion {
position: absolute;
left: 0;
display: flex;
display: none;
height: 100vh;
width: 100%;
align-items: center;
justify-content: center;
z-index: 3;
background-color: rgba(127, 127, 127, 0.5);
}
#cytoRightClickOverlay {
display: none;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 2;
}
\ No newline at end of file
......@@ -80,7 +80,8 @@ function setupDateFilter(app, newGraph, id, start, end) {
dateValues[handle].innerHTML = values[handle];
app.updateFilter();
newGraph.filterByDate(dateValues.map(toIso));
newGraph.filterGraph();
newGraph.applyFilterToGraph();
});
}
......@@ -88,10 +89,11 @@ function setupDateFilter(app, newGraph, id, start, end) {
function start(settings, login, password) {
let url = settings.database.url;
let dbConnector = new dbConnectorConstructor(settings, url, login, password);
document.getElementById("load-autocompletion").style.display = "flex";
const entrySearch = new EntrySearch(dbConnector, () => {
document.getElementById("load-autocompletion").style.visibility = "hidden";
document.getElementById("load-autocompletion").style.display = "none";
$('#keyword').focus();
})
});
dbConnector.test().then(result => {
if (!result) {
......@@ -239,9 +241,18 @@ function start(settings, login, password) {
$('#generate-btn').show();
$('#addToGraphButton').hide();
$('#contextMenu').hide();
$('#graph2DMenu').hide();
}
});
$('#graphselector #cytocanvas').trigger("click"); // To set cytocanvas as default canvas
$('#cytoRightClickOverlay').click(() => {
$('#contextMenu').hide();
$('#graph2DMenu').hide();
$('#cytoRightClickOverlay').hide();
});
$( "#queryButton" ).click(query);
$( "#keyword" ).keypress(function(e) {
if(e.which == 13) {
......@@ -418,8 +429,8 @@ function start(settings, login, password) {
$("#filter-content").on("input", () => {
const keywords = $("#filter-content").val().split(" ")
graph2D.graph2d.filterByKeywords(keywords)
graph2D.applyFilterToGraph()
graph2D.filterGraph();
graph2D.applyFilterToGraph();
})
return app;
}
......
......@@ -75,8 +75,8 @@
<button type="button" class="btn" id="toggle-right-panel-canvas"><i class="fa fa-chevron-left" aria-hidden="true"></i></button>
<div id="topButtons">
<div id="graphselector" class="btn-group btn-group-toggle">
<button type="button" id="threecanvas" class="btn active">Threecanvas</button>
<button type="button" id="cytocanvas" class="btn">Cytocanvas</button>
<button type="button" id="cytocanvas" class="btn active">Cytocanvas</button>
<button type="button" id="threecanvas" class="btn">Threecanvas</button>
</div>
<div id="generate-btn-container" hidden>
<button id="generate-btn" class="btn btn-primary" disabled>Generate graph</button>
......@@ -104,6 +104,10 @@
<div id="extraInfo"></div>
<div class="menuItem" id="deleteNode"><i class="fa fa-trash fa-fw"></i>Remove node</div>
</div>
<div id="graph2DMenu" oncontextmenu="return false">
<div><i class="fa fa-fw"></i><b>Canvas</b></div>
<div class="menuItem" id="clear2DGraph"><i class="fa fa-fw"></i>Clear Canvas</div>
</div>
</div>
<div id="filters">
<table>
......@@ -148,6 +152,7 @@
</div>
</div>
</div>
<div id="cytoRightClickOverlay" oncontextmenu="return false"></div>
<div class="hidden" style="display: none;">
<span id="info" style="display: none"></span>
<span id="type" style="display: none"></span>
......
module.exports = { version: '126' }
module.exports = { version: '196' }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment