Предотвратить масштабирование графика D3

1

Я использую это как мой базовый проект, который прокручивается и масштабируется как по оси x, так и по оси y. Я модифицировал его только для прокрутки и масштабирования по оси x. Теперь я хочу, чтобы он не был масштабируемым (т.е. Масштаб x не должен меняться), сохраняя его прокручиваемым (т.е. Щелкая по графику и перетаскивая его влево или вправо)

Я пробовал делать scale(1) где трансформация, чтобы шкала не изменялась, но это не помогает. Вот фрагмент для этого:

g.append("svg:rect")
              .attr("class", "zoom x box")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom)
              .attr("transform", "translate(" + 0 + "," + 0 + ")")
              .style("visibility", "hidden")
              .attr("pointer-events", "all")
              .call( d3.behavior.zoom().on("zoom", function(){
                  g.attr("transform", "translate(" + d3.event.translate + ") scale(1)")
              }) ).append("g");

И вот полный код:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<!DOCTYPE html>
<html>
  <head>
    <title>Simpe Single Axis Zoom</title>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <style>
    .axis path, .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
    }
    </style>
  </head>
  <body>
    <div id="chart"></div>
    <script>
      var ex_chart = example().zoom(true);

      var data = [];
      for (var i = 0; i < 100; i++) {
        data.push([Math.random(), Math.random()]);
      }
      d3.select('#chart')
      .append("svg").attr("width", window.innerWidth).attr("height",window.innerHeight)
      .datum(data).call(ex_chart);

      function example() {
        var svg;
        var margin = {
          top: 60,
          bottom: 80,
          left: 60,
          right: 0
        };
        var width = 500;
        var height = 400;
        var xaxis = d3.svg.axis();
        var yaxis = d3.svg.axis();
        var xscale = d3.scale.linear();
        var yscale = d3.scale.linear();
        var zoomable = true;

        var xzoom = d3.behavior.zoom()
          .x(xscale)
          .on("zoom", zoomable ? draw : null);

        function chart(selection) {
          selection.each(function(data) {
            svg = d3.select(this).selectAll('svg').data([data]);
            svg.enter().append('svg');
            var g = svg.append('g')
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            g.append("defs").append("clipPath")
              .attr("id", "clip")
              .append("rect")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom);

            g.append("svg:rect")
              .attr("class", "border")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom)
              .style("stroke", "black")
              .style("fill", "none");

            g.append("g").attr("class", "x axis")
              .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")");

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

            g.append("g")
              .attr("class", "scatter")
              .attr("clip-path", "url(#clip)");


            g
              .append("svg:rect")
              .attr("class", "zoom x box")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom)
              .attr("transform", "translate(" + 0 + "," + 0 + ")")
              .style("visibility", "hidden")
              .attr("pointer-events", "all")
              .call( d3.behavior.zoom().on("zoom", function(){
                  g.attr("transform", "translate(" + d3.event.translate + ") scale(1)")
              }) ).append("g");

            // Update the x-axis
            xscale.domain(d3.extent(data, function(d) {
              return d[0];
            }))
              .range([0, width - margin.left - margin.right]);

            xaxis.scale(xscale)
              .orient('bottom')
              .tickPadding(10);

            svg.select('g.x.axis').call(xaxis);

            // Update the y-scale.
            yscale.domain(d3.extent(data, function(d) {
              return d[1];
            }))
              .range([height - margin.top - margin.bottom, 0]);

            yaxis.scale(yscale)
              .orient('left')
              .tickPadding(10);

            svg.select('g.y.axis').call(yaxis);

            draw();
          });

          return chart;
        }

        function update() {
          var gs = svg.select("g.scatter");

          var circle = gs.selectAll("circle")
            .data(function(d) {
              return d;
            });

          circle.enter().append("svg:circle")
            .attr("class", "points")
            .style("fill", "steelblue")
            .attr("cx", function(d) {
              return X(d);
            })
            .attr("cy", function(d) {
              return Y(d);
            })
            .attr("r", 4);

          circle.attr("cx", function(d) {
            return X(d);
          })
            .attr("cy", function(d) {
              return Y(d);
            });

          circle.exit().remove();
        }

        function zoom_update() {

          xzoom = d3.behavior.zoom()
            .x(xscale)
            .on("zoom", zoomable ? draw : null);

          svg.select('rect.zoom.x.box').call(xzoom);
        }

        function draw() {
          svg.select('g.x.axis').call(xaxis);
          //svg.select('g.y.axis').call(yaxis);

          update();
          zoom_update();
        };

        // X value to scale

        function X(d) {
          return xscale(d[0]);
        }

        // Y value to scale

        function Y(d) {
          return yscale(d[1]);
        }

        chart.zoom = function (_){
          if (!arguments.length) return zoomable;
          zoomable = _;
          return chart;
        }

        return chart;
      }
    </script>
  </body>
</html>

Любая помощь очень ценится. Благодарю.

Теги:
d3.js

1 ответ

0

Я узнал, что для этого есть легкое решение. В функции d3.behaviour.zoom() все, что мне нужно было добавить, было: .scaleExtent([1,1]), который не масштабирует ничего более 1 и, следовательно, предотвращает увеличение.

Пример: https://jsfiddle.net/x97k4snj/1/

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<!DOCTYPE html>
<html>
  <head>
    <title>Simpe Single Axis Zoom</title>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <style>
    .axis path, .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
    }
    </style>
  </head>
  <body>
    <div id="chart"></div>
    <script>
      var ex_chart = example().zoom(true);

      var data = [];
      for (var i = 0; i < 100; i++) {
        data.push([Math.random(), Math.random()]);
      }
      d3.select('#chart')
      .append("svg").attr("width", window.innerWidth).attr("height",window.innerHeight)
      .datum(data).call(ex_chart);

      function example() {
        var svg;
        var margin = {
          top: 60,
          bottom: 80,
          left: 60,
          right: 0
        };
        var width = 500;
        var height = 400;
        var xaxis = d3.svg.axis();
        var yaxis = d3.svg.axis();
        var xscale = d3.scale.linear();
        var yscale = d3.scale.linear();
        var zoomable = true;

        var xzoom = d3.behavior.zoom()
          .scaleExtent([1,1])
          .x(xscale)
          .on("zoom", zoomable ? draw : null);

        function chart(selection) {
          selection.each(function(data) {
            svg = d3.select(this).selectAll('svg').data([data]);
            svg.enter().append('svg');
            var g = svg.append('g')
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            g.append("defs").append("clipPath")
              .attr("id", "clip")
              .append("rect")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom);

            g.append("svg:rect")
              .attr("class", "border")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom)
              .style("stroke", "black")
              .style("fill", "none");

            g.append("g").attr("class", "x axis")
              .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")");

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

            g.append("g")
              .attr("class", "scatter")
              .attr("clip-path", "url(#clip)");


            g
              .append("svg:rect")
              .attr("class", "zoom x box")
              .attr("width", width - margin.left - margin.right)
              .attr("height", height - margin.top - margin.bottom)
              .attr("transform", "translate(" + 0 + "," + 0 + ")")
              .style("visibility", "hidden")
              .attr("pointer-events", "all")
              .call( d3.behavior.zoom().on("zoom", function(){
                  g.attr("transform", "translate(" + d3.event.translate + ") scale(1)")
              }) ).append("g");

            // Update the x-axis
            xscale.domain(d3.extent(data, function(d) {
              return d[0];
            }))
              .range([0, width - margin.left - margin.right]);

            xaxis.scale(xscale)
              .orient('bottom')
              .tickPadding(10);

            svg.select('g.x.axis').call(xaxis);

            // Update the y-scale.
            yscale.domain(d3.extent(data, function(d) {
              return d[1];
            }))
              .range([height - margin.top - margin.bottom, 0]);

            yaxis.scale(yscale)
              .orient('left')
              .tickPadding(10);

            svg.select('g.y.axis').call(yaxis);

            draw();
          });

          return chart;
        }

        function update() {
          var gs = svg.select("g.scatter");

          var circle = gs.selectAll("circle")
            .data(function(d) {
              return d;
            });

          circle.enter().append("svg:circle")
            .attr("class", "points")
            .style("fill", "steelblue")
            .attr("cx", function(d) {
              return X(d);
            })
            .attr("cy", function(d) {
              return Y(d);
            })
            .attr("r", 4);

          circle.attr("cx", function(d) {
            return X(d);
          })
            .attr("cy", function(d) {
              return Y(d);
            });

          circle.exit().remove();
        }

        function zoom_update() {

          xzoom = d3.behavior.zoom()
            .scaleExtent([1,1])
            .x(xscale)
            .on("zoom", zoomable ? draw : null);

          svg.select('rect.zoom.x.box').call(xzoom);
        }

        function draw() {
          svg.select('g.x.axis').call(xaxis);
          //svg.select('g.y.axis').call(yaxis);

          update();
          zoom_update();
        };

        // X value to scale

        function X(d) {
          return xscale(d[0]);
        }

        // Y value to scale

        function Y(d) {
          return yscale(d[1]);
        }

        chart.zoom = function (_){
          if (!arguments.length) return zoomable;
          zoomable = _;
          return chart;
        }

        return chart;
      }
    </script>
  </body>
</html>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню