首页 > 解决方案 > 缩放和平移在 D3 中不起作用 在鼠标滚轮上

问题描述

我使用 D3 创建了一个多折线图。绘制线条后,我将在鼠标事件上添加缩放和平移功能。我面临的问题是 X 轴正在重新缩放,但数据丢失并且无法与 X 轴一起正确缩放。我想,我犯了一些愚蠢的错误。任何帮助将非常感激。

if (!window.lineChart) window.lineChart = {}
var xAxisForAllChart = {};
var xAxisData = {}
var yAxisTest = {}

//Hello test
lineChart = function (graphContainer) {
  // set the dimensions and margins of the graph
  var margin = graphContainer.margin,
      padding = graphContainer.padding,
      width = graphContainer.size.width - margin.left - margin.right,
      height = graphContainer.size.height - 40;
  
  // CONVERT LIST INTO ARRAY
  variableslist  = graphContainer.graphVariableList.split(",");
  var $this ='';
  // ADD DATE VARIBLE TO ARRAY
  variableslist.push("Date");
  var lineChartType = graphContainer.containerDisplayType; 
  if( typeof(lineChartType) == 'undefined'){
    lineChartType = 'quadratic';
  }
  var typeOfLineChart = {"quadratic":d3.curveStep, "split":d3.curveLinear, "scatter":d3.curveLinear, "default":d3.curveStep};
  var y2AxisVariablesList  = graphContainer.y2LineVariableData;
  for(var key in graphContainer.y2LineVariableData) {
    this['y2'+key] = d3.scaleLinear()
           .domain([y2AxisVariablesList[key].min, y2AxisVariablesList[key].max])
           .range([height, 11]);

    this['valueline'+key]  ='';
    width = width;
    padding.right = padding.right + 40;
  }
  
  $this = this;
  // set the ranges
  var x = d3.scaleUtc().range([0, width]);
  // stored for further opertaion of synchline
  xAxisForAllChart[graphContainer.id] = x;
  //for zooming and panning
  var data = graphContainer.data
  var xExtent = d3.extent(data, function(d, i) { return d.Date; });

  var x2 = d3.scaleUtc().range([width, 0]);

  var xOrigScale = d3.scaleUtc()
      .domain([ new Date(xExtent[0]), new Date(xExtent[1]) ])
      .range([0, width]);
        
  var xScale = xOrigScale.copy();
  
  var y = d3.scaleLinear()
            .domain([graphContainer.yAxisData.y1Data.min, graphContainer.yAxisData.y1Data.max])
            .range([height, 11]);
  var line2 = ''; 
  var line1 = '';
  var y2Lines = '';
  var paths = {};
  var lines = {};
  
  Object.keys(typeOfLineChart).forEach(function(daCurve) {
    if(daCurve == lineChartType) {
      line1 = d3.line().curve(typeOfLineChart[lineChartType])
                        .x(function(d) { 
                          return x( Date.parse(d.Date));
                        })
                        .y(function(d) { 
           var line1GraphVariableIdValue = parseFloat(d[this["graphVariableId"]]);
           if(isNaN(line1GraphVariableIdValue)){
            return y(graphContainer.yAxisData.y1Data.min); 
            } else if(line1GraphVariableIdValue < graphContainer.yAxisData.y1Data.min) {
              return y(graphContainer.yAxisData.y1Data.min); 
            }else {
              return y(line1GraphVariableIdValue); 
            }
                        });
         
          for(var key in y2AxisVariablesList) {
            $this['valueline'+key] = d3.line().curve(typeOfLineChart[lineChartType])
              .x(function(d) {  return x( Date.parse(d.Date));  })
              .y(function(d) { 
                var line2GraphVariableIdValue = parseFloat(d[this["graphVariableId"]]);
                if(this['y2lines']  == this["graphVariableId"]) {
                  y2Lines = $this['y2'+this["graphVariableId"]];
                } else {
                  return y(line1GraphVariableIdValue); 
                }
              });
            for(var key in y2AxisVariablesList) {
              $this['valueline'+key] = d3.line().curve(typeOfLineChart[lineChartType])
                                            .x(function(d) {  return x( Date.parse(d.Date));  })
                                            .y(function(d) { 
                                              var line2GraphVariableIdValue = parseFloat(d[this["graphVariableId"]]);
                                              if(this['y2lines']  == this["graphVariableId"]) {
                                                y2Lines = $this['y2'+this["graphVariableId"]];
                                              } else {
                                                y2Lines = $this['y2'+this['y2lines']];
                                              }
                                              
                                              if(isNaN(line2GraphVariableIdValue))
                                              {
                                                return y2Lines(y2AxisVariablesList[this["graphVariableId"]].min); 
                                              } else {
                                                return y2Lines(line2GraphVariableIdValue); 
                                              }
                                            });
            }
          } 
    } 
  });
                         
  // append the svg obgect to the body of the page
  // appends a 'group' element to 'svg'
  // moves the 'group' element to the top left margin
  var svg = d3.select("#"+graphContainer.id).append("svg")
            .attr('class', "graph")
            .attr('width', width + padding.left + padding.right)
            .attr('height', height + padding.bottom + padding.top)
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .attr('mirrorXAxis' , graphContainer.mirrorXAxis)
            .style("padding-left", (padding.left - 30));

  var linesG = svg.append("g")
                    .attr("class", "movingTag")
                    
  var circleG = svg.append("g")
                   .attr("class", "movingCircleTag") 
  // data pass to draw function to plot the lines
  draw(graphContainer.data);

  var getAllGElements = $('#'+graphContainer.id+' svg .movingTag');
  var getAllCircleElements = $('#'+graphContainer.id+' svg .movingCircleTag');

  $.each( getAllGElements, function( i, l ){
    if(lineChartType == 'scatter'){
      moveDown(getAllCircleElements[i],(getAllCircleElements.length -1)- i)
    }else{
      moveDown(getAllGElements[i],(getAllGElements.length -1)- i)
    }
  });
  //MOVE HTML ELEMENT DOWN
  function moveDown(element,index) {
    for (var i = 0; i < index; i++) {
      if(element.nextElementSibling)
      element.parentNode.insertBefore(element.nextElementSibling, element);
    }
  }

  //MOVE HTML ELEMENT UP
  function moveUp(element,index) {
    for (var i = 0; i < index; i++) {
     if(element.previousElementSibling)
      element.parentNode.insertBefore(element, element.previousElementSibling);
    }
  }
    
  function draw(data) {
    // DRAW X AND X2 DOMAIN IN ASCENDING ORDER
    x.domain(d3.extent(data, function(d) { return Date.parse(d.Date); }));
    x2.domain(d3.extent(data, function(d) { return Date.parse(d.Date); }));
    // Scale the range of the data IN DESCENDING ORDER
    if(graphContainer.mirrorXAxis == true) {
      x.domain(d3.extent(data, function(d) { return Date.parse(d.Date); }).reverse());
      x2.domain(d3.extent(data, function(d) { return Date.parse(d.Date); }).reverse()); 
    }
    
    variableslist.forEach(function(variablevalue,key) {
      $this['DataLine'+variablevalue] = [];
      data.forEach(function(datavalue,key) {
       for (var i in datavalue){
        if(variablevalue == i && i != 'Date'){
          t = {'Date':datavalue['Date']};
          t[i] = datavalue[i];
          $this['DataLine'+variablevalue].push(t)
        }
       }
      });
    });

    variableslist.forEach(function(value,key) {
      if(value != 'Date')
      {
        this['graphVariableId'] = value;
        this['y2lines'] = value;
        if(graphContainer.y2AxisVariables.indexOf(value) != -1) {
            plottingLine = $this['valueline'+value];
            yaxisLine = $this['y2'+value];
            if(typeof(graphContainer.y2LineVariableData[value]) == 'undefined') {
              yAxisSameLines = Object.keys(graphContainer.y2LineVariableData);
              plottingLine = $this['valueline'+yAxisSameLines[0]];
              yaxisLine = $this['y2'+yAxisSameLines[0]];
              this['y2lines'] = yAxisSameLines[0];
            } 
         } else { 
          plottingLine = line1;
          yaxisLine = y;
        }
        // lines[value]= line1; 

        // Add the scatterplot on y axis
        if(lineChartType == 'scatter') {
          var Line_chart = svg.append('g').attr('class','movingCircleTag').attr('id','containerId'+graphContainer.containerid+'Circle'+value).selectAll("dot")
              .data($this['DataLine'+value])
              .enter().append("circle")
              .attr("transform", "translate(45,0)")
              .style("fill", graphContainer.colourList[value])
              .attr("r", 2)
              .attr("cx", function(d) {
                return x(Date.parse(d['Date']));})
              .attr("cy", function(d) {  
                  if(typeof(d[value]) == 'undefined') 
                  { // checking whether the variable in of first or secound line
                    if((value).includes(y2AxisVariablesList)) {
                      return  yaxisLine(y2AxisVariablesList[value].min);
                    } else {
                      return yaxisLine(graphContainer.yAxisData.y1Data.min) 
                    }
                  } else{
                    return  yaxisLine(d[value]);
                  }
                })
              // paths['containerId'+graphContainer.containerid+'Circle'+value] = Line_chart;
        } else {
            var Line_chart = linesG.append("path")
               .data([$this['DataLine'+value]]) // Adding separate data for each line
               .attr("id",'containerId'+graphContainer.containerid+'line'+value)
               .attr("class", "line group")
               .attr("transform", "translate(45,0)")
               .style("stroke", graphContainer.colourList[value])
               .attr("d", plottingLine) 

            lines['containerId'+graphContainer.containerid+'line'+value]= plottingLine; 
            paths['containerId'+graphContainer.containerid+'line'+value] = Line_chart;
        }
      }
    });

    var legend = d3.select('#'+graphContainer.legend)
                   .attr("class", "legends sortableLegendList")

    var legenG = legend.selectAll("div")
                       .data(variableslist.map(function(d) {  return d;}))
                       .enter()
                      .append("div")
                       .attr("containerId",graphContainer.containerid)
                       .attr("id", function(d, i) { if(d != "Date") { return graphContainer['id']+d; } })
                       .attr("variableSource", function(d, i) { if(d != "Date") {return d; } })
                       .attr("containerId",function(d, i) { if(d != "Date") {return graphContainer.containerid; } })
                       .append("span");  

    legenG.append("span")
          .attr('class', 'legendColor')
          .attr("x", 0)
          .attr("width", 20)
          .attr("height", 20)
          .style("background-color", function(d, i) { if(d != "Date") {return graphContainer.colourList[d]; } });

    legenG.append("text")
          .attr("x", 25)
          .attr("y", 9.5)
          .attr("dy", "0.32em")
          .attr("id", function(d, i) { if(d != "Date") {return graphContainer.id+d; } })
          .text(function(d, i) { if(d != "Date") { return d; } });
  
    var clipPath = svg.append('clipPath')
        .attr('id', 'clip'+graphContainer.containerid)
        .append('rect')
        .attr('x', 40)
        .attr('y', 0)
        .attr('height', 240)
        .attr('width', 500);

    svg.append("rect")
      .attr("class", "overlay")
      .attr("width", 500)
      .attr("height", 240)
      .style('cursor', 'move')
      .attr('clip-path', 'url(#clip'+graphContainer.containerid+')');
    
    // Add the Y2 Axis
    if(graphContainer.y2Axis == true) {
      var i = 0;
      for(var key in graphContainer.y2LineVariableData) {
          svg.append("g")
             .attr("class", "y2-axis "+key+" axis line")
             .attr("transform", "translate(" + (width + i + 35)  + ",0)")
             .call(d3.axisRight($this['y2'+key]).tickFormat(d3.format("d")).ticks(11).tickSize(0).tickPadding(15));
        i = i+40;
       }
    }

    // Add the X Axis
    var xAxis = svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(45,"+ (height) +")")
                .call(d3.axisBottom(x));

    xAxisData[graphContainer.id] = xAxis
    // Add the Y1 Axis
    var yAxis = svg.append("g")
                   .attr("class", "y-axis axis line")
                   .attr("transform", "translate(45,0)")
                   .call(d3.axisLeft(y).tickFormat(d3.format("d")).tickSize(-width + 5).tickPadding(10));

    yAxisTest[graphContainer.id] = yAxis
  }

  var activeLine = ''
  variableslist.forEach(function(value,key) {
    $("#"+graphContainer.id+value).on("click", function() {
       // Determine if current line is visible
       attributeValue = $(this).attr("id");
       // Check the opacity of line
       var active   = activeLine ? false : true 
         newOpacity = active ? 0 : 1;
       // Hide or show the elements
       d3.select('#containerId'+graphContainer.containerid+'line'+value).style("opacity", newOpacity);
       d3.select('#containerId'+graphContainer.containerid+'Circle'+value).style("opacity", newOpacity);
       // Update whether or not the elements are active
       // Set value for hide and show line
       activeLine = active;
    })
  });

  var zoom = d3.zoom()
        .scaleExtent([1, 10])
        .on('zoom', zoomed);

    svg.call(zoom);

    function zoomed() {
      xScale = d3.event.transform.rescaleX(xOrigScale);
      var xAxis = d3.axisBottom(x)
      xAxisData[graphContainer.id].call(xAxis.scale(xScale));

      var ContainerID = (this.parentNode.id).slice(9, -1)
      
      variableslist.forEach(function(value,key) {
        if(value != 'Date')
        {
          var line = lines['containerId'+ContainerID+'line'+value];
          var path = paths['containerId'+ContainerID+'line'+value];
          path.attr("d", line(data));
          path.attr('clip-path', 'url(#clip'+ContainerID+')');
        }
      });

    }
} 


var jsonData = [{Date: "February, 14 2019 03:35:53 +0530", BCCH: "972"},
                   {Date: "February, 14 2019 03:35:51 +0530", BCCH: "972"},
                   {Date: "February, 14 2019 03:35:50 +0530", BCCH: "972"},
                   {Date: "February, 14 2019 03:35:49 +0530", BCCH: "972", RxLev: "-33"},
                   {Date: "February, 14 2019 03:35:48 +0530", BCCH: "972", RxLev: "-33"},
                   {Date: "February, 14 2019 03:35:47 +0530", BCCH: "972", RxLev: "-33"},
                   {Date: "February, 14 2019 03:35:46 +0530", BCCH: "972", RxLev: "-33"}]
   var graphVariableList = 'BCCH,RxLev';
   var objectname = "linechart";
   var objectId = "linechart4211";
   var containerid = "421";
   var margin = {top: 10, right: 0, bottom: 100, left: 10};
   var padding = {top:10, right:50, bottom: 50, left:50};
   var size =  {height: 300,width: 400};
   var displayY2Variable = false;
   var interval = 10;
   var mirrorXAxis = 1;
   var y1Data = {min: 950, max: 974};
   var colourList = {BCCH: "#1ef25d", RxLev: "#f2911e"};
   var containerDisplayType = "quadratic";
   var y2LineVariableData = {RxLev: {min: -110, max: -20}};
   var y2Line = '';
	 var y2Data = {min: -110, max: -20};
   var y2AxisVariableList = "RxLev";
   var yAxisData = {y1Data, y2Data};
   var thresholdLine = {};
                              
   var graphContainer= {id:objectId,legend:objectId+"Legends", size, margin, padding, yAxisData,data:jsonData,graphVariableList:graphVariableList,colourList, y2Axis:displayY2Variable,y2AxisVariables:y2AxisVariableList,thresholdLine:thresholdLine,containerid:containerid,mirrorXAxis:mirrorXAxis,objectname:objectname,interval:interval,containerDisplayType:containerDisplayType,y2Line:y2Line,y2LineVariableData:y2LineVariableData};
                              
	new lineChart(graphContainer);
.graph .group {
    fill: none;
    stroke: black;
    stroke-width: 1.5;
}

.overlay {
    fill: none;
    pointer-events: all;
}

.graph .axis .tick line {
    stroke: #cbcbcc;
    opacity: 0.3;
    font-size: 1.2em;
}

.graph .axis .domain {
    fill: none;
    stroke: #6c6c75;
    opacity: 0;
    cursor: move;
    pointer-events: all;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.1.0/d3.min.js"></script>
<div class="graph" graphid="linechart4211" containerid="421">
 <div id="linechart4211"></div>
</div>

标签: javascriptjqueryd3.js

解决方案


推荐阅读