med-viewer-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -0
- package/dist/adapters/vue/MedViewer.d.ts +17 -0
- package/dist/adapters/vue/index.d.ts +2 -0
- package/dist/core/AnnoAnnotator.d.ts +15 -0
- package/dist/core/BaseAnnotator.d.ts +33 -0
- package/dist/core/ColorAdjustPlugin.d.ts +29 -0
- package/dist/core/Coords.d.ts +6 -0
- package/dist/core/Engine.d.ts +57 -0
- package/dist/core/KonvaAnnotator.d.ts +36 -0
- package/dist/core/Scalebar.d.ts +42 -0
- package/dist/core/SelectionPlugin.d.ts +102 -0
- package/dist/core/Toolbar.d.ts +32 -0
- package/dist/med-viewer-sdk.d.ts +6 -0
- package/dist/med-viewer-sdk.mjs +14248 -0
- package/dist/med-viewer-sdk.umd.js +2 -0
- package/dist/style.css +1 -0
- package/package.json +34 -0
- package/src/adapters/vue/MedViewer.ts +37 -0
- package/src/adapters/vue/index.ts +4 -0
- package/src/assets/icons/button_grouphover.png +0 -0
- package/src/assets/icons/button_hover.png +0 -0
- package/src/assets/icons/button_pressed.png +0 -0
- package/src/assets/icons/button_rest.png +0 -0
- package/src/assets/icons/flip_grouphover.png +0 -0
- package/src/assets/icons/flip_hover.png +0 -0
- package/src/assets/icons/flip_pressed.png +0 -0
- package/src/assets/icons/flip_rest.png +0 -0
- package/src/assets/icons/fullpage_grouphover.png +0 -0
- package/src/assets/icons/fullpage_hover.png +0 -0
- package/src/assets/icons/fullpage_pressed.png +0 -0
- package/src/assets/icons/fullpage_rest.png +0 -0
- package/src/assets/icons/home_grouphover.png +0 -0
- package/src/assets/icons/home_hover.png +0 -0
- package/src/assets/icons/home_pressed.png +0 -0
- package/src/assets/icons/home_rest.png +0 -0
- package/src/assets/icons/next_grouphover.png +0 -0
- package/src/assets/icons/next_hover.png +0 -0
- package/src/assets/icons/next_pressed.png +0 -0
- package/src/assets/icons/next_rest.png +0 -0
- package/src/assets/icons/previous_grouphover.png +0 -0
- package/src/assets/icons/previous_hover.png +0 -0
- package/src/assets/icons/previous_pressed.png +0 -0
- package/src/assets/icons/previous_rest.png +0 -0
- package/src/assets/icons/rotateleft_grouphover.png +0 -0
- package/src/assets/icons/rotateleft_hover.png +0 -0
- package/src/assets/icons/rotateleft_pressed.png +0 -0
- package/src/assets/icons/rotateleft_rest.png +0 -0
- package/src/assets/icons/rotateright_grouphover.png +0 -0
- package/src/assets/icons/rotateright_hover.png +0 -0
- package/src/assets/icons/rotateright_pressed.png +0 -0
- package/src/assets/icons/rotateright_rest.png +0 -0
- package/src/assets/icons/selection_cancel_grouphover.png +0 -0
- package/src/assets/icons/selection_cancel_hover.png +0 -0
- package/src/assets/icons/selection_cancel_pressed.png +0 -0
- package/src/assets/icons/selection_cancel_rest.png +0 -0
- package/src/assets/icons/selection_confirm_grouphover.png +0 -0
- package/src/assets/icons/selection_confirm_hover.png +0 -0
- package/src/assets/icons/selection_confirm_pressed.png +0 -0
- package/src/assets/icons/selection_confirm_rest.png +0 -0
- package/src/assets/icons/selection_grouphover.png +0 -0
- package/src/assets/icons/selection_hover.png +0 -0
- package/src/assets/icons/selection_pressed.png +0 -0
- package/src/assets/icons/selection_rest.png +0 -0
- package/src/assets/icons/tool_anno.png +0 -0
- package/src/assets/icons/tool_selection.png +0 -0
- package/src/assets/icons/zoomin_grouphover.png +0 -0
- package/src/assets/icons/zoomin_hover.png +0 -0
- package/src/assets/icons/zoomin_pressed.png +0 -0
- package/src/assets/icons/zoomin_rest.png +0 -0
- package/src/assets/icons/zoomout_grouphover.png +0 -0
- package/src/assets/icons/zoomout_hover.png +0 -0
- package/src/assets/icons/zoomout_pressed.png +0 -0
- package/src/assets/icons/zoomout_rest.png +0 -0
- package/src/core/AnnoAnnotator.ts +102 -0
- package/src/core/BaseAnnotator.ts +43 -0
- package/src/core/ColorAdjustPlugin.ts +256 -0
- package/src/core/Coords.ts +9 -0
- package/src/core/Engine.ts +246 -0
- package/src/core/KonvaAnnotator.ts +185 -0
- package/src/core/Scalebar.ts +87 -0
- package/src/core/SelectionPlugin.ts +252 -0
- package/src/core/Toolbar.ts +370 -0
- package/src/index.ts +21 -0
- package/src/plugins/ShapeLabelsFormatter.js +435 -0
- package/src/plugins/openseadragon-scalebar.js +592 -0
- package/src/plugins/openseadragon-selection.js +657 -0
- package/src/types/type.d.ts +9 -0
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import OpenSeadragon from "openseadragon";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* This software was developed at the National Institute of Standards and
|
|
5
|
+
* Technology by employees of the Federal Government in the course of
|
|
6
|
+
* their official duties. Pursuant to title 17 Section 105 of the United
|
|
7
|
+
* States Code this software is not subject to copyright protection and is
|
|
8
|
+
* in the public domain. This software is an experimental system. NIST assumes
|
|
9
|
+
* no responsibility whatsoever for its use by other parties, and makes no
|
|
10
|
+
* guarantees, expressed or implied, about its quality, reliability, or
|
|
11
|
+
* any other characteristic. We would appreciate acknowledgement if the
|
|
12
|
+
* software is used.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @author Antoine Vandecreme <antoine.vandecreme@nist.gov>
|
|
18
|
+
*/
|
|
19
|
+
(function ($) {
|
|
20
|
+
if (!$.version || $.version.major < 2) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"This version of OpenSeadragonScalebar requires " +
|
|
23
|
+
"OpenSeadragon version 2.0.0+"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
$.Viewer.prototype.scalebar = function (options) {
|
|
28
|
+
if (!this.scalebarInstance) {
|
|
29
|
+
options = options || {};
|
|
30
|
+
options.viewer = this;
|
|
31
|
+
this.scalebarInstance = new $.Scalebar(options);
|
|
32
|
+
} else {
|
|
33
|
+
this.scalebarInstance.refresh(options);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
$.ScalebarType = {
|
|
38
|
+
NONE: 0,
|
|
39
|
+
MICROSCOPY: 1,
|
|
40
|
+
MAP: 2,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
$.ScalebarLocation = {
|
|
44
|
+
NONE: 0,
|
|
45
|
+
TOP_LEFT: 1,
|
|
46
|
+
TOP_RIGHT: 2,
|
|
47
|
+
BOTTOM_RIGHT: 3,
|
|
48
|
+
BOTTOM_LEFT: 4,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @class Scalebar
|
|
54
|
+
* @param {Object} options
|
|
55
|
+
* @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this
|
|
56
|
+
* Scalebar to.
|
|
57
|
+
* @param {OpenSeadragon.ScalebarType} options.type The scale bar type.
|
|
58
|
+
* Default: microscopy
|
|
59
|
+
* @param {Integer} options.pixelsPerMeter The pixels per meter of the
|
|
60
|
+
* zoomable image at the original image size. If null, the scale bar is not
|
|
61
|
+
* displayed. default: null
|
|
62
|
+
* @param {Integer} options.referenceItemIdx Specify the item from
|
|
63
|
+
* viewer.world to which options.pixelsPerMeter is refering.
|
|
64
|
+
* default: 0
|
|
65
|
+
* @param (String} options.minWidth The minimal width of the scale bar as a
|
|
66
|
+
* CSS string (ex: 100px, 1em, 1% etc...) default: 150px
|
|
67
|
+
* @param {OpenSeadragon.ScalebarLocation} options.location The location
|
|
68
|
+
* of the scale bar inside the viewer. default: bottom left
|
|
69
|
+
* @param {Integer} options.xOffset Offset location of the scale bar along x.
|
|
70
|
+
* default: 5
|
|
71
|
+
* @param {Integer} options.yOffset Offset location of the scale bar along y.
|
|
72
|
+
* default: 5
|
|
73
|
+
* @param {Boolean} options.stayInsideImage When set to true, keep the
|
|
74
|
+
* scale bar inside the image when zooming out. default: true
|
|
75
|
+
* @param {String} options.color The color of the scale bar using a color
|
|
76
|
+
* name or the hexadecimal format (ex: black or #000000) default: black
|
|
77
|
+
* @param {String} options.fontColor The font color. default: black
|
|
78
|
+
* @param {String} options.backgroundColor The background color. default: none
|
|
79
|
+
* @param {String} options.fontSize The font size. default: not set
|
|
80
|
+
* @param {String} options.fontFamily The font-family. default: not set
|
|
81
|
+
* @param {String} options.barThickness The thickness of the scale bar in px.
|
|
82
|
+
* default: 2
|
|
83
|
+
* @param {function} options.sizeAndTextRenderer A function which will be
|
|
84
|
+
* called to determine the size of the scale bar and it's text content.
|
|
85
|
+
* The function must have 2 parameters: the PPM at the current zoom level
|
|
86
|
+
* and the minimum size of the scale bar. It must return an object containing
|
|
87
|
+
* 2 attributes: size and text containing the size of the scale bar and the text.
|
|
88
|
+
* default: $.ScalebarSizeAndTextRenderer.METRIC_LENGTH
|
|
89
|
+
*/
|
|
90
|
+
$.Scalebar = function (options) {
|
|
91
|
+
options = options || {};
|
|
92
|
+
if (!options.viewer) {
|
|
93
|
+
throw new Error("A viewer must be specified.");
|
|
94
|
+
}
|
|
95
|
+
this.viewer = options.viewer;
|
|
96
|
+
|
|
97
|
+
this.divElt = document.createElement("div");
|
|
98
|
+
this.viewer.container.appendChild(this.divElt);
|
|
99
|
+
this.divElt.style.position = "relative";
|
|
100
|
+
this.divElt.style.margin = "0";
|
|
101
|
+
this.divElt.style.pointerEvents = "none";
|
|
102
|
+
|
|
103
|
+
this.setMinWidth(options.minWidth || "150px");
|
|
104
|
+
|
|
105
|
+
this.setDrawScalebarFunction(options.type || $.ScalebarType.MICROSCOPY);
|
|
106
|
+
this.color = options.color || "black";
|
|
107
|
+
this.fontColor = options.fontColor || "black";
|
|
108
|
+
this.backgroundColor = options.backgroundColor || "none";
|
|
109
|
+
this.fontSize = options.fontSize || "";
|
|
110
|
+
this.fontFamily = options.fontFamily || "";
|
|
111
|
+
this.barThickness = options.barThickness || 2;
|
|
112
|
+
this.pixelsPerMeter = options.pixelsPerMeter || null;
|
|
113
|
+
this.referenceItemIdx = options.referenceItemIdx || 0;
|
|
114
|
+
this.location = options.location || $.ScalebarLocation.BOTTOM_LEFT;
|
|
115
|
+
this.xOffset = options.xOffset || 5;
|
|
116
|
+
this.yOffset = options.yOffset || 5;
|
|
117
|
+
this.stayInsideImage = isDefined(options.stayInsideImage)
|
|
118
|
+
? options.stayInsideImage
|
|
119
|
+
: true;
|
|
120
|
+
this.sizeAndTextRenderer =
|
|
121
|
+
options.sizeAndTextRenderer ||
|
|
122
|
+
$.ScalebarSizeAndTextRenderer.METRIC_LENGTH;
|
|
123
|
+
|
|
124
|
+
var self = this;
|
|
125
|
+
this.viewer.addHandler("open", function () {
|
|
126
|
+
self.refresh();
|
|
127
|
+
});
|
|
128
|
+
this.viewer.addHandler("animation", function () {
|
|
129
|
+
self.refresh();
|
|
130
|
+
});
|
|
131
|
+
this.viewer.addHandler("resize", function () {
|
|
132
|
+
self.refresh();
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
$.Scalebar.prototype = {
|
|
137
|
+
updateOptions: function (options) {
|
|
138
|
+
if (!options) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (isDefined(options.type)) {
|
|
142
|
+
this.setDrawScalebarFunction(options.type);
|
|
143
|
+
}
|
|
144
|
+
if (isDefined(options.minWidth)) {
|
|
145
|
+
this.setMinWidth(options.minWidth);
|
|
146
|
+
}
|
|
147
|
+
if (isDefined(options.color)) {
|
|
148
|
+
this.color = options.color;
|
|
149
|
+
}
|
|
150
|
+
if (isDefined(options.fontColor)) {
|
|
151
|
+
this.fontColor = options.fontColor;
|
|
152
|
+
}
|
|
153
|
+
if (isDefined(options.backgroundColor)) {
|
|
154
|
+
this.backgroundColor = options.backgroundColor;
|
|
155
|
+
}
|
|
156
|
+
if (isDefined(options.fontSize)) {
|
|
157
|
+
this.fontSize = options.fontSize;
|
|
158
|
+
}
|
|
159
|
+
if (isDefined(options.fontFamily)) {
|
|
160
|
+
this.fontFamily = options.fontFamily;
|
|
161
|
+
}
|
|
162
|
+
if (isDefined(options.barThickness)) {
|
|
163
|
+
this.barThickness = options.barThickness;
|
|
164
|
+
}
|
|
165
|
+
if (isDefined(options.pixelsPerMeter)) {
|
|
166
|
+
this.pixelsPerMeter = options.pixelsPerMeter;
|
|
167
|
+
}
|
|
168
|
+
if (isDefined(options.referenceItemIdx)) {
|
|
169
|
+
this.referenceItemIdx = options.referenceItemIdx;
|
|
170
|
+
}
|
|
171
|
+
if (isDefined(options.location)) {
|
|
172
|
+
this.location = options.location;
|
|
173
|
+
}
|
|
174
|
+
if (isDefined(options.xOffset)) {
|
|
175
|
+
this.xOffset = options.xOffset;
|
|
176
|
+
}
|
|
177
|
+
if (isDefined(options.yOffset)) {
|
|
178
|
+
this.yOffset = options.yOffset;
|
|
179
|
+
}
|
|
180
|
+
if (isDefined(options.stayInsideImage)) {
|
|
181
|
+
this.stayInsideImage = options.stayInsideImage;
|
|
182
|
+
}
|
|
183
|
+
if (isDefined(options.sizeAndTextRenderer)) {
|
|
184
|
+
this.sizeAndTextRenderer = options.sizeAndTextRenderer;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
setDrawScalebarFunction: function (type) {
|
|
188
|
+
if (!type) {
|
|
189
|
+
this.drawScalebar = null;
|
|
190
|
+
} else if (type === $.ScalebarType.MAP) {
|
|
191
|
+
this.drawScalebar = this.drawMapScalebar;
|
|
192
|
+
} else {
|
|
193
|
+
this.drawScalebar = this.drawMicroscopyScalebar;
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
setMinWidth: function (minWidth) {
|
|
197
|
+
this.divElt.style.width = minWidth;
|
|
198
|
+
// Make sure to display the element before getting is width
|
|
199
|
+
this.divElt.style.display = "";
|
|
200
|
+
this.minWidth = this.divElt.offsetWidth;
|
|
201
|
+
},
|
|
202
|
+
/**
|
|
203
|
+
* Refresh the scalebar with the options submitted.
|
|
204
|
+
* @param {Object} options
|
|
205
|
+
* @param {OpenSeadragon.ScalebarType} options.type The scale bar type.
|
|
206
|
+
* Default: microscopy
|
|
207
|
+
* @param {Integer} options.pixelsPerMeter The pixels per meter of the
|
|
208
|
+
* zoomable image at the original image size. If null, the scale bar is not
|
|
209
|
+
* displayed. default: null
|
|
210
|
+
* @param {Integer} options.referenceItemIdx Specify the item from
|
|
211
|
+
* viewer.world to which options.pixelsPerMeter is refering.
|
|
212
|
+
* default: 0
|
|
213
|
+
* @param (String} options.minWidth The minimal width of the scale bar as a
|
|
214
|
+
* CSS string (ex: 100px, 1em, 1% etc...) default: 150px
|
|
215
|
+
* @param {OpenSeadragon.ScalebarLocation} options.location The location
|
|
216
|
+
* of the scale bar inside the viewer. default: bottom left
|
|
217
|
+
* @param {Integer} options.xOffset Offset location of the scale bar along x.
|
|
218
|
+
* default: 5
|
|
219
|
+
* @param {Integer} options.yOffset Offset location of the scale bar along y.
|
|
220
|
+
* default: 5
|
|
221
|
+
* @param {Boolean} options.stayInsideImage When set to true, keep the
|
|
222
|
+
* scale bar inside the image when zooming out. default: true
|
|
223
|
+
* @param {String} options.color The color of the scale bar using a color
|
|
224
|
+
* name or the hexadecimal format (ex: black or #000000) default: black
|
|
225
|
+
* @param {String} options.fontColor The font color. default: black
|
|
226
|
+
* @param {String} options.backgroundColor The background color. default: none
|
|
227
|
+
* @param {String} options.fontSize The font size. default: not set
|
|
228
|
+
* @param {String} options.barThickness The thickness of the scale bar in px.
|
|
229
|
+
* default: 2
|
|
230
|
+
* @param {function} options.sizeAndTextRenderer A function which will be
|
|
231
|
+
* called to determine the size of the scale bar and it's text content.
|
|
232
|
+
* The function must have 2 parameters: the PPM at the current zoom level
|
|
233
|
+
* and the minimum size of the scale bar. It must return an object containing
|
|
234
|
+
* 2 attributes: size and text containing the size of the scale bar and the text.
|
|
235
|
+
* default: $.ScalebarSizeAndTextRenderer.METRIC_LENGTH
|
|
236
|
+
*/
|
|
237
|
+
refresh: function (options) {
|
|
238
|
+
this.updateOptions(options);
|
|
239
|
+
|
|
240
|
+
if (
|
|
241
|
+
!this.viewer.isOpen() ||
|
|
242
|
+
!this.drawScalebar ||
|
|
243
|
+
!this.pixelsPerMeter ||
|
|
244
|
+
!this.location
|
|
245
|
+
) {
|
|
246
|
+
this.divElt.style.display = "none";
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
this.divElt.style.display = "";
|
|
250
|
+
|
|
251
|
+
var viewport = this.viewer.viewport;
|
|
252
|
+
var tiledImage = this.viewer.world.getItemAt(this.referenceItemIdx);
|
|
253
|
+
var zoom = tiledImageViewportToImageZoom(
|
|
254
|
+
tiledImage,
|
|
255
|
+
viewport.getZoom(true)
|
|
256
|
+
);
|
|
257
|
+
var currentPPM = zoom * this.pixelsPerMeter;
|
|
258
|
+
var props = this.sizeAndTextRenderer(currentPPM, this.minWidth);
|
|
259
|
+
|
|
260
|
+
this.drawScalebar(props.size, props.text);
|
|
261
|
+
var location = this.getScalebarLocation();
|
|
262
|
+
this.divElt.style.left = location.x + "px";
|
|
263
|
+
this.divElt.style.top = location.y + "px";
|
|
264
|
+
},
|
|
265
|
+
drawMicroscopyScalebar: function (size, text) {
|
|
266
|
+
this.divElt.style.fontSize = this.fontSize;
|
|
267
|
+
this.divElt.style.fontFamily = this.fontFamily;
|
|
268
|
+
this.divElt.style.textAlign = "center";
|
|
269
|
+
this.divElt.style.color = this.fontColor;
|
|
270
|
+
this.divElt.style.border = "none";
|
|
271
|
+
this.divElt.style.borderBottom =
|
|
272
|
+
this.barThickness + "px solid " + this.color;
|
|
273
|
+
this.divElt.style.backgroundColor = this.backgroundColor;
|
|
274
|
+
this.divElt.innerHTML = text;
|
|
275
|
+
this.divElt.style.width = size + "px";
|
|
276
|
+
},
|
|
277
|
+
drawMapScalebar: function (size, text) {
|
|
278
|
+
this.divElt.style.fontSize = this.fontSize;
|
|
279
|
+
this.divElt.style.fontFamily = this.fontFamily;
|
|
280
|
+
this.divElt.style.textAlign = "center";
|
|
281
|
+
this.divElt.style.color = this.fontColor;
|
|
282
|
+
this.divElt.style.border = this.barThickness + "px solid " + this.color;
|
|
283
|
+
this.divElt.style.borderTop = "none";
|
|
284
|
+
this.divElt.style.backgroundColor = this.backgroundColor;
|
|
285
|
+
this.divElt.innerHTML = text;
|
|
286
|
+
this.divElt.style.width = size + "px";
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* Compute the location of the scale bar.
|
|
290
|
+
* @returns {OpenSeadragon.Point}
|
|
291
|
+
*/
|
|
292
|
+
getScalebarLocation: function () {
|
|
293
|
+
if (this.location === $.ScalebarLocation.TOP_LEFT) {
|
|
294
|
+
var x = 0;
|
|
295
|
+
var y = 0;
|
|
296
|
+
if (this.stayInsideImage) {
|
|
297
|
+
var pixel = this.viewer.viewport.pixelFromPoint(
|
|
298
|
+
new $.Point(0, 0),
|
|
299
|
+
true
|
|
300
|
+
);
|
|
301
|
+
if (!this.viewer.wrapHorizontal) {
|
|
302
|
+
x = Math.max(pixel.x, 0);
|
|
303
|
+
}
|
|
304
|
+
if (!this.viewer.wrapVertical) {
|
|
305
|
+
y = Math.max(pixel.y, 0);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return new $.Point(x + this.xOffset, y + this.yOffset);
|
|
309
|
+
}
|
|
310
|
+
if (this.location === $.ScalebarLocation.TOP_RIGHT) {
|
|
311
|
+
var barWidth = this.divElt.offsetWidth;
|
|
312
|
+
var container = this.viewer.container;
|
|
313
|
+
var x = container.offsetWidth - barWidth;
|
|
314
|
+
var y = 0;
|
|
315
|
+
if (this.stayInsideImage) {
|
|
316
|
+
var pixel = this.viewer.viewport.pixelFromPoint(
|
|
317
|
+
new $.Point(1, 0),
|
|
318
|
+
true
|
|
319
|
+
);
|
|
320
|
+
if (!this.viewer.wrapHorizontal) {
|
|
321
|
+
x = Math.min(x, pixel.x - barWidth);
|
|
322
|
+
}
|
|
323
|
+
if (!this.viewer.wrapVertical) {
|
|
324
|
+
y = Math.max(y, pixel.y);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return new $.Point(x - this.xOffset, y + this.yOffset);
|
|
328
|
+
}
|
|
329
|
+
if (this.location === $.ScalebarLocation.BOTTOM_RIGHT) {
|
|
330
|
+
var barWidth = this.divElt.offsetWidth;
|
|
331
|
+
var barHeight = this.divElt.offsetHeight;
|
|
332
|
+
var container = this.viewer.container;
|
|
333
|
+
var x = container.offsetWidth - barWidth;
|
|
334
|
+
var y = container.offsetHeight - barHeight;
|
|
335
|
+
if (this.stayInsideImage) {
|
|
336
|
+
var pixel = this.viewer.viewport.pixelFromPoint(
|
|
337
|
+
new $.Point(1, 1 / this.viewer.source.aspectRatio),
|
|
338
|
+
true
|
|
339
|
+
);
|
|
340
|
+
if (!this.viewer.wrapHorizontal) {
|
|
341
|
+
x = Math.min(x, pixel.x - barWidth);
|
|
342
|
+
}
|
|
343
|
+
if (!this.viewer.wrapVertical) {
|
|
344
|
+
y = Math.min(y, pixel.y - barHeight);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return new $.Point(x - this.xOffset, y - this.yOffset);
|
|
348
|
+
}
|
|
349
|
+
if (this.location === $.ScalebarLocation.BOTTOM_LEFT) {
|
|
350
|
+
var barHeight = this.divElt.offsetHeight;
|
|
351
|
+
var container = this.viewer.container;
|
|
352
|
+
var x = 0;
|
|
353
|
+
var y = container.offsetHeight - barHeight;
|
|
354
|
+
if (this.stayInsideImage) {
|
|
355
|
+
var pixel = this.viewer.viewport.pixelFromPoint(
|
|
356
|
+
new $.Point(0, 1 / this.viewer.source.aspectRatio),
|
|
357
|
+
true
|
|
358
|
+
);
|
|
359
|
+
if (!this.viewer.wrapHorizontal) {
|
|
360
|
+
x = Math.max(x, pixel.x);
|
|
361
|
+
}
|
|
362
|
+
if (!this.viewer.wrapVertical) {
|
|
363
|
+
y = Math.min(y, pixel.y - barHeight);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return new $.Point(x + this.xOffset, y - this.yOffset);
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
/**
|
|
370
|
+
* Get the rendered scalebar in a canvas.
|
|
371
|
+
* @returns {Element} A canvas containing the scalebar representation
|
|
372
|
+
*/
|
|
373
|
+
getAsCanvas: function () {
|
|
374
|
+
var canvas = document.createElement("canvas");
|
|
375
|
+
canvas.width = this.divElt.offsetWidth;
|
|
376
|
+
canvas.height = this.divElt.offsetHeight;
|
|
377
|
+
var context = canvas.getContext("2d");
|
|
378
|
+
context.fillStyle = this.backgroundColor;
|
|
379
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
380
|
+
context.fillStyle = this.color;
|
|
381
|
+
context.fillRect(
|
|
382
|
+
0,
|
|
383
|
+
canvas.height - this.barThickness,
|
|
384
|
+
canvas.width,
|
|
385
|
+
canvas.height
|
|
386
|
+
);
|
|
387
|
+
if (this.drawScalebar === this.drawMapScalebar) {
|
|
388
|
+
context.fillRect(0, 0, this.barThickness, canvas.height);
|
|
389
|
+
context.fillRect(
|
|
390
|
+
canvas.width - this.barThickness,
|
|
391
|
+
0,
|
|
392
|
+
this.barThickness,
|
|
393
|
+
canvas.height
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
context.font = window.getComputedStyle(this.divElt).font;
|
|
397
|
+
context.textAlign = "center";
|
|
398
|
+
context.textBaseline = "middle";
|
|
399
|
+
context.fillStyle = this.fontColor;
|
|
400
|
+
var hCenter = canvas.width / 2;
|
|
401
|
+
var vCenter = canvas.height / 2;
|
|
402
|
+
context.fillText(this.divElt.textContent, hCenter, vCenter);
|
|
403
|
+
return canvas;
|
|
404
|
+
},
|
|
405
|
+
/**
|
|
406
|
+
* Get a copy of the current OpenSeadragon canvas with the scalebar.
|
|
407
|
+
* @returns {Element} A canvas containing a copy of the current OpenSeadragon canvas with the scalebar
|
|
408
|
+
*/
|
|
409
|
+
getImageWithScalebarAsCanvas: function () {
|
|
410
|
+
var imgCanvas = this.viewer.drawer.canvas;
|
|
411
|
+
var newCanvas = document.createElement("canvas");
|
|
412
|
+
newCanvas.width = imgCanvas.width;
|
|
413
|
+
newCanvas.height = imgCanvas.height;
|
|
414
|
+
var newCtx = newCanvas.getContext("2d");
|
|
415
|
+
newCtx.drawImage(imgCanvas, 0, 0);
|
|
416
|
+
var scalebarCanvas = this.getAsCanvas();
|
|
417
|
+
var location = this.getScalebarLocation();
|
|
418
|
+
newCtx.drawImage(scalebarCanvas, location.x, location.y);
|
|
419
|
+
return newCanvas;
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
$.ScalebarSizeAndTextRenderer = {
|
|
424
|
+
/**
|
|
425
|
+
* Metric length. From nano meters to kilometers.
|
|
426
|
+
*/
|
|
427
|
+
METRIC_LENGTH: function (ppm, minSize) {
|
|
428
|
+
return getScalebarSizeAndTextForMetric(ppm, minSize, "m");
|
|
429
|
+
},
|
|
430
|
+
/**
|
|
431
|
+
* Imperial length. Choosing the best unit from thou, inch, foot and mile.
|
|
432
|
+
*/
|
|
433
|
+
IMPERIAL_LENGTH: function (ppm, minSize) {
|
|
434
|
+
var maxSize = minSize * 2;
|
|
435
|
+
var ppi = ppm * 0.0254;
|
|
436
|
+
if (maxSize < ppi * 12) {
|
|
437
|
+
if (maxSize < ppi) {
|
|
438
|
+
var ppt = ppi / 1000;
|
|
439
|
+
return getScalebarSizeAndText(ppt, minSize, "th");
|
|
440
|
+
}
|
|
441
|
+
return getScalebarSizeAndText(ppi, minSize, "in");
|
|
442
|
+
}
|
|
443
|
+
var ppf = ppi * 12;
|
|
444
|
+
if (maxSize < ppf * 2000) {
|
|
445
|
+
return getScalebarSizeAndText(ppf, minSize, "ft");
|
|
446
|
+
}
|
|
447
|
+
var ppmi = ppf * 5280;
|
|
448
|
+
return getScalebarSizeAndText(ppmi, minSize, "mi");
|
|
449
|
+
},
|
|
450
|
+
/**
|
|
451
|
+
* Astronomy units. Choosing the best unit from arcsec, arcminute, and degree
|
|
452
|
+
*/
|
|
453
|
+
ASTRONOMY: function (ppa, minSize) {
|
|
454
|
+
var maxSize = minSize * 2;
|
|
455
|
+
if (maxSize < ppa * 60) {
|
|
456
|
+
return getScalebarSizeAndText(ppa, minSize, '"', false, "");
|
|
457
|
+
}
|
|
458
|
+
var ppminutes = ppa * 60;
|
|
459
|
+
if (maxSize < ppminutes * 60) {
|
|
460
|
+
return getScalebarSizeAndText(ppminutes, minSize, "'", false, "");
|
|
461
|
+
}
|
|
462
|
+
var ppd = ppminutes * 60;
|
|
463
|
+
return getScalebarSizeAndText(ppd, minSize, "°", false, "");
|
|
464
|
+
},
|
|
465
|
+
/**
|
|
466
|
+
* Standard time. Choosing the best unit from second (and metric divisions),
|
|
467
|
+
* minute, hour, day and year.
|
|
468
|
+
*/
|
|
469
|
+
STANDARD_TIME: function (pps, minSize) {
|
|
470
|
+
var maxSize = minSize * 2;
|
|
471
|
+
if (maxSize < pps * 60) {
|
|
472
|
+
return getScalebarSizeAndTextForMetric(pps, minSize, "s", false);
|
|
473
|
+
}
|
|
474
|
+
var ppminutes = pps * 60;
|
|
475
|
+
if (maxSize < ppminutes * 60) {
|
|
476
|
+
return getScalebarSizeAndText(ppminutes, minSize, "minute", true);
|
|
477
|
+
}
|
|
478
|
+
var pph = ppminutes * 60;
|
|
479
|
+
if (maxSize < pph * 24) {
|
|
480
|
+
return getScalebarSizeAndText(pph, minSize, "hour", true);
|
|
481
|
+
}
|
|
482
|
+
var ppd = pph * 24;
|
|
483
|
+
if (maxSize < ppd * 365.25) {
|
|
484
|
+
return getScalebarSizeAndText(ppd, minSize, "day", true);
|
|
485
|
+
}
|
|
486
|
+
var ppy = ppd * 365.25;
|
|
487
|
+
return getScalebarSizeAndText(ppy, minSize, "year", true);
|
|
488
|
+
},
|
|
489
|
+
/**
|
|
490
|
+
* Generic metric unit. One can use this function to create a new metric
|
|
491
|
+
* scale. For example, here is an implementation of energy levels:
|
|
492
|
+
* function(ppeV, minSize) {
|
|
493
|
+
* return OpenSeadragon.ScalebarSizeAndTextRenderer.METRIC_GENERIC(
|
|
494
|
+
* ppeV, minSize, "eV");
|
|
495
|
+
* }
|
|
496
|
+
*/
|
|
497
|
+
METRIC_GENERIC: getScalebarSizeAndTextForMetric,
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// Missing TiledImage.viewportToImageZoom function in OSD 2.0.0
|
|
501
|
+
function tiledImageViewportToImageZoom(tiledImage, viewportZoom) {
|
|
502
|
+
var ratio =
|
|
503
|
+
(tiledImage._scaleSpring.current.value *
|
|
504
|
+
tiledImage.viewport._containerInnerSize.x) /
|
|
505
|
+
tiledImage.source.dimensions.x;
|
|
506
|
+
return ratio * viewportZoom;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function getScalebarSizeAndText(
|
|
510
|
+
ppm,
|
|
511
|
+
minSize,
|
|
512
|
+
unitSuffix,
|
|
513
|
+
handlePlural,
|
|
514
|
+
spacer
|
|
515
|
+
) {
|
|
516
|
+
spacer = spacer === undefined ? " " : spacer;
|
|
517
|
+
var value = normalize(ppm, minSize);
|
|
518
|
+
var factor = roundSignificand((value / ppm) * minSize, 3);
|
|
519
|
+
var size = value * minSize;
|
|
520
|
+
var plural = handlePlural && factor > 1 ? "s" : "";
|
|
521
|
+
return {
|
|
522
|
+
size: size,
|
|
523
|
+
text: factor + spacer + unitSuffix + plural,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function getScalebarSizeAndTextForMetric(ppm, minSize, unitSuffix) {
|
|
528
|
+
var value = normalize(ppm, minSize);
|
|
529
|
+
var factor = roundSignificand((value / ppm) * minSize, 3);
|
|
530
|
+
var size = value * minSize;
|
|
531
|
+
var valueWithUnit = getWithUnit(factor, unitSuffix);
|
|
532
|
+
return {
|
|
533
|
+
size: size,
|
|
534
|
+
text: valueWithUnit,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function normalize(value, minSize) {
|
|
539
|
+
var significand = getSignificand(value);
|
|
540
|
+
var minSizeSign = getSignificand(minSize);
|
|
541
|
+
var result = getSignificand(significand / minSizeSign);
|
|
542
|
+
if (result >= 5) {
|
|
543
|
+
result /= 5;
|
|
544
|
+
}
|
|
545
|
+
if (result >= 4) {
|
|
546
|
+
result /= 4;
|
|
547
|
+
}
|
|
548
|
+
if (result >= 2) {
|
|
549
|
+
result /= 2;
|
|
550
|
+
}
|
|
551
|
+
return result;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function getSignificand(x) {
|
|
555
|
+
return x * Math.pow(10, Math.ceil(-log10(x)));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function roundSignificand(x, decimalPlaces) {
|
|
559
|
+
var exponent = -Math.ceil(-log10(x));
|
|
560
|
+
var power = decimalPlaces - exponent;
|
|
561
|
+
var significand = x * Math.pow(10, power);
|
|
562
|
+
// To avoid rounding problems, always work with integers
|
|
563
|
+
if (power < 0) {
|
|
564
|
+
return Math.round(significand) * Math.pow(10, -power);
|
|
565
|
+
}
|
|
566
|
+
return Math.round(significand) / Math.pow(10, power);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function log10(x) {
|
|
570
|
+
return Math.log(x) / Math.log(10);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function getWithUnit(value, unitSuffix) {
|
|
574
|
+
if (value < 0.000001) {
|
|
575
|
+
return value * 1000000000 + " n" + unitSuffix;
|
|
576
|
+
}
|
|
577
|
+
if (value < 0.001) {
|
|
578
|
+
return value * 1000000 + " μ" + unitSuffix;
|
|
579
|
+
}
|
|
580
|
+
if (value < 1) {
|
|
581
|
+
return value * 1000 + " m" + unitSuffix;
|
|
582
|
+
}
|
|
583
|
+
if (value >= 1000) {
|
|
584
|
+
return value / 1000 + " k" + unitSuffix;
|
|
585
|
+
}
|
|
586
|
+
return value + " " + unitSuffix;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function isDefined(variable) {
|
|
590
|
+
return typeof variable !== "undefined";
|
|
591
|
+
}
|
|
592
|
+
})(OpenSeadragon);
|