So I'm doing a simple representation on a map where i have nodes and links, a simple data just to test it out before i connect to a json file and i'm using leaflet.js for the map. I'll show my following JavaScrip, CSS and HTML.
Basically, I can see my nodes creating on the map but when it comes to the links they don't show it anywhere. I'm sure i made a mistake somewhere but i can't figure out where. I bet a fresh pair of eyes can point me out my basic mistake. Can someone help me out please? (Note: before i inserted a map and tried to connect the nodes with the links it worked just fine)
QUESTION How can i show the links between the nodes in the map?
$(document).ready(function() {
$("#mapid").height(window.innerHeight);
$('#slide-in').height(window.innerHeight);
$(document).on('click', '#advanced', function() {
if ($('#slide-in').hasClass('in')) {
$('#slide-in').removeClass('in')
} else {
$('#slide-in').addClass('in')
}
});
//A partir daqui
var map = L.map('mapid').setView([41.4079700, -8.5197800], 12)
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
id: 'mapbox/streets-v10',
tileSize: 512,
zoomOffset: -1,
}).addTo(map);
//Mover o zoom para o canto inferior direito
map.zoomControl.remove();
L.control.zoom({
position: 'bottomright'
}).addTo(map);
// Até aqui tá certo \\
// Add a svg layer to the map
L.svg().addTo(map);
// dados provisórios
var nodes = [{
lat: 41.4579700,
long: -8.5297800,
private: 2,
numContr: 10
},
{
lat: 41.4379700,
long: -8.5297800,
private: 2,
numContr: 20
},
{
lat: 41.4579700,
long: -8.4897800,
private: 1,
numContr: 40
},
{
lat: 41.4179700,
long: -8.4597800,
private: 1,
numContr: 50
},
{
lat: 41.3879700,
long: -8.5997800,
private: 2,
numContr: 10
},
{
lat: 41.4779700,
long: -8.5097800,
private: 1,
numContr: 30
},
];
var links = [{
source: nodes[0],
target: nodes[1],
fraude: 1
},
{
source: nodes[2],
target: nodes[1],
fraude: 2
},
{
source: nodes[0],
target: nodes[3],
fraude: 1
},
{
source: nodes[0],
target: nodes[4],
fraude: 2
},
{
source: nodes[0],
target: nodes[5],
fraude: 1
},
{
source: nodes[4],
target: nodes[1],
fraude: 1
},
{
source: nodes[4],
target: nodes[5],
fraude: 1
},
{
source: nodes[2],
target: nodes[3],
fraude: 1
}
];
//Adicionar os links
d3.select("#mapid")
.select("svg")
.selectAll("line")
.data(links)
.enter()
.append("line")
.attr("x1", function(d) {
return d.source.x
})
.attr("y1", function(d) {
return d.source.y
})
.attr("x2", function(d) {
return d.target.x
})
.attr("y2", function(d) {
return d.target.y
})
.style("stroke", function(d, i) {
if (d.fraude == 2) {
return "rgb(197,53,53)"
} else {
return "rgb(96,211,62"
}
})
.style("stroke-width", 5)
// Adicionar os nodes
d3.select("#mapid")
.select("svg")
.selectAll("myCircles")
.data(nodes) //onde tão os dados
.enter()
.append("circle")
.attr("cx", function(d) {
return map.latLngToLayerPoint([d.lat, d.long]).x
})
.attr("cy", function(d) {
return map.latLngToLayerPoint([d.lat, d.long]).y
})
.attr("r", function(d, i) {
if (d.numContr >= 50) {
return 20;
} else {
if (d.numContr < 50 && d.numContr > 25) {
return 16;
} else {
if (d.numContr < 25 && d.numContr > 10) {
return 12;
} else {
return 8;
}
}
}
})
.attr("fill", function(d, i) {
if (d.private == 1) {
return "rgb(8,105,114)"
} else {
return "rgb(167,255,131)"
}
})
.attr("stroke", "rgb(7,26,82)")
.attr("stroke-width", 6)
// Function that update circle position if something change
function update() {
d3.selectAll("circle")
.attr("cx", function(d) {
return map.latLngToLayerPoint([d.lat, d.long]).x
})
.attr("cy", function(d) {
return map.latLngToLayerPoint([d.lat, d.long]).y
})
}
// If the user change the map (zoom or drag), it update circle position:
map.on("moveend", update)
})
body {
margin: 0;
padding: 0;
}
#menu-pesquisa {
position: absolute;
z-index: 1000;
width: 324px;
height: 24px;
background: #fff;
left: 0;
margin: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(0, 0, 0, 0.02);
min-height: relative;
border-bottom: 0px solid transparent;
padding: 5px 0px 20px 30px;
text-align: center;
}
#slide-id h2 {
margin: 0;
padding: 0;
margin-bottom: 10px;
}
#slide-in {
padding: 10px;
position: absolute;
width: 250px;
z-index: 1000;
background: white;
margin-left: -270px;
transition: 0.5s;
}
#slide-in.in {
margin-left: 0px;
}
#input-pesquisa {
padding: 10px;
font-size: 15px;
border: 0;
float: left;
width: 65%;
background: transparent;
outline: none;
margin-top: 2px;
}
#input-pesquisa::placeholder {
opacity: 0.6;
font-family: Arial, Helvetica, sans-serif;
}
#Pesquisa {
box-sizing: border-box;
border-style: hidden;
background-color: inherit;
text-align: justify;
padding: 12px;
padding-left: 30px;
padding-right: 30px;
outline: none;
margin-top: -4px;
}
#Pesquisa .icon {
background: url(/images/magnifying-glass.svg) no-repeat;
float: left;
width: 24px;
height: 24px;
color: white;
border-left: none;
cursor: pointer;
border-color: transparent;
position: center;
}
#numero-contrato {
position: absolute;
z-index: 1000;
width: 280px;
height: 80px;
background: #fff;
padding: 5px;
left: 0;
bottom: 15px;
margin: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(0, 0, 0, 0.02);
text-align: initial;
}
#numero-contrato h5 {
padding: 0;
margin-left: 5px;
margin-top: 0px;
font-family: Arial, Helvetica, sans-serif;
}
#tipo-contrato {
position: absolute;
z-index: 1000;
width: 160px;
height: 80px;
background: #fff;
padding: 5px;
right: 230px;
bottom: 15px;
margin: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(0, 0, 0, 0.02);
text-align: initial;
}
#tipo-contrato h5 {
padding: 0;
margin-left: 5px;
margin-top: 0px;
font-family: Arial, Helvetica, sans-serif;
}
#tipo-entidades {
position: absolute;
z-index: 1000;
width: 160px;
height: 80px;
background: #fff;
padding: 5px;
right: 40px;
bottom: 15px;
margin: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(0, 0, 0, 0.02);
text-align: initial;
}
#tipo-entidades h5 {
padding: 0;
margin-left: 5px;
margin-top: 0px;
font-family: Arial, Helvetica, sans-serif;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" href="/styles/styles.css">
<link rel="stylesheet" href="/images/magnifying-glass.svg">
<!-- Mapa -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script>
<title>Fraud Detection</title>
</head>
<body>
<div id="slide-in">
<h2>More info</h2>
</div>
<div id="tipo-entidades">
<h5>Tipos de Entidades:</p>
</div>
<div id="tipo-contrato">
<h5>Tipos de Contratos:</p>
</div>
<div id="numero-contrato">
<h5>Número de contratos realizados:</p>
</div>
<div id="menu-pesquisa">
<input type="text" id="input-pesquisa" placeholder="Pesquisar informações" name="Pesquisa"></input>
<button id="Pesquisa"><span class="icon"></span></button>
</div>
<div>
<!-- <button id="advanced" class="icon">Pesquisa Avançada</button> -->
</div>
<div id="mapid" style="width: 100%;"></div>
</body>
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<script src="/scripts/force_directed_layout.js"></script>
</html>
I forgot to adapt the coordinates lat
and long
to x
and y
axes from html, like I did in the circles.
Basically this is my result:
d3.select("#mapid")
.select("svg")
.selectAll("line")
.data(links)
.enter()
.append("line")
.attr("x1", function(d) { return map.latLngToLayerPoint([d.source.lat, d.source.long]).x})
.attr("y1", function(d) { return map.latLngToLayerPoint([d.source.lat, d.source.long]).y})
.attr("x2", function(d) { return map.latLngToLayerPoint([d.target.lat, d.target.long]).x})
.attr("y2", function(d) { return map.latLngToLayerPoint([d.target.lat, d.target.long]).y})
.style("stroke", function(d, i)
{
if(d.fraude == 2)
{ return "rgb(197,53,53)"}
else
{ return "rgb(96,211,62"}
})
.style("stroke-width", 5)
And I have to update the function update as well, because if I don't the lines will stay in the frame all the time:
function update() {
d3.selectAll("circle")
.attr("cx", function(d){ return map.latLngToLayerPoint([d.lat, d.long]).x })
.attr("cy", function(d){ return map.latLngToLayerPoint([d.lat, d.long]).y })
d3.selectAll("line")
.attr("x1", function(d) { return map.latLngToLayerPoint([d.source.lat, d.source.long]).x})
.attr("y1", function(d) { return map.latLngToLayerPoint([d.source.lat, d.source.long]).y})
.attr("x2", function(d) { return map.latLngToLayerPoint([d.target.lat, d.target.long]).x})
.attr("y2", function(d) { return map.latLngToLayerPoint([d.target.lat, d.target.long]).y})
}