Skip to content

Instantly share code, notes, and snippets.

@vkuchinov
Last active April 30, 2018 11:06
Show Gist options
  • Save vkuchinov/9a22f79e34f5a032bc769ffb238a50d3 to your computer and use it in GitHub Desktop.
Save vkuchinov/9a22f79e34f5a032bc769ffb238a50d3 to your computer and use it in GitHub Desktop.
D3.JS Liquid Shapes (external SVG)
d3.liquid = function(parent_, index_, object_) {
var x = object_.x, y = object_.y;
var g = parent_.append("g").attr("id", "shape" + index_).attr("transform", "translate(" + (x) + ", " + (y) + " )");
d3.xml(object_.asset).mimeType("image/svg+xml").get(function(error, xml) {
if (error) throw error;
var imported = document.importNode(xml.documentElement, true);
d3.select("#shape" + index_)
.each(function() { this.appendChild(imported); });
d3.select("#" + object_.name).select("#area").attr("fill", "#228CC8");
var o = d3.select("#" + object_.name).select("#area");
this.xy = o.node().getBBox();
d3.select("#" + object_.name).append("clipPath").attr("id", "clip").append("rect")
.attr("id", "clip")
.attr("x", this.xy.x - object_.strokeWidth / 2)
.attr("y", this.xy.y - object_.strokeWidth / 2)
.attr("width", this.xy.width + object_.strokeWidth)
.attr("height", this.xy.height + object_.strokeWidth)
.attr("fill", "#FF00FF")
.attr("opacity", 0.4);
d3.select("#" + object_.name).append("text")
.attr("id", "full")
.attr("dx", this.xy.x + this.xy.width / 2 + object_.offset.x)
.attr("dy", this.xy.y + this.xy.height / 1.75 + object_.offset.y)
.attr("text-anchor", "middle")
.attr("font-size", object_.fontsize)
.attr("fill", "#FFFFFF")
.attr("stroke", "#none")
.html("<tspan>" + map(object_.value, 0, 1, 0, object_.units).toFixed(object_.decimals) + "</tspan><tspan style='font-size: " + object_.fontsize / 2 + "'>" + "ml</tspan>");
d3.select("#" + object_.name).append("text")
.attr("id", "clipped")
.attr("dx", this.xy.x + this.xy.width / 2 + object_.offset.x)
.attr("dy", this.xy.y + this.xy.height / 1.75 + + object_.offset.y)
.attr("fill", "#FFFFFF")
.attr("text-anchor", "middle")
.attr("font-size", object_.fontsize)
.attr("fill", "#000000")
.attr("stroke", "#000000")
.attr("stroke-width", 2)
.html("<tspan>" + map(object_.value, 0, 1, 0, object_.units).toFixed(object_.decimals) + "</tspan><tspan style='font-size: " + object_.fontsize / 2 + "'>" + "ml</tspan>");
this.cx = this.xy.x + this.xy.width / 2, this.cy = + this.xy.y + this.xy.height / 2;
this.halfWidth = this.xy.width / 2, this.halfHeight = this.xy.height / 2;
this.ratio = this.halfHeight/this.halfWidth;
this.waveCount = 1;
this.waveOffset = 0;
this.waveHeight = 5;
this.waveLength = this.halfWidth * 2 / this.waveCount;
this.waveClipCount = 1 + this.waveCount;
this.waveClipWidth = this.waveLength * this.waveClipCount;
this.gaugeCircleX = d3.scaleLinear().range([0, 2 * Math.PI]).domain([0, 1]);
this.gaugeCircleY = d3.scaleLinear().range([0, this.halfWidth]).domain([0, this.halfWidth]);
this.waveScaleX = d3.scaleLinear().range([0, this.waveClipWidth]).domain([0, 1]);
this.waveScaleY = d3.scaleLinear().range([0, this.waveHeight]).domain([0, 1]);
waveAnimateScale = d3.scaleLinear().range([0, this.waveClipWidth - this.halfWidth * 2]).domain([0, 1]);
this.data = [];
for(var i = 0; i <= 32 * this.waveClipCount; i++){ this.data.push({x: i / (32 * this.waveClipCount), y: (i / (32))}); }
this.clipArea = d3.area()
.x(function(d) { return this.waveScaleX(d.x); } )
.y0(function(d) { return this.waveScaleY(Math.sin(Math.PI * 2 * this.waveOffset * -1 + Math.PI * 2 * ( 1 - this.waveCount) + d.y * 2 * Math.PI));} )
.y1(function(d) { return (this.halfWidth * this.ratio * 2 + this.waveHeight); } );
this.clip = d3.select("#" + object_.name).append("clipPath")
.attr("id", "clipWave" + index_)
.attr("transform", "translate(" + (this.cx + this.halfWidth - this.waveClipWidth) + ", " + (this.cy + map(object_.value, 0, 1, this.halfWidth * this.ratio, -this.halfWidth * this.ratio)) + ")");
this.wave = this.clip.append("path")
.datum(this.data)
.attr("d", this.clipArea)
.attr("T", 0)
.attr("fill", "#0FFFF0");
d3.select("#" + object_.name).select("#area").attr("clip-path","url(#clipWave" + index_ + ")");
d3.select("#" + object_.name).select("#clipped").attr("clip-path","url(#clipWave" + index_ + ")");
animate(this.wave, this.waveAnimateScale);
});
function animate(wave_, waveAnimateScale_){
wave_.attr("transform","translate("+ waveAnimateScale_(wave_.attr("T"))+", 0)");
wave_.transition()
.ease(d3.easeLinear)
.duration(object_.waveAnimateTime * (1 - wave_.attr("T")))
.attr("transform","translate(" + waveAnimateScale_(1)+", 0)")
.attr("T", 1)
.on("end", function(){ wave_.attr("T", 0); animate(wave_, waveAnimateScale_); });
}
}
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>D3.JS Liquid Shapes</title>
<link rel="stylesheet" href="styles.css?v=1.0">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="d3.liquid.js"></script>
</head>
<body>
<script>
function map(value_, min0_, max0_, min1_, max1_){ return min1_ + (value_ - min0_) / (max0_ - min0_) * (max1_- min1_); }
var objects = [
{ name : "sampleA", asset: "sampleA.svg", waveAnimateTime: 1800, x: -150, y: window.innerHeight / 4, value: 0.75, units: 568, strokeWidth: 3, fontsize: 28, decimals: 0, offset: { x: 0, y: 0 } },
{ name : "sampleB", asset: "sampleB.svg", waveAnimateTime: 1800, x: 150, y: window.innerHeight / 4, value: 0.33, units: 0.5, strokeWidth: 3, fontsize: 48, decimals: 2, offset: { x: 0, y: 24 } }
]
var svg = d3.select("body").append("svg")
.attr("width", window.innerWidth)
.attr("height", window.innerHeight);
var shapeA = d3.liquid(svg, 0, objects[0]);
var shapeB = d3.liquid(svg, 1, objects[1]);
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
body { margin : 0; font-family: "Open Sans", sans-serif; background: #000; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment