单击刻度线时删除一行 - d3js

时间:2016-02-23 08:34:22

标签: d3.js

我有两个y轴,时间作为数据。 我想在相应的轴上点击刻度时添加和删除一行。 生成线但不确定如何删除线。我尝试使用



var data = [{
	  "inTime": "2013-04-24T00:00:00-05:00",
	  "outTime": "2013-04-24T00:00:00-05:00"
	}, {
	  "inTime": "2013-04-24T00:00:00-05:00",
	  "outTime": "2013-04-24T00:00:00-05:00"
	}, {
	  "inTime": "2013-04-24T00:00:00-05:00",
	  "outTime": "2013-04-24T00:00:00-05:00"
	}, {
	  "inTime": "2013-04-26T00:00:00-05:00",
	  "outTime": "2013-04-26T00:00:00-05:00"
	},
	];

	var margin = {
	    top: 40,
	    right: 40,
	    bottom: 40,
	    left: 40
	  },
	  width = 600,
	  height = 700;

	//Define Left Y axis
	var y = d3.time.scale()
	  .domain([new Date(data[0].inTime), d3.time.day.offset(new Date(data[data.length - 1].inTime), 1)])
	  .rangeRound([0, width - margin.left - margin.right]);

	//Define Right Y axis

	var y1 = d3.time.scale()
	  .domain([new Date(data[1].inTime), d3.time.day.offset(new Date(data[data.length - 1].outTime), 1)])
	  .rangeRound([0, width - margin.left - margin.right]);


	//Left Yaxis attributes
	var yAxis = d3.svg.axis()
	  .scale(y)
	  .orient('left')
	  .tickFormat(d3.time.format('%m/%d %H:%M'))
	  .tickSize(8)
	  .tickPadding(8);


	//Right Yaxis attributes       
	var yAxisRight = d3.svg.axis()
	  .scale(y1)
	  .orient('right')
	  .tickFormat(d3.time.format('%m/%d %H:%M'))
	  .tickSize(8)
	  .tickPadding(8);


	//Create chart
	var svg = d3.select('body').append('svg')
	  .attr('class', 'chart')
	  .attr('width', width)
	  .attr('height', height)
	  .append('g')
	  .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
	


	//Add left Yaxis to group
	svg.append('g')
	  .attr('class', 'y axis')
	  .attr('transform', 'translate(100,   5)')
	  .call(yAxis);

	//Add right Yaxis to group
	svg.append('g')
	  .attr('class', 'x axis')
	  .attr('transform', 'translate(400,   1)')
	  .call(yAxisRight);


	var parse = d3.time.format('%m/%d %H:%M');


	//Function to add a line between two ticks
	function addLine(t1, t2) {
	  var ticks = {};
	  d3.selectAll('.tick text').each(function(d) {
	    ticks[d3.select(this).text()] = this;
	  });

	  var pos1 = ticks[t1].getBoundingClientRect();
	  var pos2 = ticks[t2].getBoundingClientRect();

	  svg.append('line')
	    .attr('x1', pos1.top - pos1.width)
	    .attr('y1', pos1.top + 5)
	    .attr('x2', pos2.left - 5)
	    .attr('y2', pos2.top + 5)
	    .style('stroke', 'black')
	}

	var ticks = svg.selectAll(".tick");
	ticks.attr('class', function(d, i) {
	  return 'ticks' + i;
	}).each(function(d, i) {
	  d3.select(this).append("circle")
	    .attr('id', function(d) {
	      return 'tickCircle' + i;
	    })
	    .attr('class', function(d) {
	      return 'tickCircles' + this.id
	    })
	    .attr("r", 5)
	    .on('click', function(d) {
	    console.log('clicked')
	      return addLineNew(this);
	    })
	    .on('mouseover', function(d){
	          d3.select(this).style('fill','red'); })
	          
	          .on('mouseout', function(d){
	          d3.select(this).style('fill','black'); })
	          });

	ticks.selectAll("line").remove();

	var firstTick;
	var secondTick;
	var secondTickMap={};
	var firstTickMap={};
	var allLines=[];
	//add Line
	function addLineNew(element) {
	  if (firstTick && secondTick) {
	    firstTick = '';
	    secondTick = '';
	  }
	  if (!firstTick || firstTick === '') {
	    firstTick = element.id
	  } 
	  else if ((secondTick != 'undefined' || secondTick === '') && !(secondTick in firstTickMap)) {
	    secondTick = element.id
	  }

	  if (firstTick && secondTick) {
		  
		  if(firstTick == secondTick){
			  if(firstTick in firstTickMap){delete firstTickMap.firstTick;}
			  else if(firstTick in secondTickMap){delete secondTickMap.firstTick;}
			  if(secondTick in firstTickMap){delete firstTickMap.secondTick;}
			  else if(secondTick in secondTickMap ){delete secondTickMap.secondTick;}
		  }
		 if(!(firstTick in firstTickMap) && !(secondTick in secondTickMap) && !(firstTick in secondTickMap) && !(secondTick in firstTickMap))
			 {
		var firstTickBBox = getBBox(firstTick)
	    var secondTickBBox = getBBox(secondTick);
	    var firstTickPos = getCenterPoint(firstTickBBox);
	    var secondTickPos = getCenterPoint(secondTickBBox);
		firstTickMap[firstTick] = firstTick;
		secondTickMap[secondTick] = secondTick;
	    createLine(firstTickPos, secondTickPos)
			 }
			 }
	}
	
	
	//get Center Point
	function getCenterPoint(element) {
	  var thisX = element.left + element.width / 2;
	  var thisY = element.top + element.height / 2;

	  return [thisX, thisY]
	}

	function getBBox(element) {
	  var thisEl = document.getElementById(element).getBoundingClientRect();
	  return thisEl;
	}

	//create a line between pointA and pointB
	function createLine(pointA, pointB) {
	
	  var thisData = {
	    x1: pointA[0],
	    y1: pointA[1],
	    x2: pointB[0],
	    y2: pointB[1]
	  };

	  allLines.push(svg.data([thisData]).append('line')
	    .attr('x1', function(d) {
	    console.log(d)
	      return d.x1;
	    })
	    .attr('y1', function(d) {
	      return d.y1;
	    })
	    .attr('x2', function(d) {
	      return d.x2;
	    })
	    .attr('y2', function(d) {
	      return d.y2;
	    }).style('stroke', 'black')
	    .style('stroke-width','1')
	    .attr('transform', 'translate(' + (-margin.left - 5) + ', ' + (- margin.top - 5) + ')'));
	    
	 
	}




但完全删除了图表。

更详细信息 各轴的刻度之间存在1-1的关系。



<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
&#13;
{{1}}
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

首先让我们澄清一些事情。在创建线条时,将线条数组推送到如下所示的数组:

allLines.push(svg.data([thisData]).append('line')...

这不是正确的方法。最好的方法是,在创建一条线时,将数据线(例如x1,y1,x2,y2等)推送到数组,并使用此数组一次创建所有线。这就是D3的工作方式。

所以我改变了你的功能。

function createLine(pointA, pointB) {

  var thisData = {
    x1: pointA[0],
    y1: pointA[1],
    x2: pointB[0],
    y2: pointB[1]
  };

  allLinesData.push(thisData) //push points into array
  drawLines(allLinesData); //draw all lines at once from 'allLinesData'
}

绘制线条的功能:

function drawLines(data) { //pass the data you want
  var line = svg.selectAll('.line').data(data);

  line.enter().append('line')
    .attr('id', function(d, i) {return 'genLine' + i; })
    .attr('x1', function(d) { return d.x1;})
    .attr('y1', function(d) { return d.y1; })
    .attr('x2', function(d) { return d.x2; })
    .attr('y2', function(d) { return d.y2; })
    .style('stroke', 'black')
    .style('stroke-width', '3')
    .on('mouseover', function(d) { d3.select(this).style('stroke', 'red') })
    .on('mouseout', function(d) { d3.select(this).style('stroke', 'black') })
    .attr('transform', 'translate(' + (-margin.left - 5) + ', ' + (-margin.top - 5) + ')')

  line.on('dblclick', function(d) { //delete line
    var thisLine = this;

    line.each(function(e, i) {
      var thisLine2 = this;
      if (thisLine.id === thisLine2.id) {
        console.log('splice')
          allLinesData.splice(i--, 1); //remove from array you use to feed the line drawer
        d3.select(this).remove(); //remove it from DOM
      }
        })
  })
  line.exit().remove(); //remove unwanted lines

}

还添加了&#39; mouseover&#39;所以你知道你在哪一行。

这是一个工作小提琴:https://jsfiddle.net/reko91/vr09w905/1/

此外,如果你只想在这里:

&#13;
&#13;
var data = [{
  "inTime": "2013-04-24T00:00:00-05:00",
  "outTime": "2013-04-24T00:00:00-05:00"
}, {
  "inTime": "2013-04-24T00:00:00-05:00",
  "outTime": "2013-04-24T00:00:00-05:00"
}, {
  "inTime": "2013-04-24T00:00:00-05:00",
  "outTime": "2013-04-24T00:00:00-05:00"
}, {
  "inTime": "2013-04-26T00:00:00-05:00",
  "outTime": "2013-04-26T00:00:00-05:00"
}, ];

var margin = {
    top: 40,
    right: 40,
    bottom: 40,
    left: 40
  },
  width = 600,
  height = 700;

//Define Left Y axis
var y = d3.time.scale()
  .domain([new Date(data[0].inTime), d3.time.day.offset(new Date(data[data.length - 1].inTime), 1)])
  .rangeRound([0, width - margin.left - margin.right]);

//Define Right Y axis

var y1 = d3.time.scale()
  .domain([new Date(data[1].inTime), d3.time.day.offset(new Date(data[data.length - 1].outTime), 1)])
  .rangeRound([0, width - margin.left - margin.right]);


//Left Yaxis attributes
var yAxis = d3.svg.axis()
  .scale(y)
  .orient('left')
  .tickFormat(d3.time.format('%m/%d %H:%M'))
  .tickSize(8)
  .tickPadding(8);


//Right Yaxis attributes       
var yAxisRight = d3.svg.axis()
  .scale(y1)
  .orient('right')
  .tickFormat(d3.time.format('%m/%d %H:%M'))
  .tickSize(8)
  .tickPadding(8);


//Create chart
var svg = d3.select('body').append('svg')
  .attr('class', 'chart')
  .attr('width', width)
  .attr('height', height)
  .append('g')
  .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');



//Add left Yaxis to group
svg.append('g')
  .attr('class', 'y axis')
  .attr('transform', 'translate(100,   5)')
  .call(yAxis);

//Add right Yaxis to group
svg.append('g')
  .attr('class', 'x axis')
  .attr('transform', 'translate(400,   1)')
  .call(yAxisRight);


var parse = d3.time.format('%m/%d %H:%M');


//Function to add a line between two ticks
function addLine(t1, t2) {
  var ticks = {};
  d3.selectAll('.tick text').each(function(d) {
    ticks[d3.select(this).text()] = this;
  });

  var pos1 = ticks[t1].getBoundingClientRect();
  var pos2 = ticks[t2].getBoundingClientRect();

  svg.append('line')
    .attr('x1', pos1.top - pos1.width)
    .attr('y1', pos1.top + 5)
    .attr('x2', pos2.left - 5)
    .attr('y2', pos2.top + 5)
    .style('stroke', 'black')
}

var ticks = svg.selectAll(".tick");
ticks.attr('class', function(d, i) {
  return 'ticks' + i;
}).each(function(d, i) {
  d3.select(this).append("circle")
    .attr('id', function(d) {
      return 'tickCircle' + i;
    })
    .attr('class', function(d) {
      return 'tickCircles' + this.id
    })
    .attr("r", 5)
    .on('click', function(d) {
      console.log('clicked')
      return addLineNew(this);
    })
    .on('mouseover', function(d) {
      d3.select(this).style('fill', 'red');
    })

  .on('mouseout', function(d) {
    d3.select(this).style('fill', 'black');
  })
});

ticks.selectAll("line").remove();

var firstTick;
var secondTick;
var secondTickMap = {};
var firstTickMap = {};
//var allLines = [];
var allLinesData = [];
//add Line
function addLineNew(element) {
  if (firstTick && secondTick) {
    firstTick = '';
    secondTick = '';
  }
  if (!firstTick || firstTick === '') {
    firstTick = element.id
  } else if ((secondTick != 'undefined' || secondTick === '') && !(secondTick in firstTickMap)) {
    secondTick = element.id
  }

  if (firstTick && secondTick) {

    if (firstTick == secondTick) {
      if (firstTick in firstTickMap) {
        delete firstTickMap.firstTick;
      } else if (firstTick in secondTickMap) {
        delete secondTickMap.firstTick;
      }
      if (secondTick in firstTickMap) {
        delete firstTickMap.secondTick;
      } else if (secondTick in secondTickMap) {
        delete secondTickMap.secondTick;
      }
    }
    if (!(firstTick in firstTickMap) && !(secondTick in secondTickMap) && !(firstTick in secondTickMap) && !(secondTick in firstTickMap)) {
      var firstTickBBox = getBBox(firstTick)
      var secondTickBBox = getBBox(secondTick);
      var firstTickPos = getCenterPoint(firstTickBBox);
      var secondTickPos = getCenterPoint(secondTickBBox);
      firstTickMap[firstTick] = firstTick;
      secondTickMap[secondTick] = secondTick;
      createLine(firstTickPos, secondTickPos)
    }
  }
}


//get Center Point
function getCenterPoint(element) {
  var thisX = element.left + element.width / 2;
  var thisY = element.top + element.height / 2;

  return [thisX, thisY]
}

function getBBox(element) {
  var thisEl = document.getElementById(element).getBoundingClientRect();
  return thisEl;
}

//create a line between pointA and pointB
function createLine(pointA, pointB) {

  var thisData = {
    x1: pointA[0],
    y1: pointA[1],
    x2: pointB[0],
    y2: pointB[1]
  };

  allLinesData.push(thisData) //push points into array
  drawLines(allLinesData); //draw all lines at once from 'allLinesData'
}


function drawLines(data) { //pass the data you want
  var line = svg.selectAll('.line').data(data);

  line.enter().append('line')
    .attr('id', function(d, i) {
      return 'genLine' + i;
    })
    .attr('x1', function(d) {
      return d.x1;
    })
    .attr('y1', function(d) {
      return d.y1;
    })
    .attr('x2', function(d) {
      return d.x2;
    })
    .attr('y2', function(d) {
      return d.y2;
    })
    .style('stroke', 'black')
    .style('stroke-width', '3')
    .on('mouseover', function(d) {
      d3.select(this).style('stroke', 'red')
    })
    .on('mouseout', function(d) {
      d3.select(this).style('stroke', 'black')
    })
    .attr('transform', 'translate(' + (-margin.left - 5) + ', ' + (-margin.top - 5) + ')')

  line.on('dblclick', function(d) { //delete line
    var thisLine = this;

    line.each(function(e, i) {
      var thisLine2 = this;
      if (thisLine.id === thisLine2.id) {
        console.log('splice')
        allLinesData.splice(i--, 1); //remove from array you use to feed the line drawer
        d3.select(this).remove(); //remove it from DOM
      }
    })
  })
  line.exit().remove(); //remove unwanted lines

}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
&#13;
&#13;
&#13;