如何使用d3绘制连续线而无需单击拖动鼠标,而只是使用鼠标悬停事件?

问题描述 投票:1回答:1

我试图使用d3绘制一条连续的线而不点击鼠标。目前我有这个d3代码,当我点击并移动时可以工作,但是当我只是进入应绘制线条的区域时,它不起作用。我在这里提供了CodePen链接:https://codepen.io/pwill2/pen/NLdJoL

的index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Freehand drawing</title>
    <link rel="stylesheet" href="index.css">
    <script src="http://d3js.org/d3.v3.min.js"></script>
  </head>
  <body>
    <svg id="canvas" width="500px" height="250px"></svg>
    <script src="index.js"></script>
  </body>
</html>

index.css

#canvas {
  background: oldlace;
}
.swatch {
  pointer-events: all;
}
.swatch.active {
  stroke-width: 2px;
  stroke: black;
}
.swatch {
  cursor: pointer;
}
.btn {
  pointer-events: all;

  font-family: FontAwesome;
  fill: #333;
  font-size: 32px;
  text-anchor: middle;

  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.btn:hover {
  fill: black;
  cursor: pointer;
}

.line {
  fill: none;
  stroke-width: 2px;
  stroke-linejoin: round;
  stroke-linecap: round;
}

index.js

(function() {
  var SWATCH_D, active_color, active_line, canvas, drag, drawing_data, lines_layer, palette, redraw, render_line, swatches, trash_btn, ui;

  SWATCH_D = 22;

  render_line = d3.svg.line().x(function(d) {
    return d[0];
  }).y(function(d) {
    return d[1];
  }).interpolate('basis');

  drawing_data = {
    lines: [
      {
        color: "#000000",
        points: []}
    ]
  };

  active_line = null;

  active_color = "#000000";

  canvas = d3.select('#canvas');

  lines_layer = canvas.append('g');

  drag = d3.behavior.drag();

  drag.on('dragstart', function() {
    active_line = {
      points: [],
      color: active_color
    };
    drawing_data.lines.push(active_line);
    return redraw(active_line);
  });

  drag.on('drag', function() {
    active_line.points.push(d3.mouse(this));
    return redraw(active_line);
  });

  drag.on('dragend', function() {
    if (active_line.points.length === 0) {
      drawing_data.lines.pop();
    }
    active_line = null;
    return console.log(drawing_data);
  });

  canvas.call(drag);

  redraw = function(specific_line) {
    var lines;
    lines = lines_layer.selectAll('.line').data(drawing_data.lines);
    lines.enter().append('path').attr({
      "class": 'line',
      stroke: function(d) {
        return d.color;
      }
    }).each(function(d) {
      return d.elem = d3.select(this);
    });
    if (specific_line != null) {
      specific_line.elem.attr({
        d: function(d) {
          return render_line(d.points);
        }
      });
    } else {
      lines.attr({
        d: function(d) {
          return render_line(d.points);
        }
      });
    }
    return lines.exit().remove();
  };

  redraw();

}).call(this);
javascript html5 d3.js dom-events
1个回答
2
投票

为什么不在画布上监听mousemove事件而不是使用拖动,而是按照这种方式将点推送到路径绘制函数。

举个简单的例子:

var points = [];
var canvas = d3.select("body")
   .append("canvas")
   .attr("height",500)
   .attr("width", 600)
   .on("mousemove", addPoint);
      
var context = canvas.node().getContext("2d");
      
function addPoint() {
   points.push(d3.mouse(this));
   draw();
}

function draw() {
  context.clearRect(0,0,600,600);
  context.beginPath();
  context.moveTo(...points[0]);
  points.forEach(function(d) {
    context.lineTo(...d);
  })
  context.lineWidth = 1;
  context.stroke();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

如果你需要在画布上单击鼠标的每个条目后绘制图形,你也可以在点击时分配mousemove监听器(鼠标移除下面的mousemove监听器,所以你可以绘制多行):

var points = [];

var canvas = d3.select("body")
   .append("canvas")
   .attr("height",500)
   .attr("width", 600)
   .on("click", function() {
     points.push([])
     d3.select(this).on("mousemove", addPoint);
   })
   .on("mouseout", function() {
     d3.select(this).on("mousemove",null);
   })
   
      
var context = canvas.node().getContext("2d");
      
function addPoint() {
   points[points.length-1].push(d3.mouse(this));
   draw();
}

function draw() {
  context.clearRect(0,0,600,600);
  points.forEach(function(p) {
    context.beginPath();
    context.moveTo(...p[0]);
    p.forEach(function(d) {
      context.lineTo(...d);
    })
    context.lineWidth = 1;
    context.stroke();
  })
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

如果你想平滑曲线因为手抖动你可以使用d3.line和d3曲线绘制线条:

var points = [];
var canvas = d3.select("body")
   .append("canvas")
   .attr("height",500)
   .attr("width", 600)
   .on("mousemove", addPoint);
      
var context = canvas.node().getContext("2d");

var line = d3.line().context(context)
    .x(function(d) { return d[0]; })
    .y(function(d) { return d[1]; })
    .curve(d3.curveBasis);
      
function addPoint() {
   points.push(d3.mouse(this));
   draw();
}

function draw() {
  context.clearRect(0,0,600,600)
  context.beginPath();
  line(points);  
  context.lineWidth = 1;
  context.stroke();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

虽然你也可以过滤掉数组中的点以获得更平滑的东西(因为鼠标移动添加的点将根据鼠标速度非常接近地添加,使得平滑更难),或者使用不同的d3曲线:

var points = [];
var canvas = d3.select("body")
   .append("canvas")
   .attr("height",500)
   .attr("width", 600)
   .on("mousemove", addPoint);
      
var context = canvas.node().getContext("2d");

var line = d3.line().context(context)
    .x(function(d) { return d[0]; })
    .y(function(d) { return d[1]; })
    .curve(d3.curveBasis);
      
function addPoint() {
   points.push(d3.mouse(this));
   draw();
}

function draw() {
  context.clearRect(0,0,600,600)
  context.beginPath();
  line(points.filter(function(p,i) {
    if(i%8 == 0 || i == points.length-1) return p;
  }));  
  context.lineWidth = 1;
  context.stroke();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.