Skip to main content

How to modify line points with anchors?

This demo shows how to create interactive curves (quadratic and Bezier) that can be modified by dragging their anchor points. This technique is commonly used in vector graphic editors and gives users the ability to create and adjust custom curves.

Instructions: Use your mouse or finger to drag and drop the anchor points to modify the curvature of the quadratic curve (red) and the Bezier curve (blue).

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();