跳到主要内容

如何使用锚点修改线条的点?

本示例演示如何创建可通过拖动锚点修改的交互式曲线(二次曲线和贝塞尔曲线)。矢量图形编辑器经常使用此技术,让用户可以创建和调整自定义曲线。

操作说明: 使用鼠标或手指拖放锚点,以修改二次曲线(红色)和贝塞尔曲线(蓝色)的曲率。

import Konva from 'konva';

const width = window.innerWidth;
const height = window.innerHeight;

// Create stage and layer
const stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height,
});

const layer = new Konva.Layer();
stage.add(layer);

// Function to build anchor point
function buildAnchor(x, y) {
  const anchor = new Konva.Circle({
    x: x,
    y: y,
    radius: 20,
    stroke: '#666',
    fill: '#ddd',
    strokeWidth: 2,
    draggable: true,
  });
  layer.add(anchor);

  // Add hover styling
  anchor.on('mouseover', function () {
    document.body.style.cursor = 'pointer';
    this.strokeWidth(4);
  });
  
  anchor.on('mouseout', function () {
    document.body.style.cursor = 'default';
    this.strokeWidth(2);
  });

  // Update curves when anchor is moved
  anchor.on('dragmove', function () {
    updateDottedLines();
  });

  return anchor;
}

// Function to update dashed line points (showing control points)
function updateDottedLines() {
  const q = quad;
  const b = bezier;

  const quadLinePath = layer.findOne('#quadLinePath');
  const bezierLinePath = layer.findOne('#bezierLinePath');

  // Update control point lines for quadratic curve
  quadLinePath.points([
    q.start.x(),
    q.start.y(),
    q.control.x(),
    q.control.y(),
    q.end.x(),
    q.end.y(),
  ]);

  // Update control point lines for bezier curve
  bezierLinePath.points([
    b.start.x(),
    b.start.y(),
    b.control1.x(),
    b.control1.y(),
    b.control2.x(),
    b.control2.y(),
    b.end.x(),
    b.end.y(),
  ]);
}

// Create quadratic curve with custom shape
const quadraticLine = new Konva.Shape({
  stroke: 'red',
  strokeWidth: 4,
  sceneFunc: (ctx, shape) => {
    ctx.beginPath();
    ctx.moveTo(quad.start.x(), quad.start.y());
    ctx.quadraticCurveTo(
      quad.control.x(),
      quad.control.y(),
      quad.end.x(),
      quad.end.y()
    );
    ctx.fillStrokeShape(shape);
  },
});
layer.add(quadraticLine);

// Create bezier curve with custom shape
const bezierLine = new Konva.Shape({
  stroke: 'blue',
  strokeWidth: 5,
  sceneFunc: (ctx, shape) => {
    ctx.beginPath();
    ctx.moveTo(bezier.start.x(), bezier.start.y());
    ctx.bezierCurveTo(
      bezier.control1.x(),
      bezier.control1.y(),
      bezier.control2.x(),
      bezier.control2.y(),
      bezier.end.x(),
      bezier.end.y()
    );
    ctx.fillStrokeShape(shape);
  },
});
layer.add(bezierLine);

// Create dashed line to show control points for quadratic curve
const quadLinePath = new Konva.Line({
  dash: [10, 10, 0, 10],
  strokeWidth: 3,
  stroke: 'black',
  lineCap: 'round',
  id: 'quadLinePath',
  opacity: 0.3,
  points: [0, 0],
});
layer.add(quadLinePath);

// Create dashed line to show control points for bezier curve
const bezierLinePath = new Konva.Line({
  dash: [10, 10, 0, 10],
  strokeWidth: 3,
  stroke: 'black',
  lineCap: 'round',
  id: 'bezierLinePath',
  opacity: 0.3,
  points: [0, 0],
});
layer.add(bezierLinePath);

// Create anchor points for the quadratic curve
const quad = {
  start: buildAnchor(60, 30),
  control: buildAnchor(240, 110),
  end: buildAnchor(80, 160),
};

// Create anchor points for the bezier curve
const bezier = {
  start: buildAnchor(280, 20),
  control1: buildAnchor(530, 40),
  control2: buildAnchor(480, 150),
  end: buildAnchor(300, 150),
};

// Update the control point lines
updateDottedLines();