# Slider-Viewer-Module

This library is using Angular 14, Angular Material 14, ngrx 14 and OpenLayers 6.9.

## Public Api Usage

include in `SlideViewerModule` in your App Module:
```ts 
@NgModule({
 //...
  imports: [
    //...
    /* viewer module */
    SlideViewerModule,
  ],
  //...
})
export class AppModule { }
```


in your template add
```html
<svm-slide-viewer
  [slide]="slide"
  [selectedSlideId]="selectedSlideId"
  [annotationIds]="annotationIds"
  [annotations]="annotations"
  [hideAnnotationIds]="hiddenAnnotations"
  [removeAnnotations]="removedAnnotations"
  [clearAnnotations]="clearViewer"
  [highlightAnnotations]="highlightedAnnotations"
  [focusAnnotation]="focusAnnotation"
  [uiConfig]="uiConfig"
  [interactionType]="interactionType"
  [updateSlideViewer]="updateSlideViewer"
  [clusterDistance]="clusterDistance"
  [annotationCentroidsForClustering]="annotationCentroidsForClustering"
  [allowedInteractionTypes]="allowedInteractionTypes"
  [examinationState]="examinationState"
  (requestAnnotations)="requestAnnotations($event)"
  (annotationAdded)="saveNewAnnotation($event)"
  (annotationHover)="hoverAnnotations($event)"
  (slideMoveEnd)="slideMoved($event)"
  (errorMessage)="onErrorMessage($event)"
  (toolSelected)="toolSelection($event)"
  (hoveredClasses)="hoveredClasses"
  ></svm-slide-viewer>
```


> `svm-slide-viewer` sources are located in [slide-viewer.component.ts](./src/lib/containers/slide-viewer/slide-viewer.component.ts)


in your angular project configuration add stylePreprocessorOptions and include slide-viewer module styles in the include path array

```json
{
  "projects": {
    "slide-viewer-web-demo": {
      // ...
      "architect": {
        "build": {
            // ...
            "stylePreprocessorOptions": {
              "includePaths": [
                "node_modules/slide-viewer/src/lib/styles"
            ]
          },
        }
      }
    }
  }
}
```

finally in your global styles.(s)css file import the slide-viewer lib styles

```scss
@import "slide-viewer-styles.scss";
```

and include the slide viewer theming mixin with your app theme

```scss
@include slide-viewer-module-theme($your-material-theme);
```

the complete styles file *could* look like this: 

```scss
// material theming
@import "~@angular/material/theming";
// slide viewer module
@import "slide-viewer-styles.scss";

// Be sure that you only ever include the mat-core mixin once!
@include mat-core();

$demo-theme-primary: mat-palette($mat-deep-purple);
$demo-theme-accent: mat-palette($mat-amber, A200, A100, A400);

// Create the theme object.
$demo-theme: mat-light-theme(
  (
    color: (
      primary: $demo-theme-primary,
      accent: $demo-theme-accent,
    ),
  )
);

// material theming mixin
@include angular-material-color($demo-theme);
  
// set theme in slide-viewer-module
@include slide-viewer-module-theme($demo-theme);
```



### Inputs

`[slide]`: a single slide of type `Slide` to be shown in viewer. Slide is defined in [slide.ts](./src/lib/models/slide.ts)

`[selectedSlideId]`: a single slide id (`string`) of the current selected slide.

`[annotationIds]`: an array of annotation ids (`string[]`) that are currently in the viewer port.

`[annotations]`: an array of type annotation as defined in [annotation.ts](./src/lib/models/annotation.ts). Annotations will be added to the annotation cache and be drawn on the slide with a blue outline, when all need annotations are loaded.

`[hideAnnotationIds]`: an array of annotation ids (`string[]`) these annotations will not be drawn on the slide.

`[removeAnnotations]`: an array of annotation ids (`string[]`) these will be removed from cache and the slide.

`[clearAnnotations]`: a boolean that indicates to clear all annotations from the slide.

`[highlightAnnotations]`: an array of annotation Ids (`string`) that will be highlighted on the slide in red. Can be used to highlight annotations from the calling App. I.e. Annotations in an list that are currently hovered by the user.

`[focusAnnotation]`: a single annotation id (`string`). The viewer will focus on this annotation. Can be used to implement Zoom to Annotation feature.

`[uiConfig]`: a configuration interface to manipulate certain ui elements. Ui Elements you could configure:
- `showAnnotationbar`: set the annotation toolbar visible or hidden (type: `boolean`, default: `true`).
- `autoSetAnnotationTitle`: generates title with no description for a new created annotation, when set to `true`. Otherwise, a popup for title and description will appear after drawing a new annotation. (type: `boolean`, default: `false`)
- `renderHideNavigationButton`: determines if an additional button to minimize/maximize the navigation panels should be rendered in the slide-viewer next to the annotation bar. The button triggers the `(doubleClicked)` event. (type: `boolean`, default: `false`)

`[updateSlideViewer]`: expects a `number` (e.g. side nav width) that indicates if the viewport has changed and updates the viewer.

`[clusterDistance]`: defines the distance in pixels between clusters as type `number`.

`[annotationCentroidsForClustering]`: the coordinates of the cluster centroids. Expects an 2D Array of type `number`'. For example `[[19184, 1350], [18426, 31729], ...]`

`[interactionType]`: sets the `ToolbarInteractionType` for the viewer. can be of type `InteractionType` (e.g. move or measure) or of type `DrawType` (e.g. rectangle or circle).

`[allowedInteractionTypes]`: sets a white list of active types `ToolbarInteractionType[]` to deactivate all tool items in the navigation toolbar that are not listed.

`[characterConfig]`: a configuration interface to set the maximum character length for the following types:
- `annotation`: sets the character limit for the attributes `name` and `description` e.g. `{ name: 100, description: 1000 }`

`[examinationState]`: a boolean to indicate if the current examination is open or closed.

### Output Events
`(requestAnnotations)`: emits an array of annotation ids which are missing in the cache and must be loaded to be drawn on the slide.

`(annotationAdded)`: emits a `Partial<Annotation>` the user has drawn on the slide with a user defined `name` and `description`. Already contains the slideId of the currently shown slide in the `referenceId` field. `creatorId` and `creatorType` field should be set be the calling App.

`(annotationHover)`: emits a `string[]` with annotation Ids of annotations that the user currently hovers over. Emits an empty `[]`  once if no annotation hovered anymore.
Can be used to i.e highlight annotation in list.

`(annotationClick)`: emits a `string[]` with the clicked annotation ids of annotations the user clicked on.
Nothing will be emitted, if the user clicks on something that isn't an annotation.

`(slideMoveEnd)`: emits a `CurrentView` object containing the current viewport and zoom level of the viewer. `CurrentView` is defined in [ui.ts](./src/lib/models/ui.ts). The Viewport `extent` is defined as OpenLayers Extend (An array of numbers representing an extent: `[minx, miny, maxx, maxy]`). `slideMoveEnd` emits once every time the view changes.

`(errorMessage)`: emits a `string` with an error message, whenever an internal error occurs. Currently an annotation-out-of-bounds-error will occur, whenever a user tries to zoom to or create an annotation that is not within the wsi's extent.

`(doubleClicked)`: emits an empty event (`void`) if the slide itself has been double clicked

`(toolSelected)`: emits the tool the user has selected in the annotation toolbar. Of type `enum ToolbarInteractionType` as defined in [interaction.ts](./src/lib/models/interaction.ts)

`(hoveredClasses)`: emits a `Class[]` of the hovered annotations or `undefined` if the user doesn't hover over an annotation anymore.
 
### CSS Classes 

#### Background of Slide & Overview 

set color of slide viewer & overview map (default is white)
```scss
.svm-slide-background {
  background-color: #ffed8a;
}
```

#### Zoom slider & scale line

Zoom slider & scale line are sharing a flex container. 
The container overlays the whole screen. 

Default alignment of the contained elements is bottom left (flex-end for both main and cross axis)

```scss
.svm-zoom-scale-container{
  flex-direction: column;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: flex-end;
  // other properties omitted
}
```

The elements themselves by default have a 12px margin set. 
Set or reset these values as you need.

```scss
.svm-scale-line {
  margin-right: 4px;
  margin-bottom: 4px;
}

.svm-zoom-slider {
  margin-right: 4px;
  margin-bottom: 4px;
}
```

#### Overview 

The slide overview container is positioned via a flex container. 
The container overlays the whole screen. 
Default postion is top right.
```scss
.svm-overview-container {
  justify-content: flex-end;
  // other properties omitted
}
```

The element itself can be styled via:

```scss
.svm-overview {}
```

#### Toolbar 
The annotation toolbar container is also positioned via a flex container. Default postion is top left.

```scss
.svm-toolbar-container {}
```

The Toolbar has a default margin of 4px. 
The element can be styled via:

```scss
.svm-toolbar {
   margin: 4px;
}
```

## Debugging
if you want to enable logging to console for debug purposes use the `forRoot` configuration method:
```ts
SlideViewerModule.forRoot({ logging: true })
```
if no config is provided via `forRoot` logging defaults to `false`.

## Module Developers

### slide-viewer

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test slide-viewer` to execute the unit tests.
### Code scaffolding

Run `ng generate component component-name --project slide-viewer` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project slide-viewer`.
> Note: Don't forget to add `--project slide-viewer` or else it will be added to the default project in your `angular.json` file. 

### Build

Run `ng build slide-viewer` to build the project. The build artifacts will be stored in the `dist/` directory.
### Watch Mode
`ng build slide-viewer --watch`
