Experimenting with draggable and resizable images in D3. Unfortunately, using a clip-path to put the images within circles causes some problems with resizing.
TODO:
- Implement something like this
| license: mit |
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| svg { | |
| background-color: #fffbef; | |
| } | |
| .circle-outline { | |
| fill: none; | |
| stroke: #dbdbdb; | |
| stroke-width: 2; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", 960) | |
| .attr("height", 500) | |
| var image = { | |
| size: 100 | |
| } | |
| var defs = svg.append("defs"); | |
| var clipPath = defs.append("clipPath") | |
| .attr("id", "clip") | |
| .append("circle") | |
| .attr("cx", image.size / 2) | |
| .attr("cy", image.size / 2) | |
| .attr("r", image.size / 2); | |
| var glow = defs.append("filter") | |
| .attr("id", "glow"); | |
| glow.append("feGaussianBlur") | |
| .attr("class", "blur") | |
| .attr("stdDeviation", 3.5) | |
| .attr("result","coloredBlur"); | |
| var feMergeGlow = glow.append("feMerge"); | |
| feMergeGlow.append("feMergeNode") | |
| .attr("in","coloredBlur"); | |
| feMergeGlow.append("feMergeNode") | |
| .attr("in","SourceGraphic"); | |
| var doctorUrl1 = "http://68.media.tumblr.com/avatar_52ce5b752efa_128.png", | |
| doctorUrl2 = "https://curbsideprophecies.files.wordpress.com/2007/08/davidolder.thumbnail.png", | |
| doctorUrl3 = "https://68.media.tumblr.com/avatar_fde0361fb75d_128.png", | |
| doctorUrl4 = "https://68.media.tumblr.com/avatar_91eba9afde80_128.png"; | |
| appendDraggableImage(doctorUrl1, [70, 175]); | |
| appendDraggableImage(doctorUrl2, [310, 175]); | |
| appendDraggableImage(doctorUrl3, [550, 175]); | |
| appendDraggableImage(doctorUrl4, [790, 175]); | |
| function appendDraggableImage(url, position) { | |
| var imageGroup = svg.append("g") | |
| .datum({position: position}) | |
| .attr("transform", d => "translate(" + d.position + ")"); | |
| var circleFill = imageGroup.append("circle") | |
| .attr("class", "circle-fill") | |
| .attr("cx", image.size / 2) | |
| .attr("cy", image.size / 2 ) | |
| .attr("r", image.size / 2) | |
| .attr("filter", "url(#glow"); | |
| var imageElem = imageGroup.append("image") | |
| .attr("xlink:href", url) | |
| .attr("height", image.size) | |
| .attr("width", image.size) | |
| .attr("clip-path", "url(#clip)"); | |
| var circleOutline = imageGroup.append("circle") | |
| .attr("class", "circle-outline") | |
| .attr("cx", image.size / 2) | |
| .attr("cy", image.size / 2 ) | |
| .attr("r", 1 + image.size / 2); | |
| imageGroup.call(d3.drag() | |
| .on("start", dragstarted) | |
| .on("drag", dragged) | |
| .on("end", dragended)); | |
| } | |
| function dragstarted(d) { | |
| // d3.select(this).raise(); | |
| // d3.select(this).select(".circle-outline") | |
| // .transition() | |
| // .attr("r", 1 + image.size / 3); | |
| // d3.select(this).select(".circle-fill") | |
| // .transition() | |
| // .attr("r", 1 + image.size / 3); | |
| // d3.select(this).select("image") | |
| // .attr("x", image.size / 6) | |
| // .attr("y", image.size / 6) | |
| // .attr("height", image.size * 2 / 3) | |
| // .attr("width", image.size * 2 / 3) | |
| // clipPath.attr("r", image.size / 3) | |
| } | |
| function dragged(d) { | |
| var newX = d3.event.x - image.size / 2, | |
| newY = d3.event.y - image.size / 2; | |
| d3.select(this) | |
| .attr("transform", "translate(" + (d.position = [newX, newY]) + ")"); | |
| } | |
| function dragended(d) { | |
| d3.select(this).lower(); | |
| } | |
| </script> | |
| </body> |