]> granicus.if.org Git - graphviz/commitdiff
reworked id mechanis for maps, svg
authorellson <devnull@localhost>
Sat, 20 Sep 2008 20:32:27 +0000 (20:32 +0000)
committerellson <devnull@localhost>
Sat, 20 Sep 2008 20:32:27 +0000 (20:32 +0000)
doc/infosrc/attrs
doc/infosrc/output.2
lib/common/emit.c
plugin/core/gvrender_core_svg.c

index 769f641a15fb333df4fa67a4029910a25fe529e1..610ac3edefc05b965d56a24277acb6c8008eec3c 100644 (file)
@@ -353,6 +353,12 @@ contain the label. Note also that, if the output format is dot, the
 value given to <B>height</B> will be the final value.
 :href:E:lblString:"";  map,ps,svg
 Synonym for <A HREF=#d:URL>URL</A>.
+: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,
index 6b75e0d11f4917d974f7cb3afdd00a59774400e3..7d99512a0048c13dd704b707bbe54dcb1de21baf 100644 (file)
@@ -4,10 +4,7 @@
 <OL TYPE="1">
 <LI>
 <A NAME=ID>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.
 </OL>
index 161e2c133cf6bd3c99ca289d8340e2d83c3e286f..3c49fbc9008d5ff387dccaa22d5e8f6dbc3ef099 100644 (file)
@@ -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;
index dfb835fc8c9f331f5c6c307f87505aa8b66e7b56..3e5d1abfe919ed72a63161d40f297221e16341aa 100644 (file)
@@ -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, "<g id=\"graph%d\" class=\"graph\"", job->common->viewNum);
+    gvprintf(job, "<g id=\"%s\" class=\"graph\"", obj->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, "<g id=\"cluster%ld\" class=\"cluster\">",
-           obj->u.sg->meta_node->id);
+    gvprintf(job, "<g id=\"%s\" class=\"cluster\">", obj->id);
     gvputs(job, "<title>");
     gvputs(job, xml_string(obj->u.sg->name));
     gvputs(job, "</title>\n");
@@ -248,7 +247,7 @@ static void svg_begin_node(GVJ_t * job)
 {
     obj_state_t *obj = job->obj;
 
-    gvprintf(job, "<g id=\"node%ld\" class=\"node\">", obj->u.n->id);
+    gvprintf(job, "<g id=\"%s\" class=\"node\">", obj->id);
     gvputs(job, "<title>");
     gvputs(job, xml_string(obj->u.n->name));
     gvputs(job, "</title>\n");
@@ -265,7 +264,7 @@ svg_begin_edge(GVJ_t * job)
     obj_state_t *obj = job->obj;
     char *edgeop;
 
-    gvprintf(job, "<g id=\"edge%ld\" class=\"edge\">", obj->u.e->id);
+    gvprintf(job, "<g id=\"%s\" class=\"edge\">", obj->id);
     if (obj->u.e->tail->graph->root->kind & AGFLAG_DIRECTED)
        edgeop = "&#45;&gt;";
     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])