KKostya
7/17/2013 - 10:57 PM

Joukowski + d3.brush

Joukowski + d3.brush

<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg { font: 10px sans-serif; }
.brsh .extent { fill: steelblue; stroke: grey; stroke-width: 0.5px; fill-opacity: .125;}
.brsh .back   { fill: none; stroke: black; stroke-width: 1px;}
.line         { fill: none; stroke: black; stroke-width: 0.5px; }
.axis         { fill: none; stroke: black; }
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
    function Complex(re, im) { this.re  =   re; this.im  =   im; };
    Complex.prototype.clone = function(){ return new Complex(this.re,this.im); };
    Complex.prototype.add = function(z) { this.re += z.re; this.im += z.im; return this; };
    Complex.prototype.sub = function(z) { this.re -= z.re; this.im -= z.im; return this; };
    Complex.prototype.mul = function(z) 
    { 
        var tmp = this.re;
        this.re = this.re*z.re - this.im*z.im; 
        this.im =     tmp*z.im + this.im*z.re; 
        return this;
    };
                                                     
    Complex.prototype.div = function(z) 
    { 
        var tmp =  this.re, 
              n =     z.re*z.re +    z.im*z.im;
        this.re = (this.re*z.re + this.im*z.im)/n; 
        this.im = (   -tmp*z.im + this.im*z.re)/n; 
        return this;
    };
                                                     
 
 
    var width = 960, height = 500;
 
    var svg = d3.select("body")
                .append("svg")
                .attr("width",   width)
                .attr("height", height);

    var mapd = svg.append("g").attr("class","mapd");

    var brsh = svg.append("g").attr("class","brsh")
                              .attr("transform","translate("+width/2+")");

    var brsb = brsh.append("g");
 
    var x1 = d3.scale.linear().range([0, width/2]).domain([-10, 10]);
    var y1 = d3.scale.linear().range([ height, 0]).domain([-10, 10]);
    var x2 = d3.scale.linear().range([0, width/2]).domain([-2, 2]);
    var y2 = d3.scale.linear().range([ height, 0]).domain([-2, 2]);

    mapd.append("g").attr("class","axis")
        .attr("transform","translate(0,"+height/2+")")
        .call(d3.svg.axis().scale(x1).orient("bottom"));

    mapd.append("g").attr("class","axis")
        .attr("transform","translate("+width/4+")")
        .call(d3.svg.axis().scale(y1).orient("left")); 

    brsh.append("g").attr("class","axis")
        .attr("transform","translate(0,"+height/2+")")
        .call(d3.svg.axis().scale(x2).orient("bottom"));

    brsh.append("g").attr("class","axis")
        .attr("transform","translate("+width/4+")")
        .call(d3.svg.axis().scale(y2).orient("left"));

    var line1 = d3.svg.line()
                      .x(function(d) { return x1(d.re); })
                      .y(function(d) { return y1(d.im); });

    var line2 = d3.svg.line()
                      .x(function(d) { return x2(d.re); })
                      .y(function(d) { return y2(d.im); });

    var brush = d3.svg.brush().x(x2).y(y2).on("brush", plot);    

    brsh.append("rect").attr("class","back")
                       .attr("width",width/2)
                       .attr("height",height);

    brsh.call(brush);

    function plines(sel,data, f)
    {
        var paths = sel.selectAll('.line').data(data);
        paths.enter().append('path').attr('class','line');
        paths.attr('d',f);
        paths.exit().remove();
    }


    function plot()
    { 
        if(brush.empty()) return;
        ext = brush.extent();
        
        var x0 = (ext[1][0] + ext[0][0])/2;
        var y0 = (ext[1][1] + ext[0][1])/2;
        var dx = (ext[1][0] - ext[0][0])/2;
        var dy = (ext[1][1] - ext[0][1])/2;
        
        var data = d3.range(0,1,1/20).map(function(r){
            return d3.range(-Math.PI,Math.PI,Math.PI/20).map(function(p){
            return new Complex(x0+r*dx*Math.cos(p),y0+r*dy*Math.sin(p));})})

        plines(brsb,data,function(d){return line2(d)+'Z';});
        data.forEach(function(d){d.forEach(function(z) {z.add((new Complex(1,0)).div(z));})});
        plines(mapd,data,function(d){return line1(d)+'Z';});
    }

</script>
</body>