Skip to content

Commit

Permalink
Graphviewer: Major layout update
Browse files Browse the repository at this point in the history
  • Loading branch information
thvitt committed Jul 22, 2020
1 parent 0b16fce commit 728c466
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 42 deletions.
15 changes: 14 additions & 1 deletion src/graphviewer/graphviewer.py
Expand Up @@ -139,4 +139,17 @@ def render_svg():

@app.route('/macrogenesis/subgraph/help')
def render_help():
return render_template('help.html')
return render_template('help.html')


@app.route('/macrogenesis/subgraph/check-nodes')
def check_nodes():
node_str = request.values.get('nodes')
model = request.values.get('model', 'default')
info = models.get(model, default_model)
nodes, errors = info.nodes(node_str, report_errors=True)
return jsonify(dict(
normalized=', '.join(map(str, nodes)),
not_found=errors,
error_msg="Unbekannte Knoten ignoriert: " + ', '.join(errors) if errors else ''
))
3 changes: 2 additions & 1 deletion src/graphviewer/templates/faustedition.html
Expand Up @@ -5,7 +5,7 @@
<title>Faustedition{% block title %}{% endblock %}</title>


<script type="application/javascript" src="/js/wasm/index.min.js"></script>
<script type="javascript/worker" src="/js/wasm/index.min.js"></script>
<script type="application/javascript" src="/js/d3.min.js"></script>
<script type="application/javascript" src="/js/d3-graphviz.min.js"></script>

Expand Down Expand Up @@ -38,6 +38,7 @@
<div id="current" class="pure-nowrap"></div>
<nav id="nav_all" class="pure-menu pure-menu-open pure-menu-horizontal pure-right pure-nowrap pure-noprint">
<ul>
<li class="pure-alert pure-alert-info pure-invisible" id="header-status">Lade ...</li>
<li><a href="{% block helpurl %}/help{% endblock %}" title="Hilfe"><i class="fa fa-help-circled fa-lg"></i></a></li>
<li><a href="#quotation" title="Zitieremfehlung"><i class="fa fa-bookmark fa-lg"></i></a></li>
<li><a href="#download" title="Download"><i class="fa fa-download fa-lg"></i></a></li>
Expand Down
172 changes: 132 additions & 40 deletions src/graphviewer/templates/form.html
@@ -1,5 +1,47 @@
{% extends "faustedition.html" %}

{% block head %}
<style>
main {
display: flex;
justify-items: center;
flex-direction: column;
width: 100%;
height: calc(100vh - 3.4em);
}
main.vertical {
flex-direction: row;
}
#subgraph-form {
flex-grow: 0;
}
.flex-form {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.flex-form fieldset, .flex-form section {
padding: 0 1em;
flex-grow: 1;
}
#refgraph {
text-align: center;
flex-grow: 1;
overflow: auto;
}
button, input, select, textarea {
vertical-align: middle;
}
footer { display: none; }

#header-status {
padding: 5px;
margin-bottom: 0;
}
</style>
{% endblock %}

{% block d3script %}
<script type="application/javascript">

Expand All @@ -11,44 +53,86 @@
location.search = searchString;
history.replaceState(null, '', location)

const downloadArea = document.getElementById('download-graph');
for (const a of downloadArea.getElementsByTagName("a")) {
a.search = searchString;
try {
const downloadArea = document.getElementById('download-graph');
for (const a of downloadArea.getElementsByTagName("a")) {
a.search = searchString;
}
} catch (e) {
console.warn(e);
}
}
}

function message(msg, severity, long) {
const headerElement = document.getElementById('header-status'),
longMessage = document.getElementById('long-message'),
updating = long? longMessage: headerElement,
other = long? headerElement: longMessage;
if (msg) {
if (!severity)
severity = "info";
updating.innerHTML = msg;
updating.className = "pure-alert pure-alert-" + severity
updating.style.visibility = "visible";
other.style.visibility = "hidden";
} else {
updating.style.visibility = "hidden";
other.style.visibility = "hidden";
}
}

async function getDotStr() {
const form = document.getElementById('subgraph-form'),
updating = document.getElementById('updating'),
formdata = new FormData(form);
updating.style.visibility = "visible";
updateURLs(formdata);
const response = await fetch('subgraph/dot', {method: "POST", body: formdata});
if (response.status === 200)
return await response.text();
else
throw await response.text();
}
const graphviz = d3.select('#refgraph').graphviz();
const graphviz = d3.select('#refgraph').graphviz({fit: false}),
statusMessages = {
start: "Parse Graphdatei",
layoutStart: "Berechne Graphlayout",
renderStart: "Rendere",
transitionStart: "Überblende neuen Graph",
end: ""
};
for (const eventType in statusMessages) {
graphviz.on(eventType, () => message(statusMessages[eventType], 'info'));
}

const transitionFactory = () => d3.transition().duration(750);
const updateGraph = function updateGraph() {
getDotStr().then(dot => {
message("Lade aktualisierten Graphen …")
getDotStr().then(dot => {message("Berechne neues Layout …"); return dot;})
.then(dot => {
graphviz.transition(transitionFactory).renderDot(dot);
}).catch(reason => console.error(reason))
.finally(() => updating.style.visibility = "hidden");
})
//.then(() => message())
.catch(reason => {
message(reason, "danger", true)
console.error(reason)
})
}
d3.selectAll('#subgraph-form input[type=checkbox]').on("click", updateGraph);
d3.selectAll('#subgraph-form input[type=checkbox], #subgraph-form input[type=radio]').on("click", updateGraph);
d3.selectAll('#subgraph-form select').on("input", updateGraph);
d3.selectAll('#subgraph-form input[type=text]').on("blur", updateGraph)
document.addEventListener("keypress", function (event) {
if (event.key === "Enter")
updateGraph();
});
updateGraph();

function contentRequired(formSelector, nonEmptyFieldName) {
const form = document.querySelector(formSelector),
nonEmptyField = form.elements[nonEmptyFieldName],
submitButton = form.querySelector('input[type=submit]'),
checkInput = function() {
submitButton.disabled = !nonEmptyField.value; /* ← äußere Variablen */
if (submitButton)
submitButton.disabled = !nonEmptyField.value; /* ← äußere Variablen */
};
nonEmptyField.addEventListener("input", checkInput);
checkInput();
Expand All @@ -59,52 +143,60 @@

{% block content %}

<p class="pure-alert pure-alert-warning pure-invisible" id="long-message">
Berechne aktualisierten Graphen …
</p>

<div id="refgraph"></div>

<form id="subgraph-form" method="get" class="pure-g-r pure-form">
<section class="pure-u-1-3">
<h3>Zentrale Knoten
<form id="subgraph-form" method="get" class="flex-form pure-form">
<fieldset>
<legend>Zentrale Knoten
<small class="pull-right"><label><input type="checkbox" name="nohl" id="nohl" {% if nohl %}checked{% endif %}> nicht hervorheben</label></small>
</h3>
<p><input type="text" name="nodes" id="nodes" value="{{ nodes }}" style="width: 100%;" placeholder="2 V H.13"></p>
</legend>
<p><input type="text" name="nodes" id="nodes" value="{{ nodes }}" style="width: 100%;" placeholder="2 V H.13">
</p>
<p><input type="checkbox" name="context" id="context" {% if context %}checked{% endif %}> <label for="context">Nachbarknoten</label></p>
<p><input type="checkbox" name="assertions" id="assertions" {% if assertions %}checked{% endif %} <label for="assertions">unmittelbare Aussagen über Kernknoten</label> </p>
<!--p><input type="submit" class="pure-button pure-button-primary" value="Teilgraph zeichnen"></p-->
<p><label for="model">Modell: </label>
<select id="model" name="model" value="{{ model }}">
{% for model_name in models %}
<option value="{{ model_name }}">{{ model_name }}</option>
{% endfor %}
</select>
</p>
<p><label for="dir">Richtung: </label>
<select id="dir" name="dir" value="{{ direction }}">
<option value="LR"></option>
<option value="TB"></option>
<option value="RL"></option>
<option value="BT"></option>
</select></p>
</section>
<section class="pure-u-1-3">
<h3>Zusätzliche Pfade</h3>
{% if models|length > 1 %}
<p>
<label for="model">Modell: </label>
<select id="model" name="model" value="{{ model }}">
{% for model_name in models %}
<option value="{{ model_name }}">{{ model_name }}</option>
{% endfor %}
</select>
</p>
{% endif %}
</fieldset>
<fieldset>
<legend>Zusätzliche Pfade</legend>
<p><input type="checkbox" name="abs_dates" id="abs_dates" {% if abs_dates %}checked{% endif %}> <label for="abs_dates">absolute Datierungen rechtfertigen</label></p>
<p><label for="extra">Pfade von/zu (falls verfügbar): </label><br/>
<input type="text" name="extra" id="extra" value="{{ extra }}" placeholder="A, 2 H" style="width: 100%"><br />
<input type="checkbox" name="paths_wo_timeline" id="paths_wo_timeline" {% if paths_wo_timeline %}checked{% endif %}> <label for="paths_wo_timeline">ohne Timeline</label>
</p>
<p class="pure-alert pure-alert-warning pure-invisible" id="updating">
Berechne aktualisierten Graphen …
</p>
</section>
<section class="pure-u-1-3">
<h3>Kantenauswahl und -gestaltung:</h3>
</fieldset>
<fieldset>
<legend>Kantenauswahl</legend>
<p><input type="checkbox" name="induced_edges" id="induced_edges" {% if induced_edges %}checked{% endif %}> <label for="induced_edges">alle induzierten Kanten</label></p>
<p><input type="checkbox" name="ignored_edges" id="ignored_edges" {% if ignored_edges %}checked{% endif %}> <label for="ignored_edges">ignorierte (graue) Kanten</label> </p>
<p><input type="checkbox" name="syn" id="syn" {% if syn %}checked{% endif %}> <label for="syn">Kanten für »ungefähr gleichzeitig«</label> </p>
<p><input type="checkbox" name="tred" id="tred" {% if tred %}checked{% endif %}> <label for="tred">Transitive Reduktion</label> </p>
</fieldset>
<fieldset>
<legend>Graphlayout</legend>
<p><input type="checkbox" name="no_edge_labels" id="no_edge_labels" {% if no_edge_labels %}checked{% endif %}> <label for="no_edge_labels">keine Kantenbeschriftung</label> </p>
<p><input type="checkbox" name="collapse" id="collapse" {% if collapse %}checked{% endif %}> <label for="collapse">Parallelkanten zusammenfassen</label> </p>
<p><input type="checkbox" name="order" id="order" {% if order %}checked{% endif %}> <label for="order">Topologische Sortierung</label></p>
<p style="vertical-align: middle">
Richtung:
<input id="dir-lr" name="dir" type="radio" value="LR" checked> <label for="dir-lr"></label>
<input id="dir-tb" name="dir" type="radio" value="TB"> <label for="dir-tb"></label>
<input id="dir-rl" name="dir" type="radio" value="RL"> <label for="dir-rl"></label>
<input id="dir-bt" name="dir" type="radio" value="BT"> <label for="dir-bt"></label>
</p>
</fieldset>
</form>

{% endblock %}
Expand Down

0 comments on commit 728c466

Please sign in to comment.