From: ellson Date: Sat, 20 Sep 2008 20:32:27 +0000 (+0000) Subject: reworked id mechanis for maps, svg X-Git-Tag: LAST_LIBGRAPH~32^2~3358 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=918ae94bb38b482d226f20af66e062b15336f9dc;p=graphviz reworked id mechanis for maps, svg --- diff --git a/doc/infosrc/attrs b/doc/infosrc/attrs index 769f641a1..610ac3ede 100644 --- a/doc/infosrc/attrs +++ b/doc/infosrc/attrs @@ -353,6 +353,12 @@ contain the label. Note also that, if the output format is dot, the value given to height will be the final value. :href:E:lblString:""; map,ps,svg Synonym for URL. +:id:GNE:lblString:""; map,ps,svg +Allows the graph author to provide an id for graph objects which is to be included in the output. +If no id is provided, then the internal id is used in the outputs, however this value is unpredictable by the graph writer. +An externally provided id is not used internally. +If provided, it is the reponsiblity of the provider to keep +its values sufficiently unique for its intended downstream use. :image:N:string:""; Gives the name of a file containing an image to be displayed inside a node. The image file must be in one of the recognized formats, diff --git a/doc/infosrc/output.2 b/doc/infosrc/output.2 index 6b75e0d11..7d99512a0 100644 --- a/doc/infosrc/output.2 +++ b/doc/infosrc/output.2 @@ -4,10 +4,7 @@
  1. In the formats: -Tcmap, -Tcmapx, -Tsvg, -Tvml, the output generates -'id="\\N"' properties for nodes and html-cells, 'id="\\E"' properties for edges, and 'id="\\G"' properties for clusters. Then it applies the usual "\\X" substitutions on these strings. - -The 'id="xxx"' property is intended to be a predictable string that uniquely identifies the graph object. This 'id' can be used from Javascript, for example. - -At the moment the edge id doesn't distinguish between multiedges in -non-strict graphs. +'id="node#"' properties for nodes, 'id="edge#"' properties for edges, and 'id="cluster#"' properties for clusters, with the '#' replaced by an internally assigned integer. These strings can be provided instead by an "id=xxx" attribute on the object. +Externally provided id values are not used internally, but it is the users reponsibilty to ensure +that they are sufficiently unique for any downstream use.
diff --git a/lib/common/emit.c b/lib/common/emit.c index 161e2c133..3c49fbc90 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -105,7 +105,7 @@ initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target, char if ((flags & GVRENDER_DOES_LABELS) && lbl) obj->label = lbl; if (flags & GVRENDER_DOES_MAPS) { - obj->id = strdup_and_subst_obj(id, gobj); + obj->id = strdup(id); if (url && url[0]) { obj->url = strdup_and_subst_obj(url, gobj); assigned = 1; @@ -130,31 +130,24 @@ initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target, char } static void -initGraphMapData (GVJ_t* job, textlabel_t *lab, void* gobj) +initObjMapData (GVJ_t* job, textlabel_t *lab, char *otyp, long int idnum, void* gobj) { char* lbl; char* url = agget(gobj, "href"); char* tooltip = agget(gobj, "tooltip"); char* target = agget(gobj, "target"); + char* id = agget(gobj, "id"); + char buf[50]; if (lab) lbl = lab->text; else lbl = NULL; - if (!url || !*url) url = agget(gobj, "URL"); - initMapData (job, lbl, url, tooltip, target, "\\G", gobj); -} - -static void -initNodeMapData (GVJ_t* job, textlabel_t *lab, void* gobj) -{ - char* lbl; - char* url = agget(gobj, "href"); - char* tooltip = agget(gobj, "tooltip"); - char* target = agget(gobj, "target"); - - if (lab) lbl = lab->text; - else lbl = NULL; - if (!url || !*url) url = agget(gobj, "URL"); - initMapData (job, lbl, url, tooltip, target, "\\N", gobj); + if (!url || !*url) /* try URL as an alias for href */ + url = agget(gobj, "URL"); + if (!id || !*id) { /* no external id, so use the internal one */ + sprintf(buf, "%s%ld", otyp, idnum); + id = buf; + } + initMapData (job, lbl, url, tooltip, target, id, gobj); } static void map_point(GVJ_t *job, pointf pf) @@ -1069,7 +1062,7 @@ static void emit_begin_node(GVJ_t * job, node_t * n) else obj->z = 0.0; } - initNodeMapData (job, ND_label(n), n); + initObjMapData (job, ND_label(n), "node", n->id, n); if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) && (obj->url || obj->explicit_tooltip)) { @@ -1521,7 +1514,7 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles) { obj_state_t *obj; int flags = job->flags; - char *s; + char *s, buf[50]; textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL; pointf *pbs = NULL; int i, nump, *pbs_n = NULL, pbs_poly_n = 0; @@ -1566,7 +1559,12 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles) } if (flags & GVRENDER_DOES_MAPS) { - obj->id = strdup_and_subst_obj("\\E", (void*)e); + s = agget(e, "id"); + if (!s || !*s) { /* no external id, so use the internal one */ + sprintf(buf,"edge%d", e->id); + s = buf; + } + obj->id = strdup(s); if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0])) dflt_url = strdup_and_subst_obj(s, (void*)e); if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0])) @@ -2214,7 +2212,7 @@ static void emit_begin_graph(GVJ_t * job, graph_t * g) obj->u.g = g; obj->emit_state = EMIT_GDRAW; - initGraphMapData (job, GD_label(g), g); + initObjMapData (job, GD_label(g), "graph", job->common->viewNum, g); #ifdef WITH_CODEGENS Obj = NONE; @@ -2420,7 +2418,7 @@ static void emit_begin_cluster(GVJ_t * job, Agraph_t * sg) obj->u.sg = sg; obj->emit_state = EMIT_CDRAW; - initGraphMapData (job, GD_label(sg), sg); + initObjMapData (job, GD_label(sg), "cluster", sg->meta_node->id, sg); #ifdef WITH_CODEGENS Obj = CLST; diff --git a/plugin/core/gvrender_core_svg.c b/plugin/core/gvrender_core_svg.c index dfb835fc8..3e5d1abfe 100644 --- a/plugin/core/gvrender_core_svg.c +++ b/plugin/core/gvrender_core_svg.c @@ -211,7 +211,7 @@ static void svg_begin_page(GVJ_t * job) /* its really just a page of the graph, but its still a graph, * and it is the entire graph if we're not currently paging */ - gvprintf(job, "common->viewNum); + gvprintf(job, "id); gvprintf(job, " transform=\"scale(%g %g) rotate(%d) translate(%g %g)\">\n", job->scale.x, job->scale.y, -job->rotation, job->translation.x, -job->translation.y); @@ -232,8 +232,7 @@ static void svg_begin_cluster(GVJ_t * job) { obj_state_t *obj = job->obj; - gvprintf(job, "", - obj->u.sg->meta_node->id); + gvprintf(job, "", obj->id); gvputs(job, ""); gvputs(job, xml_string(obj->u.sg->name)); gvputs(job, "\n"); @@ -248,7 +247,7 @@ static void svg_begin_node(GVJ_t * job) { obj_state_t *obj = job->obj; - gvprintf(job, "", obj->u.n->id); + gvprintf(job, "", obj->id); gvputs(job, ""); gvputs(job, xml_string(obj->u.n->name)); gvputs(job, "\n"); @@ -265,7 +264,7 @@ svg_begin_edge(GVJ_t * job) obj_state_t *obj = job->obj; char *edgeop; - gvprintf(job, "", obj->u.e->id); + gvprintf(job, "", obj->id); if (obj->u.e->tail->graph->root->kind & AGFLAG_DIRECTED) edgeop = "->"; else @@ -291,8 +290,12 @@ svg_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id) assert (id && id[0]); /* there should always be an id available */ if (href && href[0]) gvprintf(job, " xlink:href=\"%s\"", xml_url_string(href)); +#if 0 + /* linking to itself, jut so that it can have a link in the anchor, seems wrong. + * it changes the behavior in browsers, the link apears in the bottinm information bar */ else gvprintf(job, " xlink:href=\"#%s\"", xml_url_string(id)); +#endif if (tooltip && tooltip[0]) gvprintf(job, " xlink:title=\"%s\"", xml_string(tooltip)); if (target && target[0])