Skip to content

Commit

Permalink
Basic D3 based graph viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
thvitt committed Jul 10, 2020
1 parent e951194 commit bed3ff4
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 27 deletions.
51 changes: 27 additions & 24 deletions src/graphviewer/graphviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ class NoNodes(ValueError):


def prepare_agraph():
node_str = request.args.get('nodes')
node_str = request.values.get('nodes')
nodes, errors = info.nodes(node_str, report_errors=True)
if errors:
flash('Die folgenden zentralen Knoten wurden nicht gefunden: ' + ', '.join(errors), 'warning')
context = request.args.get('context', False)
abs_dates = request.args.get('abs_dates', False)
extra, errors = info.nodes(request.args.get('extra', ''), report_errors=True)
context = request.values.get('context', False)
abs_dates = request.values.get('abs_dates', False)
extra, errors = info.nodes(request.values.get('extra', ''), report_errors=True)
if errors:
flash('Die folgenden Pfadziele wurden nicht gefunden: ' + ', '.join(errors), 'warning')
induced_edges = request.args.get('induced_edges', False)
ignored_edges = request.args.get('ignored_edges', False)
direct_assertions = request.args.get('assertions', False)
paths_wo_timeline = request.args.get('paths_wo_timeline', False)
no_edge_labels = request.args.get('no_edge_labels', False)
tred = request.args.get('tred', False)
nohl = request.args.get('nohl', False)
induced_edges = request.values.get('induced_edges', False)
ignored_edges = request.values.get('ignored_edges', False)
direct_assertions = request.values.get('assertions', False)
paths_wo_timeline = request.values.get('paths_wo_timeline', False)
no_edge_labels = request.values.get('no_edge_labels', False)
tred = request.values.get('tred', False)
nohl = request.values.get('nohl', False)
if nodes:
g = info.subgraph(*nodes, context=context, abs_dates=abs_dates, paths=extra, keep_timeline=True,
paths_without_timeline=paths_wo_timeline,
Expand Down Expand Up @@ -76,14 +76,14 @@ def _normalize_args(args):

@app.route('/macrogenesis/subgraph')
def render_form():
try:
agraph = prepare_agraph()
output = subprocess.check_output(['dot', '-T', 'svg'], input=codecs.encode(agraph.to_string()), timeout=30)
svg = Markup(codecs.decode(output))
except NoNodes:
flash(Markup('<strong>Keine Knoten im Graphen.</strong> Bitte mindestens einen Knoten im Feld <em>Zentrale Knoten</em> eingeben.'), 'danger')
svg = ''
return render_template('form.html', svg=svg, query=codecs.decode(request.query_string), **_normalize_args(request.args))
# try:
# agraph = prepare_agraph()
# output = subprocess.check_output(['dot', '-T', 'svg'], input=codecs.encode(agraph.to_string()), timeout=30)
# svg = Markup(codecs.decode(output))
# except NoNodes:
# flash(Markup('<strong>Keine Knoten im Graphen.</strong> Bitte mindestens einen Knoten im Feld <em>Zentrale Knoten</em> eingeben.'), 'danger')
# svg = ''
return render_template('form.html', query=codecs.decode(request.query_string), **_normalize_args(request.args))


@app.route('/macrogenesis/subgraph/pdf')
Expand All @@ -96,12 +96,15 @@ def render_pdf():
return response


@app.route('/macrogenesis/subgraph/dot')
@app.route('/macrogenesis/subgraph/dot', methods=['GET', 'POST'])
def render_dot():
agraph = prepare_agraph()
response = Response(agraph.to_string(), mimetype='text/vnd.graphviz')
response.headers['Content-Disposition'] = f'attachment; filename="{agraph.graph_attr["basename"]}.dot"'
return response
try:
agraph = prepare_agraph()
response = Response(agraph.to_string(), mimetype='text/vnd.graphviz')
response.headers['Content-Disposition'] = f'attachment; filename="{agraph.graph_attr["basename"]}.dot"'
return response
except NoNodes as e:
return Response(Markup('<strong>Keine Knoten im Graphen.</strong> Bitte mindestens einen Knoten im Feld <em>Zentrale Knoten</em> eingeben.'), status=404)

@app.route('/macrogenesis/subgraph/svg')
def render_svg():
Expand Down
7 changes: 7 additions & 0 deletions src/graphviewer/templates/faustedition.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
<meta charset='utf-8'>
<title>Faustedition{% block title %}{% endblock %}</title>


<script type="application/javascript" 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>

<script type="text/javascript" src="/js/require.js"></script>
<script type="text/javascript" src="/js/faust_config.js"></script>

Expand Down Expand Up @@ -190,6 +195,8 @@ <h3><i class="fa fa-code" aria-hidden="true"></i> XML-Quellen</h3>
</script>


{% block d3script %}
{% endblock %}

<script>
requirejs(['jquery', 'jquery.chocolat', 'jquery.overlays', 'jquery.clipboard', 'faust_common', 'js.cookie'],
Expand Down
41 changes: 38 additions & 3 deletions src/graphviewer/templates/form.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
{% extends "faustedition.html" %}
{% block content %}

{{ svg }}
{% block d3script %}
<script type="application/javascript">
async function getDotStr() {
const form = document.getElementById('subgraph-form'),
formdata = new FormData(form);
console.log(new URLSearchParams(formdata).toString());
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 transitionFactory = () => d3.transition().duration(750);
const updateGraph = function updateGraph() {
getDotStr().then(dot => {
graphviz.transition(transitionFactory).renderDot(dot);
}).catch(reason => console.error(reason));
}
d3.selectAll('#subgraph-form input[type=checkbox]').on("click", updateGraph);
d3.selectAll('#subgraph-form input[type=text]').on("blur", 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 */
};
nonEmptyField.addEventListener("input", checkInput);
checkInput();
}
contentRequired('#subgraph-form', 'nodes');
</script>
{% endblock %}

{% block content %}

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

<form method="get" class="pure-g-r pure-form">
<form id="subgraph-form" method="get" class="pure-g-r pure-form">
<section class="pure-u-1-3">
<h3>Zentrale Knoten
<small class="pull-right"><label><input type="checkbox" name="nohl" id="nohl" {% if nohl %}checked{% endif %}> nicht hervorheben</label></small>
Expand Down

0 comments on commit bed3ff4

Please sign in to comment.