C'est ma version etape4 de conceptMap Version reprise de Gregory. J'ai juste changer quelques valeurs et tenté de rendre plus jolie. J'ai rajouté le zoom et le drag, c plsu pratique et on peut ensuite agrandir les elements de la visualisation.(fait avec https://bl.ocks.org/mbostock/6123708) J'ai changé quelques couleurs, mais dans l'ensemble je n'ai pas touché à la structure du code. j'ai rajouté une ligne dans Highlight et UnHighlight
xxxxxxxxxx
<head>
<meta charset="utf-8">
<meta name="name" content="Concept Map" />
<meta name="description" content="An abstract mapping for parameters. Works best if first tag is 'unique' among the tracklist, and the second tag applies to multiple tracks"/>
<meta name="mintags" content="2" />
<meta name="maxtags" content="2" />
<title>A qui appartiennent les médias?</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-rc1/jquery.min.js"></script>
<style>
html{
color:#fff;
}
svg {
font: 12px sans-serif;
}
text {
pointer-events: none;
font-color:#FFFFFF;
}
.inner_node rect {
pointer-events: all;
}
.inner_node rect.highlight {
stroke: #315B7E;
stroke-width: 2px;
}
.outer_node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
pointer-events: all;
}
.outer_node circle.highlight
{
stroke: #315B7E;
stroke-width: 2px;
}
.link {
fill: none;
}
body{
background: #2E2E2E;
}
/*
body {
background: url(https://www.liguedefensejuive.com/wp-content/uploads/2015/04/2629835-3711215.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
*/
</style>
</head>
<body>
<h2>Qui possède quoi dans les média? avec drag and zoom</h2>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
$(function(){
//
// Generated by the Exaile Playlist Analyzer plugin.
// (C) 2014 Dustin Spicuzza <dustin@virtualroadside.com>
//
// This work is licensed under the Creative Commons Attribution 4.0
// International License. To view a copy of this license, visit
// https://creativecommons.org/licenses/by/4.0/.
//
// Inspired by https://www.findtheconversation.com/concept-map/
// Loosely based on https://bl.ocks.org/mbostock/4063550
//
// RELATIONS of links
// possesseur/entreprise/personne sur groupe
var POSSESSEUR_GROUPE = 0;
// possesseur/entreprise/personne sur media
var POSSESSEUR_MEDIA = 1;
// GROUPE sur GROUPE
var GROUPE_GROUPE = 2;
// GROUPE sur MEDIA
var GROUPE_MEDIA = 3;
// TYPES OF NODES
var POSSESSOR = 0;
var GROUP = 1;
var MEDIA = 2;
var nodes = [];
var links = [];
var data = [];
var datacsv;
var treeData=[];
var datajsonArray = [];
function validName(name){
return name.indexOf("%") == -1 && name !="";
}
function Node(id,name, type) {
this.id = id;
this.name = name;
this.type = type;
};
function getMedias(){
return nodes.filter(function(e){return e.type==MEDIA});
}
function getGroups(){
return nodes.filter(function(e){return e.type==GROUP});
}
function getPossessors(){
return nodes.filter(function(e){return e.type==POSSESSOR});
}
function getId(name){
for(var i in nodes){
if(nodes[i].name == name){
return nodes[i].id;
}
}
return -1;
}
function Link(id, source, target,value,niveau,relation) {
this.id=id;
this.source = source ;
this.target = target ;
this.niveau = niveau ;
this.value = value ;
this.relation = relation ;
};
function get_links(source,relation){
return links.filter(function(d){return d.source ==source && d.relation ==relation});
}
function get_links_byRelation(relation){
return links.filter(function(d){return d.relation ==relation});
}
function add_node(name,type){
if(!validName(name)){
return;
}
for(var node in nodes){
if(nodes[node].name == name){
return;
}
}
nodes.push(new Node(nodes.length,name,type));
}
function add_link(source,target,niveau,value,participe,relation){
for(var link in links){
if(link.source == source && link.target == target){
return;
}
}
links.push(new Link(links.length,source,target,niveau,value,participe,relation));
}
d3.dsv(';')("basemedia.csv", function(error, csv) {
if (error) return console.warn(error);
datacsv = csv;
for (var prop in datacsv) {
var ligne =datacsv[prop];
var node1 = ligne["Proprietaire final NOM"];
add_node(ligne["Proprietaire final NOM"],POSSESSOR);
add_node(ligne["3e etage NOM"],GROUP);
add_node(ligne["2e etage NOM"],GROUP);
add_node(ligne["1er etage NOM"],GROUP);
add_node(ligne["Media NOM"],MEDIA);
var premier = false;
var deuxieme = false;
var troisieme = false;
if(validName(ligne["3e etage NOM"])){
troisieme = true;
var value = ligne["Proprietaire final %"];
var source = ligne["Proprietaire final NOM"];
var target = ligne["3e etage NOM"];
add_link(source,target,value,0,POSSESSEUR_GROUPE);
}
if(validName(ligne["2e etage NOM"])){
deuxieme= true;
// possesseur vers groupe n°2
var value = Math.max(ligne["Proprietaire final %"],ligne["3e etage %"]);
var source = ligne["Proprietaire final NOM"];
var target = ligne["2e etage NOM"];
add_link(source,target,value,1,POSSESSEUR_GROUPE);// mettre de niveau 0 si il y a rien eu avant ?
// groupe 3 vers groupe 2
if(troisieme){
var value = ligne["3e etage %"];
var source = ligne["3e etage NOM"];
var target = ligne["2e etage NOM"];
add_link(source,target,value,0,GROUPE_GROUPE);
}
}
if(validName(ligne["1er etage NOM"])){
var value = ligne["2e etage %"];
premier= true;
// possesseur vers groupe n°1
var value = Math.max(ligne["Proprietaire final %"],ligne["3e etage %"],ligne["2e etage %"]);
var source = ligne["Proprietaire final NOM"];
var target = ligne["1er etage NOM"];
add_link(source,target,value,2,POSSESSEUR_GROUPE);// mettre de niveau 0 si il y a rien eu avant ?
// groupe 3 vers groupe 1
if(troisieme){
var value = Math.max(ligne["3e etage %"],ligne["2e etage %"]);
var source = ligne["3e etage NOM"];
var target = ligne["1er etage NOM"];
add_link(source,target,value,1,GROUPE_GROUPE);
}
// groupe 3 vers groupe 1
if(deuxieme){
var value = ligne["2e etage %"];
var source = ligne["2e etage NOM"];
var target = ligne["1er etage NOM"];
add_link(source,target,value,0,GROUPE_GROUPE);
}
}
// on passe au media
// possesseur => media
var value = Math.max(ligne["Proprietaire final %"],ligne["3e etage %"],ligne["2e etage %"],ligne["1er etage %"]);
var source = ligne["Proprietaire final NOM"];
var target = ligne["Media NOM"];
add_link(source,target,value,3,POSSESSEUR_MEDIA);
// groupe 3 => media
if(troisieme){
var value = Math.max(ligne["3e etage %"],ligne["2e etage %"],ligne["1er etage %"]);
var source = ligne["3e etage NOM"];
var target = ligne["Media NOM"];
add_link(source,target,value,2,GROUPE_MEDIA);
}
// groupe 2 => media
if(deuxieme){
var value = Math.max(ligne["2e etage %"],ligne["1er etage %"]);
var source = ligne["2e etage NOM"];
var target = ligne["Media NOM"];
add_link(source,target,value,2,GROUPE_MEDIA);
}
// groupe 1=> media
if(premier){
var value = ligne["1er etage %"];
var source = ligne["1e etage NOM"];
var target = ligne["Media NOM"];
add_link(source,target,value,0,GROUPE_MEDIA);
}
}
var mapouter = d3.map();
var mapouterID = d3.map();
var mapinner = d3.map();
var new_links =[];
getPossessors().forEach(function(d){
if (d == null)
return;
i = { id: 'i' + d.id, name: d.name, related_links: [] };
i.related_nodes = [i.id];
mapinner.set(i.id,i);
get_links(i.name,POSSESSEUR_MEDIA).forEach(function(d1){
var o;
console.log(d1.target);
if(mapouter.get(d1.target) == undefined){
o = { name: d1.target, id: 'o' + getId(d1.target), related_links: [] };
o.related_nodes = [o.id];
mapouter.set(d1.target, o);
mapouterID.set(o.id, o);
}else{
o=mapouter.get(d1.target);
console.log(o);
}
// create the links
l = { id: 'l-' + i.id + '-' + o.id, inner: i, outer: o }
new_links.push(l);
// and the relationships
i.related_nodes.push(o.id);
i.related_links.push(l.id);
o.related_nodes.push(i.id);
o.related_links.push(l.id);
mapouter.set(d1.target, o);
});
});
data = {
inner: mapinner.values(),
outer: mapouter.values(),
links: new_links
}
// sort the data -- TODO: have multiple sort options
outer = data.outer;
data.outer = Array(outer.length);
var i1 = 0;
var i2 = outer.length - 1;
for (var i = 0; i < data.outer.length; ++i)
{
if (i % 2 == 1)
data.outer[i2--] = outer[i];
else
data.outer[i1++] = outer[i];
}
// from d3 colorbrewer:
// This product includes color specifications and designs developed by Cynthia Brewer (https://colorbrewer.org/).
var colors = ["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"]
var color = d3.scale.linear()
.domain([60, 220])
.range([colors.length-1, 0])
.clamp(true);
var diameter = 2000;// a changer pour faire reculer les outernodes des innernodes
var rect_width = 350;
var rect_height = 14;
var link_width = "1px";
var il = data.inner.length;
var ol = data.outer.length;
var inner_y = d3.scale.linear()
.domain([0, il])
.range([-(il * rect_height)/2, (il * rect_height)/2]);
mid = (data.outer.length/2.0)
var outer_x = d3.scale.linear()
.domain([0, mid, mid, data.outer.length])
.range([15, 165, 195 ,345]);
var outer_y = d3.scale.log()
.domain([0, ol])
.range([diameter / 3, 500 ]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 2])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
// setup positioning
function elipse(distance,i, max){
var coeffsin = 0.3;
var coeff = Math.sin(i/max * Math.PI)*coeffsin+1;
return distance*(coeff);
}
data.outer = data.outer.map(function(d, i) {
d.x = outer_x(i);
if(d.x>180){
d.y = elipse(diameter/3,i-ol/2,ol/2);
}else{
d.y = elipse(diameter/3,i,ol/2);
}
//d.y = diameter/3;// distance
return d;
});
data.inner = data.inner.map(function(d, i) {
d.x = -(rect_width / 2);
d.y = inner_y(i);
return d;
});
function get_color(name)
{
var c = Math.round(color(name));
if (isNaN(c))
return '#dddddd'; // fallback color
return colors[c];
}
// Can't just use d3.svg.diagonal because one edge is in normal space, the
// other edge is in radial space. Since we can't just ask d3 to do projection
// of a single point, do it ourselves the same way d3 would do it.
function projectX(x)
{
return ((x - 90) / 180 * Math.PI) - (Math.PI/2);
}
console.log(data);
var diagonal = d3.svg.diagonal()
.source(function(d) {return {"x": d.outer.y * Math.cos(projectX(d.outer.x)),
"y": -d.outer.y * Math.sin(projectX(d.outer.x))}; })
.target(function(d) { return {"x": d.inner.y + rect_height/2,
"y": d.outer.x > 180 ? d.inner.x : d.inner.x + rect_width}; })
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.call(zoom)
.append("g")
.attr("class","mainContainer");
// links
var link = svg.append('g').attr('class', 'links').selectAll(".link")
.data(data.links)
.enter().append('path')
.attr('class', 'link')
.attr('id', function(d) { return d.id })
.attr("d", diagonal)
.attr('stroke', function(d) { return get_color(d.inner.name); })
.attr('stroke-width', link_width);
// outer nodes
var onode = svg.append('g').selectAll(".outer_node")
.data(data.outer)
.enter().append("g")
.attr("class", "outer_node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
onode.append("circle")
.attr('id', function(d) { return d.id })
.attr("r", 6);
onode.append("circle")
.attr('r', 20)
.attr('visibility', 'hidden');
onode.append("text")
.attr('id', function(d) { return d.id + '-txt'; })
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.style("fill","#FFFFFF")
.text(function(d) { return d.name; });
// inner nodes
var inode = svg.append('g').selectAll(".inner_node")
.data(data.inner)
.enter().append("g")
.attr("class", "inner_node")
.attr("transform", function(d, i) { return "translate(" + d.x + "," + d.y + ")"})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
inode.append('rect')
.attr('width', rect_width)
.attr('height', rect_height)
.attr('id', function(d) { return d.id; })
.attr('stroke-width', '1px')
.attr('stroke', 'black')
.attr('fill', function(d) { return get_color(d.name); });
inode.append("text")
.attr('id', function(d) { return d.id + '-txt'; })
.attr('text-anchor', 'middle')
.attr("transform", "translate(" + rect_width/2 + ", " + rect_height * .75 + ")")
.text(function(d) { return d.name; });
// need to specify x/y/etc
d3.select(self.frameElement).style("height", diameter - 150 + "px");
function mouseover(d)
{
for (var i = 0; i < d.related_nodes.length; i++)
{
var obj = mapinner.get(d.related_nodes[i])||mapouterID.get(d.related_nodes[i]);
highlight(obj,false);
}
highlight(d,true);
console.clear();
/*
//7nl, to show only the mouse over elements
$("rect").not( 'rect#'+d.id).fadeOut();
$("text").not( 'text#'+d.id+'-txt' ).fadeOut();
for(linkednode in d.related_nodes){
console.log("name medias:",d.related_nodes[linkednode]);
$('text#'+d.related_nodes[linkednode]+'-txt').fadeIn();
$('text#'+d.related_nodes[linkednode]+'-txt').fadeIn();
}
console.log("name actionnaire:",d);
*/
}
function highlight(d, first){
d3.selectAll('.links .link').sort(function(a, b){ return d.related_links.indexOf(a.id); });
for (var i = 0; i < d.related_nodes.length; i++)
{
d3.select('#' + d.related_nodes[i]).classed('highlight', true);
d3.select('#' + d.related_nodes[i] + '-txt').attr("font-weight", 'bold');
}
for (var i = 0; i < d.related_links.length; i++){
d3.select('#' + d.related_links[i]).attr('stroke-width', '5px');
if(first){
d3.select('#' + d.related_links[i]).attr('stroke', 'green');
}else{
d3.select('#' + d.related_links[i]).attr('stroke', 'blue');
}
}
}
function mouseout(d)
{
for (var i = 0; i < d.related_nodes.length; i++)
{
var obj = mapinner.get(d.related_nodes[i])||mapouterID.get(d.related_nodes[i]);
UnHighlight(obj);
}
UnHighlight(d);
$("rect").not( 'rect#'+d.id).fadeIn('fast');
$("text").not( 'text#'+d.id+'-txt' ).fadeIn('fast');
}
function UnHighlight(d)
{
for (var i = 0; i < d.related_nodes.length; i++)
{
d3.select('#' + d.related_nodes[i]).classed('highlight', false);
d3.select('#' + d.related_nodes[i] + '-txt').attr("font-weight", 'normal');
}
for (var i = 0; i < d.related_links.length; i++){
d3.select('#' + d.related_links[i]).attr('stroke-width', link_width);
d3.select('#' + d.related_links[i]).attr('stroke', '#dddddd');
}
}
function zoomed() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
//3nl, juste pour un peu plus centrer la visu
$("svg").width($(".mainContainer").width())
d3.select(".mainContainer").attr("transform", "translate(" + ($("svg").width()-200) / 2 + "," + $("svg").width() / 3 + ")");
})//find3.json
});//jquery a la rescousse
</script>
https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-rc1/jquery.min.js
https://d3js.org/d3.v3.min.js