• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[FRAGE] d3.js Graph als Navigation: Hyperlinks einfügen, wie geht das?

Tinkerism

New member
Ich bin leider ein völliger JS-Anfänger, aber dies hier muss doch leicht zu machen sein, ob mit d3.js oder etwas anderem:

Hier ist ein Beispiel eines Graphs mit Knoten (nodes)
Graph with labeled edges.

Code:
<script type="text/javascript">

    var w = 1000;
    var h = 600;
    var linkDistance=200;

    var colors = d3.scale.category10();

    var dataset = {

    nodes: [
    {name: "Adam"},
    {name: "Bob"},
    {name: "Carrie"},
    {name: "Donovan"},
    {name: "Edward"},
    {name: "Felicity"},
    {name: "George"},
    {name: "Hannah"},
    {name: "Iris"},
    {name: "Jerry"}
    ],
    edges: [
    {source: 0, target: 1},
    {source: 0, target: 2},
    {source: 0, target: 3},
    {source: 0, target: 4},
    {source: 1, target: 5},
    {source: 2, target: 5},
    {source: 2, target: 5},
    {source: 3, target: 4},
    {source: 5, target: 8},
    {source: 5, target: 9},
    {source: 6, target: 7},
    {source: 7, target: 8},
    {source: 8, target: 9}
    ]
    };

 
    var svg = d3.select("body").append("svg").attr({"width":w,"height":h});

    var force = d3.layout.force()
        .nodes(dataset.nodes)
        .links(dataset.edges)
        .size([w,h])
        .linkDistance([linkDistance])
        .charge([-500])
        .theta(0.1)
        .gravity(0.05)
        .start();

 

    var edges = svg.selectAll("line")
      .data(dataset.edges)
      .enter()
      .append("line")
      .attr("id",function(d,i) {return 'edge'+i})
      .attr('marker-end','url(#arrowhead)')
      .style("stroke","#ccc")
      .style("pointer-events", "none");
    
    var nodes = svg.selectAll("circle")
      .data(dataset.nodes)
      .enter()
      .append("circle")
      .attr({"r":15})
      .style("fill",function(d,i){return colors(i);})
      .call(force.drag)


    var nodelabels = svg.selectAll(".nodelabel") 
       .data(dataset.nodes)
       .enter()
       .append("text")
       .attr({"x":function(d){return d.x;},
              "y":function(d){return d.y;},
              "class":"nodelabel",
              "stroke":"black"})
       .text(function(d){return d.name;});

    var edgepaths = svg.selectAll(".edgepath")
        .data(dataset.edges)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'fill-opacity':0,
               'stroke-opacity':0,
               'fill':'blue',
               'stroke':'red',
               'id':function(d,i) {return 'edgepath'+i}})
        .style("pointer-events", "none");

    var edgelabels = svg.selectAll(".edgelabel")
        .data(dataset.edges)
        .enter()
        .append('text')
        .style("pointer-events", "none")
        .attr({'class':'edgelabel',
               'id':function(d,i){return 'edgelabel'+i},
               'dx':80,
               'dy':0,
               'font-size':10,
               'fill':'#aaa'});

    edgelabels.append('textPath')
        .attr('xlink:href',function(d,i) {return '#edgepath'+i})
        .style("pointer-events", "none")
        .text(function(d,i){return 'label '+i});


    svg.append('defs').append('marker')
        .attr({'id':'arrowhead',
               'viewBox':'-0 -5 10 10',
               'refX':25,
               'refY':0,
               //'markerUnits':'strokeWidth',
               'orient':'auto',
               'markerWidth':10,
               'markerHeight':10,
               'xoverflow':'visible'})
        .append('svg:path')
            .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
            .attr('fill', '#ccc')
            .attr('stroke','#ccc');
     

    force.on("tick", function(){

        edges.attr({"x1": function(d){return d.source.x;},
                    "y1": function(d){return d.source.y;},
                    "x2": function(d){return d.target.x;},
                    "y2": function(d){return d.target.y;}
        });

        nodes.attr({"cx":function(d){return d.x;},
                    "cy":function(d){return d.y;}
        });

        nodelabels.attr("x", function(d) { return d.x; }) 
                  .attr("y", function(d) { return d.y; });

        edgepaths.attr('d', function(d) { var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
                                           //console.log(d)
                                           return path});       

        edgelabels.attr('transform',function(d,i){
            if (d.target.x<d.source.x){
                bbox = this.getBBox();
                rx = bbox.x+bbox.width/2;
                ry = bbox.y+bbox.height/2;
                return 'rotate(180 '+rx+' '+ry+')';
                }
            else {
                return 'rotate(0)';
                }
        });
    });

</script>

All die "labeled edges", die Pfeile, die Animation interessieren mich nicht. Ich möchte nur an den Knoten zu verschiedenen Seiten der Website verknüpfen, und dann noch, dass die Grafik sich responsiv verhält.

Es handelt sich um ein Netzwerk von Künstlern, auf deren einzelne Seiten jeweils verlinkt werden soll. Der Bildanhang zeigt, wie es aussehen soll.
Netzwerk.gif

Bin dankbar für jeden Tip!
 
Zuletzt bearbeitet:
Hallo Tinkerism
Das verlinken is nicht so schlimm das ganze responsive zu halten schon ziemlich.
hier eine Funktion für die Links.
du musst in setLinks.labs die url anpassen und die namen in den nodelabels müssen identisch mit denen im setLink.labs sein :)
und die Funktion am ende des scripts einfügen.

PHP:
function setLinks(){
var lnk = document.querySelectorAll('svg .nodelabel');
var i = 0;
while(i < lnk.length){
lnk[i].addEventListener('click',getHref,true);
lnk[i++].style.cursor = "pointer";
}}
setLinks.labs = 
{
	"Adam":"http://irgendwo/by-adam.html",
	"Bob":"http://irgendwo/by-bob.html",
	"Carrie":"http://irgendwo/by-carrie.html",
	"Donovan":"http://irgendwo/by-donovan.html",
	"Edward":"http://irgendwo/by-edward.html",
	"Felicity":"http://irgendwo/by-felicity.html",
	"George":"http://irgendwo/by-georg.html",
	"Hannah":"http://irgendwo/by-hannah.html",
	"Iris":"http://irgendwo/by-iris.html",
	"Jerry":"http://irgendwo/by-jerry.html"
}
    


function getHref(){
window.location.href = setLinks.labs[this.textContent];
}

setLinks();
MFG
 
Ich komme gerade zurück, und werde mir das Ganze mal angucken... Vorerst danke! Und bis später!

- - - Aktualisiert - - -

Im code steht

Code:
   var w = 1000;
    var h = 600;

Kann man das auch in Prozent ausdrücken? Dann hätte man es responsiv...

- - - Aktualisiert - - -

Wow, es hat geklappt, 1000 Dank!

Jetzt noch ein paar Fragen zum Feinschliff, wenn ich darf. Ich habe jetzt allen überflüssigen Code rausgeschmissen, so weit ich konnte, und so sieht er jetzt aus:

Code:
    var w = 1000;
    var h = 600;
    var linkDistance=300;

    var colors = d3.scale.category10();

    var dataset = {

    nodes: [
    {name: "AB"},
    {name: "KH"},
    {name: "SW"},
    {name: "KQ"},
    {name: "ER"},
    {name: "TS"},
    {name: "M/J"},
    {name: "ASH"},
    {name: "PG"},
    {name: "CS"}
    ],
    edges: [
    {source: 0, target: 1},
    {source: 0, target: 2},
    {source: 0, target: 3},
    {source: 0, target: 4},
    {source: 1, target: 5},
    {source: 2, target: 5},
    {source: 2, target: 5},
    {source: 3, target: 4},
    {source: 5, target: 8},
    {source: 5, target: 9},
    {source: 6, target: 7},
    {source: 7, target: 8},
    {source: 8, target: 9}
    ]
    };

    var svg = d3.select("body").append("svg").attr({"width":w,"height":h});

    var force = d3.layout.force()
        .nodes(dataset.nodes)
        .links(dataset.edges)
        .size([w,h])
        .linkDistance([linkDistance])
        .charge([-500])
        .start();

    var edges = svg.selectAll("line")
      .data(dataset.edges)
      .enter()
      .append("line")
      .style("stroke","#649865");
    
    var nodes = svg.selectAll("circle")
      .data(dataset.nodes)
      .enter()
      .append("circle")
      .attr({"r":30})
      .style("fill",function(d,i){return colors(i);})


    var nodelabels = svg.selectAll(".nodelabel") 
       .data(dataset.nodes)
       .enter()
       .append("text")
       .attr({"x":function(d){return d.x;},
              "y":function(d){return d.y;},
              "class":"nodelabel"})
       .text(function(d){return d.name;});

    var edgepaths = svg.selectAll(".edgepath")
        .data(dataset.edges)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'stroke-opacity':0});

    force.on("tick", function(){

        edges.attr({"x1": function(d){return d.source.x;},
                    "y1": function(d){return d.source.y;},
                    "x2": function(d){return d.target.x;},
                    "y2": function(d){return d.target.y;}
        });

        nodes.attr({"cx":function(d){return d.x;},
                    "cy":function(d){return d.y;}
        });

        nodelabels.attr("x", function(d) { return d.x; }) 
                  .attr("y", function(d) { return d.y; });

    });


function setLinks(){ 
var lnk = document.querySelectorAll('svg .nodelabel'); 
var i = 0; 
while(i < lnk.length){ 
lnk[i].addEventListener('click',getHref,true); 
lnk[i++].style.cursor = "default"; 
}} 
setLinks.labs =  
{ 
    "AB":"http://irgendwo/by-adam.html", 
    "KH":"http://irgendwo/by-bob.html", 
    "SW":"http://irgendwo/by-carrie.html", 
    "KQ":"http://irgendwo/by-donovan.html", 
    "ER":"http://irgendwo/by-edward.html", 
    "TS":"http://irgendwo/by-felicity.html", 
    "M/J":"http://irgendwo/by-georg.html", 
    "ASH":"http://irgendwo/by-hannah.html", 
    "PG":"http://irgendwo/by-iris.html", 
    "CS":"http://irgendwo/by-jerry.html" 
} 
     
function getHref(){ 
window.location.href = setLinks.labs[this.textContent]; 
} 

setLinks();  

</script>

Ich habe es geschafft, die Schriftart und -größe der Links zu verändern mit .nodelabel { font-family: 'Andale Mono'; font-size: 1.2em;}

Was mir nicht gelingt, ist die Schriftfarbe in Weiß zu verwandeln. Außerdem möchte ich die Beschriftung in die Mitte der Nodes setzen. Im Augenblick befindet sich die gedachte linke untere Ecke im Zentrum der Nodes. Wie muss ich das die x/y-Achse setzen?

Dann etwas, aus dem ich auch bei Durchsicht der d3-Dokumentation nicht rausgefunden habe: wie ersetze ich
Code:
var colors = d3.scale.category10();
(ganz oben im Code), so dass nur eine Farbe angezeigt wird?

Ich hoffe, das ist nicht zu viel gefragt.
 
Wow, danke! Es hat geklappt!

So sieht mein Code jetzt aus:

Code:
    var w = 1200;
    var h = 600;
    var linkDistance=300;

    var dataset = {

    nodes: [
    {name: "AB"},
    {name: "KH"},
    {name: "SW"},
    {name: "KQ"},
    {name: "ER"},
    {name: "TS"},
    {name: "M/J"},
    {name: "ASH"},
    {name: "PG"},
    {name: "CS"}
    ],
    edges: [
    {source: 0, target: 1},
    {source: 0, target: 2},
    {source: 0, target: 3},
    {source: 0, target: 4},
    {source: 1, target: 5},
    {source: 2, target: 5},
    {source: 2, target: 5},
    {source: 3, target: 4},
    {source: 5, target: 8},
    {source: 5, target: 9},
    {source: 6, target: 7},
    {source: 7, target: 8},
    {source: 8, target: 9}
    ]
    };

    var svg = d3.select("body").append("svg").attr({"width":w,"height":h});

    var force = d3.layout.force()
        .nodes(dataset.nodes)
        .links(dataset.edges)
        .size([w,h])
        .linkDistance([linkDistance])
        .charge([-500])
        .start();

    var edges = svg.selectAll("line")
      .data(dataset.edges)
      .enter()
      .append("line")
      .style("stroke","#649865");
    
    var nodes = svg.selectAll("circle")
      .data(dataset.nodes)
      .enter()
      .append("circle")
      .attr({"r":30})
      .style("fill","#649865")


    var nodelabels = svg.selectAll(".nodelabel") 
       .data(dataset.nodes)
       .enter()
       .append("text")
       .attr({"x":function(d){return d.x-10;},
              "y":function(d){return d.y-10;},
              "class":"nodelabel"})
        .style("fill","#ffffff")
       .text(function(d){return d.name;});

    var edgepaths = svg.selectAll(".edgepath")
        .data(dataset.edges)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'stroke-opacity':0});

    force.on("tick", function(){

        edges.attr({"x1": function(d){return d.source.x;},
                    "y1": function(d){return d.source.y;},
                    "x2": function(d){return d.target.x;},
                    "y2": function(d){return d.target.y;}
        });

        nodes.attr({"cx":function(d){return d.x;},
                    "cy":function(d){return d.y;}
        });

        nodelabels.attr("x", function(d) { return d.x; }) 
                  .attr("y", function(d) { return d.y; });

    });


function setLinks(){ 
var lnk = document.querySelectorAll('svg .nodelabel'); 
var i = 0; 
while(i < lnk.length){ 
lnk[i].addEventListener('click',getHref,true); 
lnk[i++].style.cursor = "crosshair"; 
}} 
setLinks.labs =  
{ 
    "AB":"http://irgendwo/by-adam.html", 
    "KH":"http://irgendwo/by-bob.html", 
    "SW":"http://irgendwo/by-carrie.html", 
    "KQ":"http://irgendwo/by-donovan.html", 
    "ER":"http://irgendwo/by-edward.html", 
    "TS":"http://irgendwo/by-felicity.html", 
    "M/J":"http://irgendwo/by-georg.html", 
    "ASH":"http://irgendwo/by-hannah.html", 
    "PG":"http://irgendwo/by-iris.html", 
    "CS":"http://irgendwo/by-jerry.html" 
} 
     


function getHref(){ 
window.location.href = setLinks.labs[this.textContent]; 
} 

setLinks();

WAs jetzt noch toll wäre, wenn die Mitte der Schrift auch wirklich in der Mitte der Nodes wäre. Ich nehme an, das geht mit Anpassung an sie x/y-Achse. Aber ich habe keine Ahnung, wie man das macht.

PS: Ich hatte hier etwas gepostet, aber es ist verschwunden, warum auch immer...
 
Zuletzt bearbeitet:
WAs jetzt noch toll wäre, wenn die Mitte der Schrift auch wirklich in der Mitte der Nodes wäre. Ich nehme an, das geht mit Anpassung an sie x/y-Achse. Aber ich habe keine Ahnung, wie man das macht.
Habe nun nach gründlicher Recherche eine d3.js Methode für die Links und den Text gefunden.

Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Force Layout with labels on edges</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
circle text{color:red!important;}
</style>
</head>
<body>

<script type="text/javascript">

    var w = 1200;
    var h = 600;
    var linkDistance=300;

    var dataset = {

    nodes: [
    {name: "AB", link:"http:irgendwo/im/nirgendwo/123.html"},
    {name: "KH", link:"http:irgendwo/im/nirgendwo/1234.html"},
    {name: "SW", link:"http:irgendwo/im/nirgendwo/12345.html"},
    {name: "KQ", link:"http:irgendwo/im/nirgendwo/12346.html"},
    {name: "ER", link:"http:irgendwo/im/nirgendwo/12347.html"},
    {name: "TS", link:"http:irgendwo/im/nirgendwo/12348.html"},
    {name: "M/J", link:"http:irgendwo/im/nirgendwo/12349.html"},
    {name: "ASH", link:"http:irgendwo/im/nirgendwo/12340.html"},
    {name: "PG", link:"http:irgendwo/im/nirgendwo/12341.html"},
    {name: "CS", link:"http:irgendwo/im/nirgendwo/12342.html"}
    ],
    edges: [
    {source: 0, target: 1},
    {source: 0, target: 2},
    {source: 0, target: 3},
    {source: 0, target: 4},
    {source: 1, target: 5},
    {source: 2, target: 5},
    {source: 2, target: 5},
    {source: 3, target: 4},
    {source: 5, target: 8},
    {source: 5, target: 9},
    {source: 6, target: 7},
    {source: 7, target: 8},
    {source: 8, target: 9}
    ]
    };

    var svg = d3.select("body").append("svg").attr({"width":w,"height":h});

    var force = d3.layout.force()
        .nodes(dataset.nodes)
        .links(dataset.edges)
        .size([w,h])
        .linkDistance([linkDistance])
        .charge([-500])
        .start();

    var edges = svg.selectAll("line")
      .data(dataset.edges)
      .enter()
      .append("line")
      .style("stroke","#649865");
    
    var nodes = svg.selectAll("circle")
      .data(dataset.nodes)
      .enter()
      .append("circle")
	  .attr({"r":30})
      .style("fill","#649865")
	  

 
    var nodelabels = svg.selectAll(".nodelabel") 
       .data(dataset.nodes)
	   .enter()
       .append("a")
	   .attr("xlink:href",function(d){return d.link;})
       .attr({"class":"nodelabel"})
	   .append('text')
	   .attr("text-anchor", "middle")
       .style("fill","#fff")
	   .text(function(d){return d.name;})

    var edgepaths = svg.selectAll(".edgepath")
        .data(dataset.edges)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'stroke-opacity':1});

    force.on("tick", function(){

        edges.attr({"x1": function(d){return d.source.x;},
                    "y1": function(d){return d.source.y;},
                    "x2": function(d){return d.target.x;},
                    "y2": function(d){return d.target.y;}
        });

        nodes.attr({"cx":function(d){return d.x;},
                    "cy":function(d){return d.y;}
        });

        nodelabels.attr("x", function(d) { return d.x; }) 
                  .attr("y", function(d) { return d.y+6.0; });

    });





</script>

</body>
</html>

D3.js Tips and Tricks: Attributes in d3.js
bl.ocks.org/d3noob
 
Zuletzt bearbeitet von einem Moderator:
@tinkersim
du solltest die letzte version verwenden so
kannst du auf die setLinks Funktion verzichten
und mußt auch die Pfade nicht 2x anpassen.
Vor allem aber werden echte a tags eingef0gt
MFG
 
Zurück
Oben