PMA.UI Examples 2.43.3by Pathomation

Predefined annotations

basicviewportannotations
Console
PMA.UI version: 2.43.3
Custom predefined annotations
predefined_annotations.html
1<!doctype html>
2<html lang="en">
3
4<head>
5    <meta charset="utf-8">
6    <meta http-equiv="X-UA-Compatible" content="IE=10">
7    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
8
9    <!-- Include PMA.UI required libraries downloaded or from CDN -->
10    <script src="./pma.ui/jquery-3.1.0.js"></script>
11    <link href="./pma.ui/font-awesome.min.css" type="text/css" rel="stylesheet">
12
13    <!-- Include optional libraries downloaded or from CDN -->
14    <link rel="stylesheet" href="./pma.ui/bootstrap.min.css">
15    <script src="./pma.ui/bootstrap.bundle.min.js"></script>
16
17    <!-- Include PMA.UI script & css -->
18    <script src="./pma.ui/pma.ui.js"></script>
19    <link href="./pma.ui/pma.ui.css" type="text/css" rel="stylesheet">
20
21    <!-- Include custom script & css -->
22    <script src="./js/predefined_annotations.js"></script>
23    <link href="./css/predefined_annotations.css" type="text/css" rel="stylesheet">
24
25    <title>Predefined Annotations</title>
26
27</head>
28
29<body>
30    <div id="annotations" class="slide">
31        <div class="btn-group btn-group-sm">
32            <button type="button" class="btn btn-primary annotations-button" disabled data-type="tumorArea" title="Compound polygon">
33                <span class="caret">Tumor Area</span>
34            </button>
35            <button type="button" class="btn btn-primary annotations-button" disabled data-type="necrosis" title="Compound polygon">
36                <span class="caret">Necrosis</span>
37            </button>
38            <button type="button" class="btn btn-primary annotations-button" disabled data-type="invasiveMargin" title="Freehand line">
39                <span class="caret">Invasive Margin</span>
40            </button>
41            <button type="button" class="btn btn-primary annotations-button" disabled data-type="bloodVessel" title="Compound polygon">
42                <span class="caret">Blood Vessel</span>
43            </button>
44            <button type="button" class="btn btn-primary annotations-button" disabled data-type="tmaArea" title="Circle">
45                <span class="caret">TMA Area</span>
46            </button>
47        </div>
48
49        <div class="btn-group btn-group-sm" data-toggle="buttons">
50            <button type="button" class="btn btn-primary" disabled data-type="delete" data-type title="Delete">
51                <i class="fa fa-times"></i>
52            </button>
53            <button type="button" class="btn btn-primary" disabled data-type="deleteall" data-type title="Delete all">
54                <i class="fa fa-times-circle"></i>
55            </button>
56            <button type="button" class="btn btn-primary" disabled data-type="save" data-type title="Save">
57                <i class="fa fa-save"></i>
58            </button>
59        </div>
60        <div class="btn-group btn-group-sm">
61            <span class="annotation-helper-icon">
62                <i class="fas fa-spinner fa-spin"></i>
63                <span class="badge bg-success"><i class="fas fa-check"></i> Saved</span>
64                <span class="badge bg-danger"><i class="fas fa-times"></i> Error</span>
65            </span>
66        </div>
67    </div>
68    <div id="viewer"></div>
69</body>
70
71</html>
predefined_annotations.css
1html,
2body {
3    height: 100%;
4    padding: 0px;
5    margin: 0px;
6    overflow: hidden;
7}
8
9body .pma-ui-viewport-container {
10    height: calc(100% - 64px);
11    width: 100%;
12}
13
14button {
15    border: 1px solid lightgrey !important;
16}
17
18.annotations-button {
19    width: 120px;
20}
21
22.annotations-button[data-type="tumorArea"] {
23    background-color: #000000;
24}
25
26.annotations-button[data-type="necrosis"] {
27    background-color: #ff0000;
28}
29
30.annotations-button[data-type="invasiveMargin"] {
31    background-color: #008000;
32}
33
34.annotations-button[data-type="bloodVessel"] {
35    background-color: #ff5733;
36}
37
38.annotations-button[data-type="tmaArea"] {
39    background-color: #0000ff;
40}
41
42
43#viewer {
44    border: 2px solid rgba(0, 60, 136, .5);
45}
46
47.aligned-text {
48    display: inline-block;
49    text-align: right;
50    width: 70px;
51}
52
53.annotation-helper-icon i,
54.annotation-helper-icon span {
55    display: none;
56}
57
58.annotation-helper-icon.loading i {
59    display: initial;
60}
61
62.annotation-helper-icon.loading span {
63    display: none;
64}
65
66.annotation-helper-icon.saved i,
67.annotation-helper-icon.saved span.badge.bg-danger {
68    display: none;
69}
70
71.annotation-helper-icon.saved span.badge.bg-success {
72    display: initial;
73}
74
75.annotation-helper-icon.error i,
76.annotation-helper-icon.error span.badge.bg-success {
77    display: none;
78}
79
80.annotation-helper-icon.error span.badge.bg-danger {
81    display: block;
82}
83
84#annotations {
85    padding: 15px 5px;
86}
87
88.btn-group {
89    padding: 0 5px;
90}
91
92.fa.fa-1x.fa-stack {
93    width: 1em;
94    height: 1em;
95    line-height: 1em;
96}
97
98.fa.fa-1x.fa-stack .fa:last-child {
99    left: 5px;
100    top: 5px;
101    font-size: 8px;
102}
predefined_annotations.js
1var serverUrl = "https://host.pathomation.com/pma.core.3/";
2var imageUrl = "wsiformats/brightfield/3DHistech/CMU-1.mrxs";
3var imageBaseUrl = "https://host.pathomation.com/pma.view/Content/themes/base/Images/";
4var usr = "PMA_UI_demo";
5var pwd = "PMA_UI_demo";
6
7console.log(`PMA.UI version: ${PMA.UI.getVersion()}`);
8
9function drawCommands(type) {
10    if (!type) {
11        return;
12    }
13    switch (type) {
14        case "tumorArea":
15            window.annotationManager.startDrawing({
16                type: "CompoundFreehand",
17                color: "#000000",
18                fillColor: "#00000010",
19                lineThickness: 1,
20                notes: "tumor area"
21            });
22            return;
23        case "necrosis":
24            window.annotationManager.startDrawing({
25                type: "CompoundFreehand",
26                color: "#ff0000",
27                fillColor: "#ff000010",
28                lineThickness: 1,
29                notes: "necrosis"
30            });
31            return;
32        case "invasiveMargin":
33            window.annotationManager.startDrawing({
34                type: "Freehand",
35                color: "#008000",
36                fillColor: "#00800010",
37                lineThickness: 1,
38                notes: "invasive margin"
39            });
40            return;
41        case "bloodVessel":
42            window.annotationManager.startDrawing({
43                type: "CompoundFreehand",
44                color: "#ff5733",
45                fillColor: "#ff573310",
46                lineThickness: 1,
47                notes: "blood vessel"
48            });
49            return;
50        case "tmaArea":
51            window.annotationManager.startDrawing({
52                type: "Circle",
53                color: "#0000ff",
54                fillColor: "#0000ff10",
55                lineThickness: 1,
56                size: [1600, 1600],
57                notes: "tma area"
58            });
59            return;
60    }
61
62    if (type == "delete") {
63        var singleAnnotation = window.annotationManager.getSelection();
64
65        if (singleAnnotation && singleAnnotation.length > 0) {
66            window.annotationManager.deleteAnnotation(singleAnnotation[0].getId());
67        }
68    }
69    else if (type == "deleteall") {
70        var allAnnotations = zuim.mainViewport.getAnnotations();
71
72        for (var i = 0; i < allAnnotations.length; i++) {
73            window.annotationManager.deleteAnnotation(allAnnotations[i].getId());
74        }
75    }
76    else if (type == "save") {
77        saveAnnotations();
78    }
79}
80
81function saveAnnotations(e) {
82    if (e) {
83        var metadata = e.hasOwnProperty("feature") ? e.feature.metaData : (e.hasOwnProperty("length") && e.length !== 0 ? e[0].metaData : null);
84        if (metadata) {
85            metadata.Notes = $("#annotation-text").val() ? $("#annotation-text").val() : " ";
86        }
87    }
88
89    $(".annotation-helper-icon").addClass("loading");
90    window.annotationManager.saveAnnotations();
91}
92
93$(document).ready(function () {
94    $("button[data-type], a[data-type]").click(function (e) {
95        e.preventDefault();
96
97        drawCommands($(this).data("type"));
98    });
99
100    window.context = new PMA.UI.Components.Context({
101        caller: "sdk demo"
102    });
103
104    new PMA.UI.Authentication.AutoLogin(window.context, [{
105        serverUrl: serverUrl,
106        username: usr,
107        password: pwd
108    },]);
109
110    var contextsDict = {};
111
112    window.zuim = new PMA.UI.Components.SlideLoader(window.context, {
113        element: "#viewer",
114        overview: true,
115        channels: {
116            collapsed: true
117        },
118        dimensions: true,
119        filename: false,
120        scaleLine: true,
121        annotationsLayers: false,
122        annotations: {
123            imageBaseUrl: imageBaseUrl,
124            imageScale: 1,
125            labels: false,
126            contexts: null,
127            filter: function (x) {
128                contextsDict[x.Context] = 1;
129                return true;
130            }
131        },
132        colorAdjustments: true,
133        digitalZoomLevels: 2,
134        loadingBar: true,
135        highQuality: true,
136        barcode: {
137            collapsed: true
138        },
139        snapshot: true,
140        theme: "modern",
141        magnifier: false,
142        flip: {
143            horizontally: false,
144            vertically: false,
145        }
146    });
147
148    zuim.listen(PMA.UI.Components.Events.SlideLoaded, function (args) {
149        $("button, input").removeAttr("disabled");
150        $("button[data-type='delete']").attr("disabled", true);
151
152        window.annotationManager = new PMA.UI.Components.Annotations({
153            context: window.context,
154            element: null,
155            viewport: zuim.mainViewport,
156            serverUrl: args.serverUrl,
157            path: args.path,
158            enabled: true
159        });
160
161        window.annotationManager.listen(PMA.UI.Components.Events.AnnotationsSelectionChanged, function (e) {
162            if (e) {
163                $("button[data-type='delete']").attr("disabled", false);
164
165                var metadata = e.hasOwnProperty("feature") ? e.feature.metaData : (e.hasOwnProperty("length") && e.length !== 0 ? e[0].metaData : null);
166                if (metadata) {
167                    $("#annotation-text").val(metadata.Notes);
168                } else {
169                    $("button[data-type='delete']").attr("disabled", true);
170                }
171            }
172        });
173
174        window.annotationManager.listen(PMA.UI.Components.Events.AnnotationAdded, function (e) {
175            e.feature.metaData.Context = "kagelos-test";
176            e.feature.metaData.LayerID = 2;
177            window.annotationManager.setMetadata(e.feature, e.feature.metaData);
178        });
179
180        window.annotationManager.listen(PMA.UI.Components.Events.AnnotationDeleted, function (e) {
181            $("button[data-type='delete']").attr("disabled", true);
182        });
183
184        window.annotationManager.listen(PMA.UI.Components.Events.AnnotationsSaved, function (e) {
185            if (e && e.success) {
186                $(".annotation-helper-icon").removeClass("loading").addClass("saved");
187            } else {
188                $(".annotation-helper-icon").removeClass("loading").addClass("error");
189            }
190
191            setTimeout(function () {
192                $(".annotation-helper-icon").removeClass("loading error saved");
193            }, 1000);
194        });
195    });
196
197    $("body").keydown(function (event) {
198        if (!$(event.target).is('input') && (event.key == "Delete" || event.key == "Del")) {
199            drawCommands("delete");
200        }
201    });
202
203    zuim.load(serverUrl, imageUrl);
204});
205