ailon / markerjs-live

Display dynamic, interactive, and scalable image annotations in your web apps.
7 stars 1 forks source link

Overlay incorrectly positioned when target image expands to fit available space #4

Closed danielxdam closed 2 years ago

danielxdam commented 2 years ago

This is basically the same issue as #90 in markerjs2.

In my project I need to fit my target image into the remaining available space on the page. What I'm finding is that markerjs-live seems to have difficulty placing the overlay properly because this layout requires the image to be absolutely positioned inside a relatively positioned div.

I've put together a sample html file that demonstrates the behavior:

<html>
  <head>
    <style>
      .header {
        font-size: 5em;
      }
      .container {
        height: 100%;
        display: flex;
        border: 2px solid green;
        flex-direction: column;
      }
      .rest {
        border: 2px solid red;
        box-sizing: border-box;
      }
      .img-container {
        flex: 1;
        position: relative;
      }
      .img-container img {
        margin: auto;
        opacity: 0.5;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      }
    </style>
    <script src="https://unpkg.com/markerjs-live/markerjs-live.js"></script>
  </head>
  <body>
    <div class="container">
      <div class="header">Various header stuff</div>
      <div class="img-container"><img src="Sample-Image-0025.jpg" id="myimg" /></div>
      <div class="rest">This is irrelevant stuff</div>
    </div>
    <script>
      const state = {"width":972,"height":547,"markers":[{"bgColor":"#EF4444","tipPosition":{"x":0,"y":0},"color":"#FFFFFF","fontFamily":"Helvetica, Arial, sans-serif","padding":5,"text":"A note by Bob","left":0,"top":0,"width":0,"height":0,"rotationAngle":0,"visualTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"containerTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"typeName":"CalloutMarker","state":"select"},{"fillColor":"transparent","strokeColor":"#EF4444","strokeWidth":3,"strokeDasharray":"","opacity":1,"left":0,"top":0,"width":0,"height":0,"rotationAngle":0,"visualTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"containerTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"typeName":"EllipseFrameMarker","state":"select"},{"fillColor":"transparent","strokeColor":"#EF4444","strokeWidth":3,"strokeDasharray":"","opacity":1,"left":445,"top":112.46665954589844,"width":75,"height":55,"rotationAngle":0,"visualTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"containerTransformMatrix":{"a":1,"b":0,"c":0,"d":1,"e":0,"f":0},"typeName":"EllipseFrameMarker","state":"select"},{"arrowType":"end","strokeColor":"#EF4444","strokeWidth":3,"strokeDasharray":"","x1":510,"y1":6.4666595458984375,"x2":596,"y2":111.46665954589844,"typeName":"ArrowMarker","state":"select"},{"arrowType":"end","strokeColor":"#EF4444","strokeWidth":3,"strokeDasharray":"","x1":308,"y1":17.466659545898438,"x2":429,"y2":50.46665954589844,"typeName":"ArrowMarker","state":"select"}]}
      const markerView = new mjslive.MarkerView(document.getElementById('myimg'));
      markerView.show(state);
    </script>
  </body>
</html>

image

I was able to correct the positioning problem in my app by sub classing MarkerView and overriding the positionUI and showUI methods as follows:

import * as mjslive from 'markerjs-live';

export class CustomMarkerView extends mjslive.MarkerView {
  positionUI() {
    super.positionUI(...arguments);
    this.correctCoverDivTop();
  }

  showUI() {
    super.showUI(...arguments);
    this.correctCoverDivTop();
  }

  correctCoverDivTop() {
    if (window.getComputedStyle(this.target).getPropertyValue('position') == 'absolute') {
      this.coverDiv.style.top = `${this.target.getClientRects().item(0).y}px`;
    }
  }
}

I'm not sure how well this change works in other layouts or if it's the best solution but it seems to work for my application.

ailon commented 2 years ago

I've replied to the issue in markerjs2 repo with the solution https://github.com/ailon/markerjs2/issues/90

There's a targetRoot property for that scenario.