flatImage()

in pathology/viewer/src/components/ol-tile-viewer/ol-tile-viewer.component.ts [196:312]


  flatImage() {
    if (!this.slideInfo) return;
    const slideInfo = this.slideInfo;
    // Map views always need a projection.  Here we just want to map image
    // coordinates directly to map coordinates, so we create a projection that
    // uses the image extent in pixels.
    const extent =
        [0, 0, this.slideInfo.size.x ?? 1024, this.slideInfo.size.y ?? 968];

    const projection = new Projection({
      code: 'flat-image',
      units: 'pixels',
      extent,
    });

    const imageLoadFunction =
        async (imageWrapper: ImageWrapper, src: string) => {
      const image = imageWrapper.getImage();
      const slideLevelsByZoom = [...slideInfo.levelMap];
      // OpenLayers most zoomed out layer is 0. Reversed of how levelMap
      // stores it.
      const slideLevel: Level = slideLevelsByZoom[0];

      // Frame number is computed by location at X (x+1 for offset), plus number
      // of tiles in previous rows (y*tilesPerWidth).
      const frame = slideLevel.properties[0].frames;
      const instanceUid = slideLevel?.properties[0].instanceUid ?? '';

      const path = (this.slideDescriptor?.id as string) ?? '';

      this.dicomwebService.getEncodedImageTile(path, instanceUid, frame)
          .subscribe((imageData: string) => {
            const imageUrl = this.imageDataToImageUrl(imageData);
            if (image instanceof HTMLImageElement) {
              image.src = imageUrl;
            }
          });
    };

    const flatImageSourceOptions = {
      url: '',
      projection,
      imageExtent: extent,
      imageLoadFunction,
    };

    const initialZoom = 0;
    // The arbitraryMaxZoom can be set to any value, which determines how far in
    // a flat image can be zoomed.
    const arbitraryMaxZoom = 8;
    const flatImageViewOptions = {
      extent,
      constrainOnlyCenter: true,
      center: getCenter(extent),
      zoom: initialZoom,
      minZoom: initialZoom,
      maxZoom: arbitraryMaxZoom,
      projection,
    };
    const flatImageView = new View(flatImageViewOptions);

    const slideOverviewControl = new OverviewMap({
      collapsed: false,
      view: new View(flatImageViewOptions),
      layers: [
        new ImageLayer({
          source: new ImageStatic(flatImageSourceOptions),
        }),
      ],
    });

    const loadedChangeListener =
        slideOverviewControl.getOverviewMap().on('loadend', () => {
          if (loadedChangeListener) {
            unByKey(loadedChangeListener);
          }
          const [, , x, y] = extent;
          this.setOverviewAspectRatio(`${x}/${y}`);
        });

    const flatImageLayer = new ImageLayer<ImageStatic>({
      source: new ImageStatic(flatImageSourceOptions),
      properties: {
        name: 'flat-image-layer',
        title: this.slideInfo?.slideName ?? '',
      }

    });
    if (this.isThumbnail) {
      flatImageView.setMaxZoom(initialZoom);

      this.olMap = new Map({
        layers: [
          flatImageLayer,
        ],
        controls: [],
        interactions: [],
        target: this.olMapContainer.nativeElement,
        view: flatImageView,
      });


    } else {
      this.olMap = new Map({
        layers: [
          flatImageLayer,
        ],
        controls: [slideOverviewControl],
        target: this.olMapContainer.nativeElement,
        view: flatImageView,
      });
    }

    this.olMap?.once('postrender', (event) => {
      this.olMapLoaded.emit(this.olMap!);
    });
  }