Predefined annotations
basicviewportannotations
Console
PMA.UI version: 2.43.3
Custom predefined annotations
predefined_annotations.html
1<!doctype >
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