From c24f3ddc05cb310b31a6af0f57519f7652252f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 30 Jun 2015 14:27:48 +0200 Subject: [PATCH] admin: style workflow graph with colours (#7708) --- wcs/admin/workflows.py | 65 +++++++++++++++++++++++++++---------- wcs/qommon/static/css/dc2/admin.css | 19 ++++------- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/wcs/admin/workflows.py b/wcs/admin/workflows.py index 30ee073..4505c86 100644 --- a/wcs/admin/workflows.py +++ b/wcs/admin/workflows.py @@ -59,30 +59,30 @@ def remove_attribute(node, att): del node.attrib[att] -def remove_style(node, top): +def remove_style(node, top, colours, white_text=False): remove_tag(node, TITLE) if node.get('fill') == 'white' and node.get('stroke') == 'white': # this is the general white background, wipe it to be transparent node.attrib['fill'] = 'transparent' node.attrib['stroke'] = 'transparent' + if node.tag == svg('text') and white_text: + node.attrib['fill'] = 'white' for child in node: remove_attribute(child, XLINK_TITLE) - style = child.get('style', None) - # Beware ! HACK ! salmon is matched and converted to class="page-subject" - if style: - m = re.search('(?:stroke|fill):salmon', style) - if m: - top.set('class', top.get('class','') + ' page-subject') - if child.get('fill') == 'salmon': - top.set('class', top.get('class', '') + ' page-subject') + if child.get('fill') in colours: + matching_hexa = colours.get(child.get('fill')) + child.attrib['fill'] = '#' + matching_hexa + del child.attrib['stroke'] + if misc.get_foreground_colour(matching_hexa) == 'white': + white_text = True if child.get('font-family'): del child.attrib['font-family'] if child.get('font-size'): child.attrib['font-size'] = str(float(child.attrib['font-size'])*0.8) remove_attribute(child, 'style') - remove_style(child, top) + remove_style(child, top, colours, white_text=white_text) -def graphviz_post_treatment(content): +def graphviz_post_treatment(content, colours): ''' Remove all svg:title and top-level svg:polygon nodes, remove style attributes and xlink:title attributes. @@ -90,17 +90,44 @@ def graphviz_post_treatment(content): part on as class selector on the top level svg:g element. ''' tree = ET.fromstring(content) + style = ET.SubElement(tree, svg('style')) + style.attrib['type'] = 'text/css' + css_url = '%s%s%s' % (get_publisher().get_root_url(), + get_publisher().qommon_static_dir, + get_publisher().qommon_admin_css) + style.text = '@import url(%s);' % css_url for root in tree: remove_tag(root, TITLE) # remove_tag(root, POLYGON) for child in root: - remove_style(child, child) + remove_style(child, child, colours) return ET.tostring(tree) def graphviz(workflow, url_prefix='', select=None, svg=True, include=False): out = StringIO() + # a list of colours known to graphviz, they will serve as key to get back + # to the colours defined in wcs. + graphviz_colours = [ + 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', + 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', + 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', + 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', + 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', + 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', + 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', + 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', + 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', + 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', + 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green', + 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', + 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', + 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', + 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', ] + + colours = {} + revert_colours = {} print >>out, 'digraph main {' # print >>out, 'graph [ rankdir=LR ];' print >>out, 'node [shape=box,style=filled];' @@ -110,13 +137,18 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, print >>out, 'status%s' % i, print >>out, '[label="%s"' % status.name, if select == str(i): - print >>out, ',color=salmon' + print >>out, ',id=current_status' + if status.colour: + if status.colour not in colours: + colours[status.colour] = graphviz_colours.pop() + revert_colours[colours[status.colour]] = status.colour + print >>out, ',color=%s' % colours[status.colour] print >>out, ' URL="%sstatus/%s/"];' % (url_prefix, i) for status in workflow.possible_status: i = status.id for item in status.items: - next_status_ids = [x.id for x in item.get_target_status()] + next_status_ids = [x.id for x in item.get_target_status() if x.id != status.id] if not next_status_ids: next_status_ids = [status.id] for next_id in next_status_ids: @@ -135,9 +167,8 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, label = label.encode('utf8') label = label.replace('\n', '\\n') print >>out, '[label="%s"' % label, - if select == '%s-%s' % (i, item.id): - print >>out, ',color=salmon' print >>out, ',URL="%s%s"]' % (url_prefix, url) + print >>out, '}' out = out.getvalue() if svg: @@ -146,8 +177,8 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, out, err = process.communicate(out) except OSError: return '' + out = graphviz_post_treatment(out, revert_colours) if include: - out = graphviz_post_treatment(out) # It seems webkit refuse to accept SVG when using its proper namespace, # and xlink namespace prefix must be xlink: to be acceptable out = out.replace('ns0:', '') diff --git a/wcs/qommon/static/css/dc2/admin.css b/wcs/qommon/static/css/dc2/admin.css index 089b81b..3e4df9d 100644 --- a/wcs/qommon/static/css/dc2/admin.css +++ b/wcs/qommon/static/css/dc2/admin.css @@ -720,21 +720,23 @@ svg { width: 100%; height: 100%; margin: auto; + font-family: sans-serif; } svg .node polygon { - stroke:black; - fill:#EEE; + stroke: #444; + stroke-width: 1px; } svg .node path { - fill:none; + fill: none; stroke: black; } svg .edge path { fill:none; stroke: black; + stroke: #666; } svg .edge polygon { stroke: black; @@ -745,15 +747,8 @@ svg .edge text { svg .edge text { font-size: 60%; } -svg .page-subject.edge text { - fill: #91a9b2; -} -svg .page-subject polygon { - fill: #91a9b2; - stroke: #91a9b2; -} -svg .page-subject path { - stroke: #91a9b2; +svg #current_status polygon { + stroke-width: 2px; } .foldable { -- 2.1.4