The VisDock toolkit provides various interactions in the gift wrapping algorithm based on R. A. Jarvis' O(nh) complexity algorithm. Users can make selections of SVG elements (circle) by using various selection tools and this example generates a convex hull that contains the SVG elements. For more information about VisDock, cick on the link.
xxxxxxxxxx
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v3.min.js"></script>
<link href="https://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.css" rel="stylesheet" type="text/css"/>
<script src="https://rawgithub.com/visdockhub/newvisdock/master/master/visdock.js"></script>
<script src="https://rawgithub.com/visdockhub/newvisdock/master/master/2d.js"></script>
<script src="https://rawgithub.com/visdockhub/newvisdock/master/master/intersectionutilities.js"></script>
<script src="https://rawgithub.com/visdockhub/newvisdock/master/master/visdock.utils.js"></script>
<body>
</body>
<script>
VisDock.init('body', {width: 1200, height: 800});
var viewport = VisDock.getViewport();
var svg = viewport;
var xy = [];
for (var i = 0; i < 200; i++){
xy[i] = {};
xy[i]['x'] = 1000 * Math.random();
xy[i]['y'] = 600 * Math.random();
}
var id = 0;
var circles = svg.selectAll('circle').data(xy)
.enter().append('circle')
.attr('cx', function(d){
return parseFloat(d.x);
})
.attr('cy', function(d){
return parseFloat(d.y);
})
.attr('id', function(d,i){
return 'id'+i;
})
.attr('class', 'nodes')
.attr('r', 5)
.attr('fill', 'black');
VisDock.eventHandler = {
getHitsPolygon : function(points, inclusive) {
var shapebound = new createPolygon(points);
return shapebound.intersectEllipse(d3.selectAll(".nodes")[0], inclusive)
},
getHitsEllipse : function(points, inclusive) {
var shapebound = new createEllipse(points);
return shapebound.intersectEllipse(d3.selectAll(".nodes")[0], inclusive)
},
getHitsLine : function(points, inclusive) {
var shapebound = new createLine(points);
return shapebound.intersectEllipse(d3.selectAll(".nodes")[0], inclusive)
},
setColor : function(hits) {
var circleObjects = d3.selectAll("circle")[0];
for (var i = 0; i < hits.length; i++) {
VisDock.utils.addEllipseLayer(hits[i], null, num - 1);
}
findConvex(hits);
},
changeColor : function(color, query, index) {
},
changeVisibility : function(vis, query, index) {
},
removeColor : function(hits, index) {
for (var i = 0; i < hits.length; i++) {
hits[i].remove();
}
},
}
function findConvex(hits){
VisDock.startChrome();
var theta0 = 0;
var done = 0;
var index = -1;
var xprev;
var yprev;
var connect = [];
var count = 0;
var cas = 0;
var theta_n = 0;
while (done == 0 && count < 1000){
count++;
if (index == -1){
var x = 1000000;
for (var j = 0; j < hits.length; j++){
if (parseFloat(hits[j].getAttribute("cx")) < x){
x = parseFloat(hits[j].getAttribute("cx"));
index = j;
}
}
connect.push(index);
xprev = parseFloat(hits[index].getAttribute("cx"));
yprev = 1*parseFloat(hits[index].getAttribute("cy"));
theta0 = Math.atan((yprev/xprev));
} else if (connect.length == 1){
var theta;
var theta_min = 100000000;
var dx, dy;
for (var j = 0; j < hits.length; j++){
if (j != connect[0]){
dy = 1*(parseFloat(hits[j].getAttribute("cy")) - yprev);
dx = (parseFloat(hits[j].getAttribute("cx")) - xprev);
theta = Math.atan((dy/dx));
if ((theta) < (theta_min)){
theta_min = theta;
index = j;
var dx2 = dx;
var dy2 = dy;
}
}
}
if (dx2 <= 0 && dy2 >= 0){
cas = 1;
} else if (dx2 <= 0 && dy2 <= 0){
cas = 2;
} else if (dx2 >= 0 && dy2 <= 0){
cas = 3;
} else if (dx2 >= 0 && dy2 >= 0){
cas = 4;
}
theta_n = Math.abs(Math.atan(dy2/dx2));
xprev = parseFloat(hits[index].getAttribute("cx"));
yprev = 1*parseFloat(hits[index].getAttribute("cy"));
connect.push(index);
} else if (connect.length > 1){
var n = connect.length - 1;
var theta;
var theta_min = 100000000;
var dx, dy;
for (var j = 0; j < hits.length; j++){
if (j == connect[0] || connect.indexOf(j) == -1){
if (j != connect[connect.length-2]){
if (j != connect[n]){
dy = 1*(parseFloat(hits[j].getAttribute("cy")) - yprev);
dx = (parseFloat(hits[j].getAttribute("cx")) - xprev);
theta = Math.atan((dy/dx));
if (dx <= 0 && dy >= 0){ // case 1
if (cas == 1){
theta = Math.PI + theta_n - Math.abs(theta);
} else if (cas == 2){
theta = Math.PI + theta_n + Math.abs(theta);
} else if (cas == 3){
if (Math.abs(theta) > theta_n){
theta = theta_n - Math.abs(theta) + 2*Math.PI;
} else{
theta = -1*theta_n + Math.abs(theta) + 2*Math.PI;
}
} else if (cas == 4){
theta = 2*Math.PI - theta_n - Math.abs(theta);
}
} else if (dx <= 0 && dy <= 0){ // case 2
if (cas == 1){
theta = Math.PI + theta_n + Math.abs(theta);
} else if (cas == 2){
theta = Math.PI - theta_n + Math.abs(theta);
} else if (cas == 3){
theta = 2 * Math.PI - Math.abs(theta) - theta_n;
} else if (cas == 4){
if (Math.abs(theta) > theta_n){
theta = 2*Math.PI + theta_n - Math.abs(theta);
} else {
theta = 2*Math.PI - theta_n + Math.abs(theta);
}
}
} else if (dx >= 0 && dy <= 0){ // case 3
if (cas == 1){
if (Math.abs(theta) > theta_n){
theta = 2*Math.PI + theta_n - Math.abs(theta);
} else {
theta = 2*Math.PI - theta_n + Math.abs(theta);
}
} else if (cas == 2){
theta = 2*Math.PI - theta_n - Math.abs(theta);
} else if (cas == 3){
theta = Math.PI + theta_n - Math.abs(theta);
} else if (cas == 4){
theta = Math.PI + theta_n + Math.abs(theta);
}
} else if (dx >= 0 && dy >= 0){ // case 4
if (cas == 1){
theta = 2*Math.PI - theta_n - Math.abs(theta);
} else if (cas == 2){
if (Math.abs(theta) > theta_n){
theta = 2*Math.PI + theta_n - Math.abs(theta);
} else {
theta = 2*Math.PI - theta_n + Math.abs(theta);
}
} else if (cas == 3){
theta = Math.abs(theta) + theta_n + Math.PI;
} else if (cas == 4){
theta = Math.PI - theta_n + Math.abs(theta);
}
}
if ((theta) < (theta_min)){
theta_min = theta;
index = j;
var dx2 = dx;
var dy2 = dy;
}
}
}
}
}
if (connect.indexOf(index) == -1 || index == connect[0]){
if (connect.length != 2 || connect.indexOf(index) == -1){
connect.push(index);
xprev = parseFloat(hits[index].getAttribute("cx"));
yprev = parseFloat(hits[index].getAttribute("cy"));
theta0 = theta_min;
theta_min = 10000000;
theta_n = Math.abs(Math.atan(Math.abs(dy2/dx2)));
if (dx2 <= 0 && dy2 >= 0){
cas = 1;
} else if (dx2 <= 0 && dy2 <= 0){
cas = 2;
} else if (dx2 >= 0 && dy2 <= 0){
cas = 3;
} else if (dx2 >= 0 && dy2 >= 0){
cas = 4;
}
}
}
if (index == connect[0] && connect.length != 2){
done = 1;
}
}
}
var points = "";
for (var i = 0; i < connect.length; i++){
var cx = parseFloat(hits[connect[i]].getAttribute("cx"));
var cy = parseFloat(hits[connect[i]].getAttribute("cy"));
points = points + cx + "," + cy + " ";
}
svg.append("polygon")
.attr("points", points)
.attr("stroke-width", 2)
.attr("fill", "blue")
.attr("opacity", "0.2");
VisDock.finishChrome();
}
BirdView.init(viewport, 1200, 800)
d3.select(self.frameElement).style("height", "800px");
d3.select(self.frameElement).style("width", "1200px");
</script>
</html>
Modified http://d3js.org/d3.v3.min.js to a secure url
Modified http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.js to a secure url
Modified http://rawgithub.com/VisDockHub/NewVisDock/master/master/2D.js to a secure url
Modified http://rawgithub.com/VisDockHub/NewVisDock/master/master/IntersectionUtilities.js to a secure url
Modified http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.utils.js to a secure url
https://d3js.org/d3.v3.min.js
https://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.js
https://rawgithub.com/VisDockHub/NewVisDock/master/master/2D.js
https://rawgithub.com/VisDockHub/NewVisDock/master/master/IntersectionUtilities.js
https://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.utils.js