2

I have a simple Konva set up, with a Layer, Rect, and Text.

The canvas scales with the resizing of the window. My goal is for the text to be contained within the canvas, when dragged. At present, it works on the left and top bounds, but not the bottom and right bounds.

What am I doing wrong here?

illustrating gif

https://media.giphy.com/media/fBG0OGhFPwiHUOeGSJ/giphy.gif

code

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import Konva from "konva";
import { Stage, Layer, Text, Rect } from "react-konva";

const CANVAS_INNER_PADDING = 5;

const Container = styled.div`
  width: 50vw;
  height: 50vw;
  background-color: lightgray;
`;

class Canvas extends React.Component {
  constructor(props) {
    super(props);
    this.container = React.createRef();
    this.rect = React.createRef();
    window.addEventListener("resize", this.updateCanvasDimensions);

    this.state = {
      text: {
        value: "hello",
        x: CANVAS_INNER_PADDING,
        y: CANVAS_INNER_PADDING
      },
      canvas: {
        width: 0,
        height: 0,
        color: "red"
      }
    };
  }

  componentDidMount() {
    this.updateCanvasDimensions();
  }

  updateCanvasDimensions = () => {
    const height = this.container.current.clientHeight;
    const width = this.container.current.clientWidth;

    this.setState({
      canvas: { ...this.state.canvas, height, width }
    });
  };

  handleDragMove = e => {
    const { canvas } = this.state;
    const newX = e.target.x();
    const newY = e.target.y();
    let newerX = newX;
    let newerY = newY;

    if (newX < CANVAS_INNER_PADDING) {
      newerX = CANVAS_INNER_PADDING;
    }

    if (newX > canvas.width - CANVAS_INNER_PADDING) {
      newerX = canvas.width - CANVAS_INNER_PADDING;
    }

    if (newY < CANVAS_INNER_PADDING) {
      newerY = CANVAS_INNER_PADDING;
    }

    if (newY > canvas.height - CANVAS_INNER_PADDING) {
      newerY = canvas.height - CANVAS_INNER_PADDING;
    }

    this.setState({
      text: { ...this.state.text, x: newerX, y: newerY }
    });
  };

  handleDragEnd = e => {
    const newX = e.target.x();
    const newY = e.target.y();

    this.setState({
      text: { ...this.state.text, x: newX, y: newY }
    });
  };

  render() {
    const { text, canvas } = this.state;

    return (
      // Have to use `innerRef` with Styled Components.
      <Container innerRef={this.container}>
        <Stage height={canvas.height} width={canvas.width}>
          <Layer>
            <Rect
              ref={this.rect}
              x={0}
              y={0}
              height={canvas.height}
              width={canvas.width}
              fill={canvas.color}
            />
            <Text
              ref={this.text}
              draggable
              onDragMove={this.handleDragMove}
              onDragEnd={this.handleDragEnd}
              text={`${canvas.height}, ${canvas.width}`}
              fill="black"
              x={text.x}
              y={text.y}
            />
          </Layer>
        </Stage>
      </Container>
    );
  }
}

const mapStateToProps = state => ({
  text: state.printState.text,
  canvas: state.printState.canvas
});

const rootElement = document.getElementById("root");
ReactDOM.render(<Canvas />, rootElement);

sandbox

https://codesandbox.io/s/6jnmvzyqmk

Colin Ricardo
  • 16,488
  • 11
  • 47
  • 80

1 Answers1

3

Seem to have solved it, I wasn't taking into account the height / width of the text:

const { canvas } = this.props;
const { textHeight, textWidth } = this.text.current;

const newX = e.target.x();
const newY = e.target.y();
let newerX = newX;
let newerY = newY;

if (newX < CANVAS_INNER_PADDING) {
  newerX = CANVAS_INNER_PADDING;
}

if (newX + textWidth > canvas.width - CANVAS_INNER_PADDING) {
  newerX = canvas.width - CANVAS_INNER_PADDING - textWidth;
}

if (newY < CANVAS_INNER_PADDING) {
  newerY = CANVAS_INNER_PADDING;
}

if (newY + textHeight > canvas.height - CANVAS_INNER_PADDING) {
  newerY = canvas.height - CANVAS_INNER_PADDING - textHeight;
}
Colin Ricardo
  • 16,488
  • 11
  • 47
  • 80
  • 1
    I was about to suggest that you need to consider the width and height of the rect you want to constrain the bounds of, but you found it yourself. Thanks for posting your answer. – Vanquished Wombat Aug 08 '18 at 15:49