Draggable Canvas With Redux

by Peter Jang

HTML

<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<body>
  <canvas></canvas>
</body>

CSS

canvas {
  background: lightgray;
}

JavaScript

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");

var initialState = {
  canvas: { x: 0, y: 0 },
  items: [
    { x: 10, y: 10, width: 50, height: 50, color: 'red' },
    { x: 30, y: 30, width: 50, height: 50, color: 'blue' }
  ],
  xDragging: null,
  yDragging: null
};

var reducer = function(state, action) {
  if (typeof state === 'undefined') {
    return initialState;
  }
  switch (action.type) {
    case 'TRANSLATE_CANVAS_START':
      return {
        canvas: state.canvas,
        items: state.items,
        xDragging: action.xDragging,
        yDragging: action.yDragging
      };
    case 'TRANSLATE_CANVAS':
      return {
        canvas: {
          x: state.canvas.x + action.xDragging - state.xDragging,
          y: state.canvas.y + action.yDragging - state.yDragging
        },
        items: state.items,
        xDragging: action.xDragging,
        yDragging: action.yDragging
      };
    case 'TRANSLATE_CANVAS_END':
      return {
        canvas: state.canvas,
        items: state.items,
        xDragging: null,
        yDragging: null
      };
    default:
      return state;
  }
};

var draw = function() {
  var state = store.getState();
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.setTransform(1, 0, 0, 1, state.canvas.x, state.canvas.y);
  state.items.forEach(function(item) {
    ctx.fillStyle = item.color;
    ctx.fillRect(item.x, item.y, item.width, item.height);
  });
};

var store = Redux.createStore(reducer);
store.subscribe(draw);

canvas.addEventListener('mousedown', function(event) {
  store.dispatch({
    type: 'TRANSLATE_CANVAS_START',
    xDragging: event.offsetX,
    yDragging: event.offsetY
  });
}, false);

canvas.addEventListener('mousemove', function(event) {
  var state = store.getState();
  if (state.xDragging !== null && state.yDragging !== null) {
    store.dispatch({
      type: 'TRANSLATE_CANVAS',
      xDragging: event.offsetX,
      yDragging:...