Annotations Context
basicviewportannotationscontextfilter
Console
PMA.UI version: 2.43.3
Annotations context filter
annotations_context.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/bootstrap5.min.css">
15 <script src="./pma.ui/bootstrap5.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/annotations_context.js"></script>
23 <link href="./css/annotations_context.css" type="text/css" rel="stylesheet">
24
25 <title>Annotations Context</title>
26</head>
27
28<body>
29 <div class="container-fluid">
30 <div class="row">
31 <div class="col d-flex flex-column vh-100">
32 <div class="row top-row p-1 g-2 align-items-center">
33 <div class="col-auto" style="padding-left: 0px;">
34 <div class="btn-group btn-group-sm">
35 <button type="button" class="btn btn-light" disabled data-action="draw" data-type="Freehand" title="Freehand">
36 <i class="fas fa-pencil-alt"></i>
37 </button>
38 </div>
39 </div>
40 <div class="col-auto">
41 <div class="btn-group btn-group-sm">
42 <button type="button" class="btn btn-secondary" disabled data-action="delete" data-type title="Delete">
43 <i class="fas fa-times"></i>
44 </button>
45 <button type="button" class="btn btn-secondary" disabled data-action="deleteall" data-type title="Delete all">
46 <i class="fas fa-times-circle"></i>
47 </button>
48 <button type="button" class="btn btn-secondary" disabled data-action="save" data-type title="Save">
49 <i class="fas fa-save"></i>
50 </button>
51 </div>
52 </div>
53 <div class="col-auto">
54 <div style="padding-left: 10px;">
55 <label class="custom-control-label" for="context-names">
56 <i class="fa fa-address-book-o"></i> Context:
57 </label>
58 <select name="context-names" id="context-names">
59 <option value="all"><i class="fas fa-font"></i> All</option>
60 <option value="case1"><i class="fas fa-font"></i> Case 1</option>
61 <option value="case2"><i class="fas fa-font"></i> Case 2</option>
62 </select>
63 </div>
64 </div>
65 <div class="col-auto">
66 <div class="form-group mb-0">
67 <div class="col-auto d-flex justify-content-center align-items-center">
68 <span class="annotation-helper-icon">
69 <i class="fas fa-spinner fa-spin"></i>
70 <span class="badge bg-success"><i class="fas fa-check"></i> Saved</span>
71 <span class="badge bg-danger"><i class="fas fa-times"></i> Error</span>
72 </span>
73 </div>
74 </div>
75 </div>
76 </div>
77 <div class="row viewer-row flex-grow-1">
78 <div class="col p-0">
79 <!-- The element that will host the slide loader -->
80 <div id="viewer"></div>
81 </div>
82 </div>
83 </div>
84 </div>
85</body>
86
87</html>
annotations_context.css
1html,
2body {
3 height: 100%;
4 padding: 0px;
5 margin: 0px;
6}
7
8body .pma-ui-viewport-container {
9 height: 100%;
10 width: 100%;
11}
12
13.annotation-helper-icon i,
14.annotation-helper-icon span {
15 display: none;
16}
17
18.annotation-helper-icon.loading i {
19 display: initial;
20}
21
22.annotation-helper-icon.loading span {
23 display: none;
24}
25
26.annotation-helper-icon.saved i,
27.annotation-helper-icon.saved span.badge.bg-danger {
28 display: none;
29}
30
31.annotation-helper-icon.saved span.badge.bg-success {
32 display: initial;
33}
34
35.annotation-helper-icon.error i,
36.annotation-helper-icon.error span.badge.bg-success {
37 display: none;
38}
39
40.annotation-helper-icon.error span.badge.bg-danger {
41 display: block;
42}
43
44.top-row {
45 background-color: #f8f9fa;
46 min-height: 74px;
47}
48
49.btn.btn-light.active {
50 background-color: #d2d2d2;
51}
52
53.btn:disabled {
54 cursor: not-allowed;
55 pointer-events: unset;
56}
annotations_context.js
1var serverUrl = "https://host.pathomation.com/pma.core.3/";
2var serverUsername = "PMA_UI_demo";
3var serverPassword = "PMA_UI_demo";
4var caller = "DemoPortal";
5var imageBaseUrl = "Reference/Annotations/CMU-1/CMU-1.svs";
6var context = null;
7var slideLoader = null;
8var annotationManager = null;
9
10console.log(`PMA.UI version: ${PMA.UI.getVersion()}`);
11
12function drawCommands(action, type) {
13 if (action) {
14 if (action === "draw") {
15 var f = annotationManager.getSelection();
16
17 annotationManager.startDrawing({
18 type: type,
19 color: '#78eb10',
20 fillColor: "rgba(0,0,0,0)",
21 lineThickness: Math.floor(Math.random() * 4) + 1,
22 iconRelativePath: null,
23 feature: type === undefined,
24 notes: $("#annotation-text").val() ? $("#annotation-text").val() : ""
25 });
26 }
27 else if (action === "save") {
28 saveAnnotations();
29 }
30 else if (action === "delete") {
31 var ann = annotationManager.getSelection();
32
33 if (ann && ann.length > 0) {
34 annotationManager.deleteAnnotation(ann[0].getId());
35 }
36 }
37 else if (action === "deleteall") {
38 var allAnnotations = slideLoader.mainViewport.getAnnotations();
39
40 for (var i = 0; i < allAnnotations.length; i++) {
41 annotationManager.deleteAnnotation(allAnnotations[i].getId());
42 }
43 }
44 }
45}
46
47function saveAnnotations() {
48 $(".annotation-helper-icon").addClass("loading");
49 annotationManager.saveAnnotations();
50}
51
52jQuery(function () {
53 $("button[data-action][data-type], a[data-action][data-type]").on("click", function (e) {
54 var shouldReturn = $("button.active").data("type") === $(this).data("type");
55 e.preventDefault();
56
57 if ($("button.active")?.data("action")?.toLowerCase() === "draw") {
58 annotationManager.finishDrawing(false, $("button.active").data("type"));
59 }
60
61 $("button.active").removeClass("active");
62 if (shouldReturn) return;
63
64 drawCommands($(this).data("action"), $(this).data("type"));
65
66 if ($(this).data("type")) {
67 $(this).addClass("active");
68 }
69 });
70
71 $("#context-names").change(function () {
72 let selectedContext = $("#context-names").val();
73
74 if (selectedContext === 'all') {
75 selectedContext = null;
76 }
77
78 slideLoader.setOption("annotations", {
79 imageBaseUrl: imageBaseUrl,
80 imageScale: 1,
81 labels: true,
82 contexts: [selectedContext],
83 });
84
85 slideLoader.load(serverUrl, imageBaseUrl);
86 });
87
88 // Create a context per case selection
89 context = new PMA.UI.Components.Context({ caller: caller });
90
91 // Add an autologin authentication provider
92 new PMA.UI.Authentication.AutoLogin(context, [{ serverUrl: serverUrl, username: serverUsername, password: serverPassword }]);
93
94 // Create an image loader that will allow us to load images easily
95 slideLoader = new PMA.UI.Components.SlideLoader(context, {
96 element: "#viewer",
97 overview: true,
98 channels: {
99 collapsed: true
100 },
101 dimensions: true,
102 filename: false,
103 scaleLine: true,
104 annotations: {
105 imageBaseUrl: imageBaseUrl,
106 imageScale: 1,
107 labels: true,
108 contexts: null,
109 },
110 annotationsLayers: false,
111 colorAdjustments: false,
112 digitalZoomLevels: 2,
113 loadingBar: true,
114 highQuality: true,
115 barcode: {
116 collapsed: true
117 },
118 snapshot: false,
119 theme: "modern",
120 magnifier: false,
121 flip: {
122 horizontally: false,
123 vertically: false,
124 }
125 });
126
127 // Listen for the slide loaded event by the slide loader
128 slideLoader.listen(PMA.UI.Components.Events.SlideLoaded, function (args) {
129 $("button, input").removeAttr("disabled");
130 $("button[data-action='delete']").attr("disabled", true);
131
132 annotationManager = new PMA.UI.Components.Annotations({
133 context: context,
134 element: null,
135 viewport: slideLoader.mainViewport,
136 serverUrl: args.serverUrl,
137 path: args.path,
138 enabled: true
139 });
140
141 window.annotationManager.listen(PMA.UI.Components.Events.AnnotationsSelectionChanged, function (e) {
142 if (e) {
143 $("button[data-action='delete']").attr("disabled", false);
144
145 var metadata = e.hasOwnProperty("feature") ? e.feature.metaData : (e.hasOwnProperty("length") && e.length !== 0 ? e[0].metaData : null);
146 if (metadata) {
147 $("#annotation-text").val(metadata.Notes);
148 } else {
149 $("button[data-action='delete']").attr("disabled", true);
150 }
151 }
152 });
153
154 annotationManager.listen(PMA.UI.Components.Events.AnnotationAdded, function (e) {
155 let selectedContext = $("#context-names").val();
156
157 if (selectedContext === 'all') {
158 return;
159 }
160
161 e.feature.metaData.Context = selectedContext;
162 });
163
164 window.annotationManager.listen(PMA.UI.Components.Events.AnnotationDeleted, function (e) {
165 $("button[data-action='delete']").attr("disabled", true);
166 });
167
168 annotationManager.listen(PMA.UI.Components.Events.AnnotationsSaved, function (e) {
169 if (e && e.success) {
170 $(".annotation-helper-icon").removeClass("loading").addClass("saved");
171 }
172 else {
173 $(".annotation-helper-icon").removeClass("loading").addClass("error");
174 }
175
176 $("button[data-action=save][data-type]").removeClass("active");
177
178 setTimeout(function () {
179 $(".annotation-helper-icon").removeClass("loading error saved");
180 }, 1000);
181 });
182 });
183
184 $("body").keydown(function (event) {
185 if (!$(event.target).is('input') && (event.key == "Delete" || event.key == "Del")) {
186 drawCommands("delete", null);
187 }
188 });
189
190 // Load the image with the context
191 slideLoader.load(serverUrl, imageBaseUrl);
192});