我使用此示例:https://codepen.io/AndrewGHC/pen/mPXjKr
我有两个问题:
1)如何限制拖放?例如,我想限制围绕圆圈移动50px。距离圆圈的起始位置不应超过50px。
2)刷新页面时,您会看到不同位置的元素。 一个圆可能是正确的,下一次是左边。如何避免这种情况?我想我需要设定起始位置。
// Request data, generate bg with Trianglify & set up loading function.
function slowPrint(tgt, i, msg, spd) {
if (i < msg.length) {
$(tgt).append(msg[i]);
i++;
var writeTimer = setTimeout(function() {
slowPrint(tgt, i, msg, spd)
}, spd);
}
}
function writeThis(tgt, msg, spd) {
if ($(tgt).html() === msg) {
return;
}
$(tgt).html('');
slowPrint(tgt, 0, msg, spd);
}
writeThis('#info', 'Loading . . .', 100);
var url = "https://raw.githubusercontent.com/AndrewGHC/kevin-bacon-number/master/kevinBacon.json";
d3.json(url, drawGraph);
// Credit to Trianglify @ https://github.com/qrohlf/trianglify
var pattern = Trianglify({
height: $(document).height(),
width: $(document).width(),
cell_size: 40
});
document.body.style.backgroundImage = "url(" + pattern.png() + ")";
// Create the drawGraph callback
function drawGraph(err, data) {
if (err) throw err;
var width = $('#graph').width(),
height = $('#graph').height();
// Prepare the data for the force graph, beinning by creating an array of movies (strings)
var movies = [];
(function() {
data.actors.forEach(function(actor) {
actor.movies.forEach(function(movie) {
if (movies.indexOf(movie) === -1) {
movies.push(movie);
}
});
});
}())
// Create the links array for the force graph, mapping actors to movies. This will draw a line between the two.
var links = [];
(function() {
data.actors.forEach(function(actor, actorIndex) {
actor.movies.forEach(function(movie, movieIndex) {
links.push({
"source": actorIndex,
"target": data.actors.length + movies.indexOf(movie)
});
});
});
}())
// Now prepare the nodes array, concatenating data.actors and the movies array. The order here is important, and movie indices must be converted into objects.
var nodes = data.actors;
movies.forEach(function(movie) {
nodes.push({
"movie": movie
});
});
// Create the SVG canvas & force layout
var canvas = d3.select('#graph')
.append('svg')
.attr("height", height)
.attr("width", width);
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
.links(links)
.linkDistance(50)
.charge(function(d) {
if (d.name === "Kevin Bacon") {
return -1000;
} else if (d.name) {
return -(d.weight) * 50;
}
return -((d.weight * 50) * 5);
})
.gravity(0.1)
.start();
// Helper function to remove whitespace, later used for assigning IDs
function rmWs(string) {
if (typeof string !== 'string') {
return false;
}
string = string.split(' ').join('');
return string;
}
// Create the links
var link = canvas.selectAll('.link')
.data(links)
.enter().append('line')
.attr('class', 'link');
// Create a colour scale for movie nodes. Find the min and max no. of links for the range of the colour domain.
var arrMax = [];
links.forEach(function(link) {
arrMax.push(link.target.weight);
});
var colour = d3.scale.linear()
.domain([1, d3.max(arrMax)])
.range(["white", "black"])
.interpolate(d3.interpolateHcl);
// Set up the pop up on mouse hover
// Call circles on SVG chart, with colours along a white - black gradient generated based on the max weight & variable sizing. Then place text on these movie elements.
var circleRadius = 17;
var circles = canvas.selectAll('.movies')
.data(nodes)
.enter()
.append('circle')
.attr('r', function(d, i) {
if (d.name) {
return circleRadius;
}
return circleRadius + (d.weight * 2);
})
.attr('stroke', '#777')
.attr('stroke-width', '2px')
.attr('fill', function(d, i) {
return colour(d.weight) || 'black';
})
.call(force.drag)
var text = canvas.selectAll('.moviesText')
.data(nodes)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.text(function(d) {
return d.movie;
});
// Set up clip path for each forthcoming image node to clip rectangular images to circles. Then call images on the canvas.
var clip = canvas.selectAll('clipPath')
.data(nodes)
.enter()
.append('clipPath')
.attr('id', function(d) {
return rmWs(d.name) || rmWs(d.movie)
})
.append('circle')
.attr('r', circleRadius);
var imgWidth = 50,
imgHeight = 50;
var node = canvas.selectAll('.node')
.data(nodes)
.enter()
.append('image')
.attr('xlink:href', function(d) {
return d.thumbnail;
})
.attr("class", "image")
.attr("width", imgWidth)
.attr("height", imgHeight)
.attr("clip-path", function(d) {
return "url(#" + (rmWs(d.name) || rmWs(d.movie)) + ")"
})
.call(force.drag);
// Handle operations on each tick.
force.on("tick", function() {
link.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;
});
node.attr("x", function(d) {
return d.x - (imgWidth / 2);
})
.attr("y", function(d) {
return d.y - (imgHeight / 2);
});
clip.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
circles.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
text.attr('x', function(d) {
return d.x;
})
.attr('y', function(d) {
return d.y - 30;
})
});
// When all initial calculations are done, print title to replace 'Loading . . .'
force.on('end', function() {
writeThis('#info', 'D3 Force Graph - Distance from Kevin Bacon', 100);
})
}
&#13;
@import url(https://fonts.googleapis.com/css?family=Questrial' rel='stylesheet' type='text/css);
#header {
text-align: center;
font-family: 'Jockey One', sans-serif;
}
#graph {
margin: 15px auto;
background: white;
height: 750px;
width: 750px;
-webkit-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
}
.link {
stroke: #777;
stroke-width: 2px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.1/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="header">
<h2 id="info"></h2>
</div>
<div id="graph"></div>
&#13;
答案 0 :(得分:0)
以下是限制拖动的方法:
首先,设置拖动功能:
var drag = force.drag()
.on("dragstart", dragstarted)
.on("drag", dragged);
然后,在dragstarted
中,获取当前的x
和y
位置:
function dragstarted(d) {
currentX = d.x;
currentY = d.y;
}
最后,在dragged
函数中,设置规则:
function dragged(d) {
d.px = (d.px > currentX + 50) ? currentX + 50 : d.px;
d.py = (d.py > currentY + 50) ? currentY + 50 : d.py;
d.px = (d.px < currentX - 50) ? currentX - 50 : d.px;
d.py = (d.py < currentY - 50) ? currentY - 50 : d.py;
}
PS:在这里,SO是一个很好的做法,一次处理1个问题,每个问题一个问题。所以,我建议你将第二个问题作为一个单独的问题发布。