Skip to content

Instantly share code, notes, and snippets.

@wrobstory
Last active November 16, 2024 13:38
Show Gist options
  • Select an option

  • Save wrobstory/7612013 to your computer and use it in GitHub Desktop.

Select an option

Save wrobstory/7612013 to your computer and use it in GitHub Desktop.

Revisions

  1. wrobstory revised this gist Nov 25, 2013. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -183,9 +183,9 @@
    brush_elm = svg.select(".brush").node();
    new_click_event = new Event('mousedown');
    new_click_event.pageX = d3.event.pageX;
    new_click_event.clientX = d3.event.pageX;
    new_click_event.clientX = d3.event.clientX;
    new_click_event.pageY = d3.event.pageY;
    new_click_event.clientY = d3.event.pageY;
    new_click_event.clientY = d3.event.clientY;
    brush_elm.dispatchEvent(new_click_event);
    });

  2. wrobstory revised this gist Nov 24, 2013. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    Example for [Cooperative Brushing and Tooltips in D3](http://wrobstory.github.io/2013/11/D3-brush-and-tooltip.html).

    The completed chart, with both tooltips and brushing working cooperatively. You can start a brush-zoom on either the background or a data point.
  3. wrobstory revised this gist Nov 24, 2013. 1 changed file with 31 additions and 30 deletions.
    61 changes: 31 additions & 30 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -42,7 +42,7 @@

    </style>
    <body>
    <script src="http://d3js.org/d3.v3.js"></script>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>
    d3.helper = {};

    @@ -62,7 +62,7 @@
    var absoluteMousePos = d3.mouse(bodyNode);
    tooltipDiv.style({
    left: (absoluteMousePos[0] + 10)+'px',
    top: (absoluteMousePos[1] - 15)+'px',
    top: (absoluteMousePos[1] - 40)+'px',
    'background-color': '#d8d5e4',
    width: '65px',
    height: '30px',
    @@ -82,7 +82,7 @@
    var absoluteMousePos = d3.mouse(bodyNode);
    tooltipDiv.style({
    left: (absoluteMousePos[0] + 10)+'px',
    top: (absoluteMousePos[1] - 15)+'px'
    top: (absoluteMousePos[1] - 40)+'px'
    });
    })
    .on('mouseout.tooltip', function(pD, pI){
    @@ -113,7 +113,7 @@
    var val = Math.floor(Math.random() * (50 - 5 + 1) + 5);
    data.push({index: i, value: val});
    values.push(val);
    };
    }

    var margin = {top: 20, right: 20, bottom: 60, left: 40},
    width = 960 - margin.left - margin.right,
    @@ -130,7 +130,7 @@
    var brush = d3.svg.brush()
    .x(x)
    .on("brush", brushmove)
    .on("brushend", brushend)
    .on("brushend", brushend);

    var xAxis = d3.svg.axis()
    .scale(x)
    @@ -155,13 +155,13 @@

    svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .call(yAxis);

    svg.append("g")
    .attr("class", "brush")
    .call(brush)
    .selectAll('rect')
    .attr('height', height)
    .attr('height', height);

    svg.append("defs").append("clipPath")
    .attr("id", "clip")
    @@ -174,66 +174,67 @@
    .enter().append("circle")
    .attr("class", "point")
    .attr("clip-path", "url(#clip)")
    .attr("r", function(d){return Math.floor(Math.random() * (20 - 5 + 1) + 5) })
    .attr("r", function(d){return Math.floor(Math.random() * (20 - 5 + 1) + 5);})
    .attr("cx", function(d) { return x(d.index); })
    .attr("cy", function(d) { return y(d.value); })
    .call(d3.helper.tooltip());

    points.on('mousedown', function(){
    brush_elm = svg.select(".brush").node()
    new_click_event = new Event('mousedown')
    new_click_event.initEvent('mousedown', true, true)
    new_click_event.pageX = d3.event.pageX
    new_click_event.pageY = d3.event.pageY
    brush_elm.dispatchEvent(new_click_event)
    brush_elm = svg.select(".brush").node();
    new_click_event = new Event('mousedown');
    new_click_event.pageX = d3.event.pageX;
    new_click_event.clientX = d3.event.pageX;
    new_click_event.pageY = d3.event.pageY;
    new_click_event.clientY = d3.event.pageY;
    brush_elm.dispatchEvent(new_click_event);
    });

    function brushmove() {
    var extent = brush.extent();
    points.classed("selected", function(d) {
    is_brushed = extent[0] <= d.index && d.index <= extent[1];
    return is_brushed
    return is_brushed;
    });
    };
    }

    function brushend() {
    get_button = d3.select(".clear-button")
    get_button = d3.select(".clear-button");
    if(get_button.empty() === true) {
    clear_button = svg.append('text')
    .attr("y", 460)
    .attr("x", 825)
    .attr("class", "clear-button")
    .text("Clear Brush")
    };
    .text("Clear Brush");
    }

    x.domain(brush.extent())
    x.domain(brush.extent());

    transition_data()
    reset_axis()
    transition_data();
    reset_axis();

    points.classed("selected", false)
    points.classed("selected", false);
    d3.select(".brush").call(brush.clear());

    clear_button.on('click', function(){
    x.domain([0, 50]);
    transition_data()
    reset_axis()
    clear_button.remove()
    transition_data();
    reset_axis();
    clear_button.remove();
    });
    };
    }

    function transition_data() {
    svg.selectAll(".point")
    .data(data)
    .transition()
    .duration(500)
    .attr("cx", function(d) { return x(d.index); })
    .attr("cx", function(d) { return x(d.index); });
    }

    function reset_axis() {
    svg.transition().duration(500)
    .select(".x.axis")
    .call(xAxis)
    .call(xAxis);
    }


  4. wrobstory revised this gist Nov 24, 2013. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -178,6 +178,15 @@
    .attr("cx", function(d) { return x(d.index); })
    .attr("cy", function(d) { return y(d.value); })
    .call(d3.helper.tooltip());

    points.on('mousedown', function(){
    brush_elm = svg.select(".brush").node()
    new_click_event = new Event('mousedown')
    new_click_event.initEvent('mousedown', true, true)
    new_click_event.pageX = d3.event.pageX
    new_click_event.pageY = d3.event.pageY
    brush_elm.dispatchEvent(new_click_event)
    });

    function brushmove() {
    var extent = brush.extent();
  5. wrobstory revised this gist Nov 23, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -63,7 +63,7 @@
    tooltipDiv.style({
    left: (absoluteMousePos[0] + 10)+'px',
    top: (absoluteMousePos[1] - 15)+'px',
    'background-color': '#afa2dc',
    'background-color': '#d8d5e4',
    width: '65px',
    height: '30px',
    padding: '5px',
  6. wrobstory revised this gist Nov 23, 2013. 1 changed file with 8 additions and 5 deletions.
    13 changes: 8 additions & 5 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -188,11 +188,14 @@
    };

    function brushend() {
    clear_button = svg.append('text')
    .attr("y", 460)
    .attr("x", 825)
    .attr("class", "clear-button")
    .text("Clear Brush")
    get_button = d3.select(".clear-button")
    if(get_button.empty() === true) {
    clear_button = svg.append('text')
    .attr("y", 460)
    .attr("x", 825)
    .attr("class", "clear-button")
    .text("Clear Brush")
    };

    x.domain(brush.extent())

  7. wrobstory revised this gist Nov 23, 2013. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -149,6 +149,7 @@

    svg.append("g")
    .attr("class", "x axis")
    .attr("clip-path", "url(#clip)")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

    @@ -166,7 +167,7 @@
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);
    .attr("height", height + 20);

    points = svg.selectAll(".point")
    .data(data)
  8. wrobstory revised this gist Nov 23, 2013. 1 changed file with 32 additions and 2 deletions.
    34 changes: 32 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -162,10 +162,17 @@
    .selectAll('rect')
    .attr('height', height)

    svg.append("defs").append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);

    points = svg.selectAll(".point")
    .data(data)
    .enter().append("circle")
    .attr("class", "point")
    .attr("clip-path", "url(#clip)")
    .attr("r", function(d){return Math.floor(Math.random() * (20 - 5 + 1) + 5) })
    .attr("cx", function(d) { return x(d.index); })
    .attr("cy", function(d) { return y(d.value); })
    @@ -186,12 +193,35 @@
    .attr("class", "clear-button")
    .text("Clear Brush")

    x.domain(brush.extent())

    transition_data()
    reset_axis()

    points.classed("selected", false)
    d3.select(".brush").call(brush.clear());

    clear_button.on('click', function(){
    points.classed("selected", false)
    d3.select(".brush").call(brush.clear());
    x.domain([0, 50]);
    transition_data()
    reset_axis()
    clear_button.remove()
    });
    };

    function transition_data() {
    svg.selectAll(".point")
    .data(data)
    .transition()
    .duration(500)
    .attr("cx", function(d) { return x(d.index); })
    }

    function reset_axis() {
    svg.transition().duration(500)
    .select(".x.axis")
    .call(xAxis)
    }


    </script>
  9. wrobstory created this gist Nov 23, 2013.
    197 changes: 197 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,197 @@
    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>

    .point {
    fill: #2f225d;
    stroke: #afa2dc;
    }

    .selected {
    fill: #afa2dc;
    stroke: #2f225d;
    }

    .axis {
    font: 10px sans-serif;
    }

    p {
    font: 12px sans-serif;
    margin: 0 0 2px 0;
    padding: 0;
    }

    .clear-button {
    font: 14px sans-serif;
    cursor: pointer;
    }

    .axis path,
    .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
    }

    .brush .extent {
    stroke: #fff;
    fill-opacity: .125;
    shape-rendering: crispEdges;
    }

    </style>
    <body>
    <script src="http://d3js.org/d3.v3.js"></script>
    <script>
    d3.helper = {};

    d3.helper.tooltip = function(){
    var tooltipDiv;
    var bodyNode = d3.select('body').node();

    function tooltip(selection){

    selection.on('mouseover.tooltip', function(pD, pI){
    // Clean up lost tooltips
    d3.select('body').selectAll('div.tooltip').remove();
    // Append tooltip
    tooltipDiv = d3.select('body')
    .append('div')
    .attr('class', 'tooltip')
    var absoluteMousePos = d3.mouse(bodyNode);
    tooltipDiv.style({
    left: (absoluteMousePos[0] + 10)+'px',
    top: (absoluteMousePos[1] - 15)+'px',
    'background-color': '#afa2dc',
    width: '65px',
    height: '30px',
    padding: '5px',
    position: 'absolute',
    'z-index': 1001,
    'box-shadow': '0 1px 2px 0 #656565'
    });

    var first_line = '<p>X-Value: ' + pD.index + '</p>'
    var second_line = '<p>Y-Value: ' + pD.value + '</p>'

    tooltipDiv.html(first_line + second_line)
    })
    .on('mousemove.tooltip', function(pD, pI){
    // Move tooltip
    var absoluteMousePos = d3.mouse(bodyNode);
    tooltipDiv.style({
    left: (absoluteMousePos[0] + 10)+'px',
    top: (absoluteMousePos[1] - 15)+'px'
    });
    })
    .on('mouseout.tooltip', function(pD, pI){
    // Remove tooltip
    tooltipDiv.remove();
    });

    }

    tooltip.attr = function(_x){
    if (!arguments.length) return attrs;
    attrs = _x;
    return this;
    };

    tooltip.style = function(_x){
    if (!arguments.length) return styles;
    styles = _x;
    return this;
    };

    return tooltip;
    };

    var data = [];
    var values = [];
    for (var i = 2; i <= 50; i++) {
    var val = Math.floor(Math.random() * (50 - 5 + 1) + 5);
    data.push({index: i, value: val});
    values.push(val);
    };

    var margin = {top: 20, right: 20, bottom: 60, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

    var x = d3.scale.linear()
    .range([0, width])
    .domain([0, 50]);

    var y = d3.scale.linear()
    .range([height, 0])
    .domain([0, d3.max(values) + 5]);

    var brush = d3.svg.brush()
    .x(x)
    .on("brush", brushmove)
    .on("brushend", brushend)

    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(11);

    var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

    svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)

    svg.append("g")
    .attr("class", "brush")
    .call(brush)
    .selectAll('rect')
    .attr('height', height)

    points = svg.selectAll(".point")
    .data(data)
    .enter().append("circle")
    .attr("class", "point")
    .attr("r", function(d){return Math.floor(Math.random() * (20 - 5 + 1) + 5) })
    .attr("cx", function(d) { return x(d.index); })
    .attr("cy", function(d) { return y(d.value); })
    .call(d3.helper.tooltip());

    function brushmove() {
    var extent = brush.extent();
    points.classed("selected", function(d) {
    is_brushed = extent[0] <= d.index && d.index <= extent[1];
    return is_brushed
    });
    };

    function brushend() {
    clear_button = svg.append('text')
    .attr("y", 460)
    .attr("x", 825)
    .attr("class", "clear-button")
    .text("Clear Brush")

    clear_button.on('click', function(){
    points.classed("selected", false)
    d3.select(".brush").call(brush.clear());
    clear_button.remove()
    });
    };


    </script>