Skip to main content

Interactive Building Map

Instructions: hover over sections of the building to see its description

import Konva from 'konva';

function getData() {
  return {
    '1st Floor': {
      color: 'blue',
      points: [366, 298, 500, 284, 499, 204, 352, 183, 72, 228, 74, 274],
    },
    '2nd Floor': {
      color: 'red',
      points: [72, 228, 73, 193, 340, 96, 498, 154, 498, 191, 341, 171],
    },
    '3rd Floor': {
      color: 'yellow',
      points: [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],
    },
    Gym: {
      color: 'green',
      points: [498, 283, 503, 146, 560, 136, 576, 144, 576, 278, 500, 283],
    },
  };
}

function updateTooltip(tooltip, x, y, text) {
  tooltip.getText().text(text);
  tooltip.position({
    x: x,
    y: y,
  });
  tooltip.show();
}

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight,
});

// add background image first
const imageLayer = new Konva.Layer();
stage.add(imageLayer);

Konva.Image.fromURL('https://new.konvajs.org/assets/line-building.png', function (bgImage) {
  bgImage.setAttrs({
    x: 1,
    y: 0,
  });
  imageLayer.add(bgImage);
});

const shapesLayer = new Konva.Layer();
const tooltipLayer = new Konva.Layer();

const tooltip = new Konva.Label({
  opacity: 0.75,
  visible: false,
  listening: false,
});

tooltip.add(
  new Konva.Tag({
    fill: 'black',
    pointerDirection: 'down',
    pointerWidth: 10,
    pointerHeight: 10,
    lineJoin: 'round',
    shadowColor: 'black',
    shadowBlur: 10,
    shadowOffsetX: 10,
    shadowOffsetY: 10,
    shadowOpacity: 0.5,
  })
);

tooltip.add(
  new Konva.Text({
    text: '',
    fontFamily: 'Calibri',
    fontSize: 18,
    padding: 5,
    fill: 'white',
  })
);

tooltipLayer.add(tooltip);

// get areas data
const areas = getData();

// draw areas
for (const key in areas) {
  const area = areas[key];
  const points = area.points;

  const shape = new Konva.Line({
    points: points,
    fill: area.color,
    opacity: 0,
    closed: true,
    name: 'area',
    // custom attr
    key: key,
  });

  shapesLayer.add(shape);
}

// add layers in correct order
stage.add(shapesLayer);
stage.add(tooltipLayer);

stage.on('mouseover', (evt) => {
  const shape = evt.target;
  if (shape && shape.name() === 'area') {  // only change opacity if it's an area shape
    shape.opacity(0.5);
  }
});

stage.on('mouseout', (evt) => {
  const shape = evt.target;
  if (shape && shape.name() === 'area') {  // only change opacity if it's an area shape
    shape.opacity(0);
    tooltip.hide();
  }
});

stage.on('mousemove', (evt) => {
  const shape = evt.target;
  if (shape && shape.name() === 'area') {  // only change opacity if it's an area shape
    const mousePos = stage.getPointerPosition();
    const x = mousePos.x;
    const y = mousePos.y - 5;
    updateTooltip(tooltip, x, y, shape.getAttr('key'));
  }
});