Search code examples
javascriptredundancysimplification

How I can simplify this javascript code? too many switch()


I have the code below. It looks long and complicated and now I have to add some more conditions. Is there any way I can simplify this code.Does javascript offer any other way to do the same thing as a switch? Sorry for the long code listing but I thought I should include everything.

import { CanvasControls } from './CanvasControls.js';
import { Mouse } from './Mouse.js';
import { Pencil } from './Pencil.js';
import { loadImageURL } from './imageLoader.js';
import { Spray } from './Spray.js';
import { ColorPicker } from './ColorPicker.js';
import { Rectangle } from './Rectangle.js';
import { Eraser } from './Eraser.js';




window.onload = () => {
  const canvas = document.querySelector('canvas');
  canvas.style.cursor = 'crosshair';
  const controls = new CanvasControls(canvas.getContext('2d'));
  controls.setOptions({ color: '#008B8B', LineCap: 'butt', LineWidth: 1 });
  const mouse = new Mouse();
  const pencil = new Pencil(controls.context);
  const spray = new Spray(controls.context);
  const colorPicker = new ColorPicker(controls.context);
  const eraser = new Eraser(controls.context);
  let rectangle;
  let sprayInterval;
  let tool = 'PENCIL';

  canvas.addEventListener('mousemove', (event) => {
    event.preventDefault();
    mouse.x = Math.floor(event.clientX - canvas.getBoundingClientRect().left);
    mouse.y = Math.floor(event.clientY - canvas.getBoundingClientRect().top);
  });

  canvas.addEventListener('mousedown', (event) => {
    event.preventDefault();

    switch (tool) {
      case 'PENCIL':
        pencil.startToDraw(mouse.x, mouse.y);
        break;
      case 'SPRAY':
        sprayInterval = setInterval(() => {
          spray.paint(mouse.x, mouse.y);
        }, 35);
        break;
      case 'RECTANGLE':
        rectangle = new Rectangle(controls.context, mouse);
        break;
      case 'COLORPICKER':
        console.log(colorPicker.getPixelColor(mouse.x, mouse.y));
        break;
      case 'ERASER':
        eraser.erase(mouse.x, mouse.y);
        break;
      default:
        break;
    }

    canvas.addEventListener('mousemove', (e) => {
      e.preventDefault();
      switch (tool) {
        case 'PENCIL':
          pencil.drawLine(mouse.x, mouse.y);
          break;
        case 'ERASER':
          eraser.erase(mouse.x, mouse.y);
          break;
        case 'RECTANGLE':
          rectangle.holdIlussion(mouse);
          break;
        default:
          break;
      }
    });
  });

  canvas.addEventListener('mouseup', (event) => {
    event.preventDefault();
    switch (tool) {
      case 'PENCIL':
        pencil.lock();
        break;
      case 'SPRAY':
        clearInterval(sprayInterval);
        break;
      case 'RECTANGLE':
        rectangle.paint();
        break;
      default:
        break;
    }
  });

  const fileInput = document.getElementById('loadfromDisk');
  fileInput.addEventListener('change', (event) => {
    const reader = new FileReader();
    reader.addEventListener('load', () => {
      loadImageURL(canvas.getContext('2d'), reader.result);
    });

    reader.readAsDataURL(event.target.files[0]);
  });
};

Solution

  • You can create an object that holds functions to call for each event.

    var actions = {
        PENCIL: {
            mousedown: () => { pencil.startToDraw(mouse.x, mouse.y); },
            mousemove: () => { pencil.drawLine(mouse.x, mouse.y); },
            mouseup: () => { pencil.lock(); }
        },
        SPRAY: {
            mousedown: () => {
                sprayInterval = setInterval() => {
                  spray.paint(mouse.x, mouse.y);
                }, 35);
            },
            mouseup: () =>  { clearInterval(sprayInterval; }
        },
        ...
    };
    

    Then the event handlers will look like:

    canvas.addEventListener('mousedown', (event) => {
        event.preventDefault();
        var actionToRun = actions[tool].mousedown;
        if (actionToRun) {
            actionToRun();
        };
    }