med-viewer-sdk 0.1.25 → 0.1.27

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.
@@ -12794,6 +12794,15 @@ const CSS_VAR_MAP = {
12794
12794
  function cssVar(key) {
12795
12795
  return `var(${CSS_VAR_MAP[key]})`;
12796
12796
  }
12797
+ const GLOBAL_ANNO_EDITOR_KEYS = [
12798
+ "annoEditorBg",
12799
+ "annoEditorText",
12800
+ "annoEditorBorder",
12801
+ "annoEditorInputBg",
12802
+ "annoEditorBtnBg",
12803
+ "annoEditorBtnHoverBg",
12804
+ "annoEditorBtnColor"
12805
+ ];
12797
12806
  class ThemeManager {
12798
12807
  constructor(container, themeConfig) {
12799
12808
  __publicField(this, "container");
@@ -12830,6 +12839,7 @@ class ThemeManager {
12830
12839
  }
12831
12840
  /**
12832
12841
  * 将主题颜色应用为 CSS 变量到容器元素
12842
+ * 同时将 annoEditor* 相关变量提升到 :root,供 .r6o-editor(挂载在 body 下)使用
12833
12843
  */
12834
12844
  applyTheme(colors) {
12835
12845
  const keys = Object.keys(CSS_VAR_MAP);
@@ -12837,6 +12847,9 @@ class ThemeManager {
12837
12847
  const value = colors[key];
12838
12848
  if (value !== void 0) {
12839
12849
  this.container.style.setProperty(CSS_VAR_MAP[key], value);
12850
+ if (GLOBAL_ANNO_EDITOR_KEYS.includes(key)) {
12851
+ document.documentElement.style.setProperty(CSS_VAR_MAP[key], value);
12852
+ }
12840
12853
  }
12841
12854
  });
12842
12855
  }
@@ -12874,6 +12887,9 @@ class ThemeManager {
12874
12887
  const keys = Object.keys(CSS_VAR_MAP);
12875
12888
  keys.forEach((key) => {
12876
12889
  this.container.style.removeProperty(CSS_VAR_MAP[key]);
12890
+ if (GLOBAL_ANNO_EDITOR_KEYS.includes(key)) {
12891
+ document.documentElement.style.removeProperty(CSS_VAR_MAP[key]);
12892
+ }
12877
12893
  });
12878
12894
  }
12879
12895
  }
@@ -12882,6 +12898,7 @@ class AnnoAnnotator extends BaseAnnotator {
12882
12898
  super(engine);
12883
12899
  __publicField(this, "anno");
12884
12900
  __publicField(this, "listeners", /* @__PURE__ */ new Map());
12901
+ __publicField(this, "injectedStyleEl", null);
12885
12902
  this.anno = Annotorious(this.engine.viewer, {
12886
12903
  ...config
12887
12904
  // 可以在此配置样式、偏好等
@@ -12936,7 +12953,10 @@ class AnnoAnnotator extends BaseAnnotator {
12936
12953
  this.anno.clearAnnotations();
12937
12954
  }
12938
12955
  destroy() {
12956
+ var _a2;
12939
12957
  this.anno.destroy();
12958
+ (_a2 = this.injectedStyleEl) == null ? void 0 : _a2.remove();
12959
+ this.injectedStyleEl = null;
12940
12960
  }
12941
12961
  initEvents(config) {
12942
12962
  if (config.onCreateAnnotation) {
@@ -12973,11 +12993,9 @@ class AnnoAnnotator extends BaseAnnotator {
12973
12993
  }
12974
12994
  }
12975
12995
  injectStyles() {
12976
- const styleId = "med-anno-v2-7-17-overrides";
12977
- if (document.getElementById(styleId))
12978
- return;
12979
12996
  const style = document.createElement("style");
12980
- style.id = styleId;
12997
+ style.setAttribute("data-med-anno-instance", "true");
12998
+ this.injectedStyleEl = style;
12981
12999
  style.innerHTML = `
12982
13000
  /* ── 标注手柄 ── */
12983
13001
  .a9s-handle .a9s-handle-inner {
@@ -14154,441 +14172,230 @@ function getCurrentLocale() {
14154
14172
  return currentLocale;
14155
14173
  }
14156
14174
  function getWithUnit(value, unitSuffix) {
14157
- return value.toFixed(2) + "μ" + unitSuffix;
14175
+ const isArea = unitSuffix.includes("²");
14176
+ const baseSuffix = unitSuffix.replace("²", "");
14177
+ if (isArea) {
14178
+ if (value >= 1e12) {
14179
+ return (value / 1e12).toFixed(2) + " " + baseSuffix + "²";
14180
+ }
14181
+ if (value >= 1e6) {
14182
+ return (value / 1e6).toFixed(2) + " m" + baseSuffix + "²";
14183
+ }
14184
+ return value.toFixed(2) + " μ" + baseSuffix + "²";
14185
+ } else {
14186
+ if (value >= 1e6) {
14187
+ return (value / 1e6).toFixed(2) + " " + baseSuffix;
14188
+ }
14189
+ if (value >= 1e3) {
14190
+ return (value / 1e3).toFixed(2) + " m" + baseSuffix;
14191
+ }
14192
+ return value.toFixed(2) + " μ" + baseSuffix;
14193
+ }
14158
14194
  }
14159
- function pixelsToPerMeter(value, pixelsPerMeter) {
14160
- let nweValue = value / pixelsPerMeter;
14161
- return nweValue * 1e6;
14195
+ function pixelsToMicrons(value, pixelsPerMeter) {
14196
+ return value / pixelsPerMeter * 1e6;
14197
+ }
14198
+ function computePolygonArea(pts) {
14199
+ let sum = 0;
14200
+ for (let i2 = 0; i2 < pts.length - 1; i2++) {
14201
+ const [x1, y1] = pts[i2];
14202
+ const [x2, y2] = pts[i2 + 1];
14203
+ sum += x1 * y2 - x2 * y1;
14204
+ }
14205
+ return Math.abs(sum / 2);
14162
14206
  }
14163
14207
  const ShapeLabelsFormatter = (pixelsPerMeter, showMeasure) => (annotation) => {
14164
14208
  var _a2;
14165
14209
  const bodies = Array.isArray(annotation.body) ? annotation.body : [annotation.body];
14166
- let toolName = (_a2 = annotation.target.renderedVia) == null ? void 0 : _a2.name;
14167
- if (!showMeasure) {
14210
+ let toolName = ((_a2 = annotation.target.renderedVia) == null ? void 0 : _a2.name) ?? null;
14211
+ if (!showMeasure)
14168
14212
  toolName = null;
14169
- }
14170
14213
  const foreignObject = document.createElementNS(
14171
14214
  "http://www.w3.org/2000/svg",
14172
14215
  "foreignObject"
14173
14216
  );
14174
14217
  foreignObject.setAttribute("width", "1px");
14175
14218
  foreignObject.setAttribute("height", "1px");
14176
- const firstTag = bodies.find((b2) => b2.purpose == "commenting");
14219
+ const firstTag = bodies.find((b2) => (b2 == null ? void 0 : b2.purpose) === "commenting");
14220
+ const wrapLabel = (rows, remark) => {
14221
+ const remarkRow = remark ? `<p>${t("annotation.remark")}:&nbsp;&nbsp;${remark}</p>` : "";
14222
+ return `<div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14223
+ <div class="a9s-shape-label">
14224
+ ${rows.map((r2) => `<p>${r2}</p>`).join("")}
14225
+ ${remarkRow}
14226
+ </div>
14227
+ </div>`;
14228
+ };
14177
14229
  switch (toolName) {
14178
- case "line":
14179
- console.log("line", annotation.target.selector.value);
14180
- let lineDiv = document.createElement("div");
14181
- lineDiv.innerHTML = annotation.target.selector.value;
14182
- let line = lineDiv.getElementsByTagName("line")[0];
14183
- let x1 = pixelsToPerMeter(
14184
- Number(line.getAttribute("x1")),
14185
- pixelsPerMeter
14186
- );
14187
- let y1 = pixelsToPerMeter(
14188
- Number(line.getAttribute("y1")),
14189
- pixelsPerMeter
14190
- );
14191
- let x2 = pixelsToPerMeter(
14192
- Number(line.getAttribute("x2")),
14193
- pixelsPerMeter
14194
- );
14195
- let y2 = pixelsToPerMeter(
14196
- Number(line.getAttribute("y2")),
14197
- pixelsPerMeter
14230
+ case "line": {
14231
+ const div = document.createElement("div");
14232
+ div.innerHTML = annotation.target.selector.value;
14233
+ const el = div.getElementsByTagName("line")[0];
14234
+ const x1 = pixelsToMicrons(Number(el.getAttribute("x1")), pixelsPerMeter);
14235
+ const y1 = pixelsToMicrons(Number(el.getAttribute("y1")), pixelsPerMeter);
14236
+ const x2 = pixelsToMicrons(Number(el.getAttribute("x2")), pixelsPerMeter);
14237
+ const y2 = pixelsToMicrons(Number(el.getAttribute("y2")), pixelsPerMeter);
14238
+ const len = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
14239
+ foreignObject.innerHTML = wrapLabel(
14240
+ [`${t("annotation.length")}:&nbsp;&nbsp;${getWithUnit(len, "m")}`],
14241
+ firstTag == null ? void 0 : firstTag.value
14198
14242
  );
14199
- let len = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
14200
- if (firstTag) {
14201
- foreignObject.innerHTML = `
14202
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14203
- <div class="a9s-shape-label" >
14204
- <p >
14205
- ${t(`annotation.length`)}:&nbsp;&nbsp;${getWithUnit(
14206
- len,
14207
- "m"
14208
- )}&nbsp;&nbsp; </p> <p >
14209
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14210
- </p>
14211
- </div>
14212
- </div>`;
14213
- } else {
14214
- foreignObject.innerHTML = `
14215
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14216
-
14217
- <div class="a9s-shape-label" >
14218
- <p>
14219
- ${t(`annotation.length`)}:&nbsp;&nbsp;${getWithUnit(len, "m")}&nbsp;&nbsp;
14220
- </p>
14221
- </div>
14222
- </div>`;
14223
- }
14224
14243
  break;
14225
- case "rect":
14226
- let reg = new RegExp("xywh=pixel:", "g");
14227
- let str = annotation.target.selector.value.replace(reg, "");
14228
- let point = str.split(",");
14229
- const rectWidth = pixelsToPerMeter(Number(point[2]), pixelsPerMeter);
14230
- const rectHeight = pixelsToPerMeter(Number(point[3]), pixelsPerMeter);
14231
- const rectPerimeter = 2 * (rectWidth + rectHeight);
14232
- const rectArea = rectWidth * rectHeight;
14233
- if (firstTag) {
14234
- foreignObject.innerHTML = `
14235
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14236
-
14237
- <div class="a9s-shape-label">
14238
- <p>
14239
- ${t(`annotation.width`)}:&nbsp;&nbsp;${getWithUnit(
14240
- rectWidth,
14241
- "m"
14242
- )}&nbsp;&nbsp;</p> <p>
14243
-
14244
-
14245
- ${t(`annotation.height`)}:&nbsp;&nbsp;${getWithUnit(
14246
- rectHeight,
14247
- "m"
14248
- )}&nbsp;&nbsp;</p> <p>
14249
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14250
- rectPerimeter,
14251
- "m"
14252
- )}&nbsp;&nbsp;</p> <p>
14253
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14254
- rectArea,
14255
- "m²"
14256
- )}&nbsp;&nbsp;</p> <p>
14257
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14258
- </p>
14259
- </div>
14260
- </div>`;
14261
- } else {
14262
- foreignObject.innerHTML = `
14263
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14264
- <div class="a9s-shape-label">
14265
- <p >
14266
- ${t(`annotation.width`)}:&nbsp;&nbsp;${getWithUnit(
14267
- rectWidth,
14268
- "m"
14269
- )}&nbsp;&nbsp;</p> <p>
14270
- ${t(`annotation.height`)}:&nbsp;&nbsp;${getWithUnit(
14271
- rectHeight,
14272
- "m"
14273
- )}&nbsp;&nbsp;</p> <p>
14274
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14275
- rectPerimeter,
14276
- "m"
14277
- )}&nbsp;&nbsp;</p> <p>
14278
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(rectArea, "m²")}&nbsp;&nbsp;
14279
- </p>
14280
- </div>
14281
- </div>`;
14282
- }
14283
- break;
14284
- case "circle":
14285
- let circleDiv = document.createElement("div");
14286
- console.log(annotation);
14287
- circleDiv.innerHTML = annotation.target.selector.value;
14288
- let circle = circleDiv.getElementsByTagName("circle")[0];
14289
- const circleRadius = pixelsToPerMeter(
14290
- Number(circle.getAttribute("r")),
14291
- pixelsPerMeter
14244
+ }
14245
+ case "rect": {
14246
+ const str = annotation.target.selector.value.replace(/xywh=pixel:/g, "");
14247
+ const parts = str.split(",");
14248
+ const rw = pixelsToMicrons(Number(parts[2]), pixelsPerMeter);
14249
+ const rh = pixelsToMicrons(Number(parts[3]), pixelsPerMeter);
14250
+ const rp = 2 * (rw + rh);
14251
+ const ra = rw * rh;
14252
+ foreignObject.innerHTML = wrapLabel(
14253
+ [
14254
+ `${t("annotation.width")}:&nbsp;&nbsp;${getWithUnit(rw, "m")}`,
14255
+ `${t("annotation.height")}:&nbsp;&nbsp;${getWithUnit(rh, "m")}`,
14256
+ `${t("annotation.perimeter")}:&nbsp;&nbsp;${getWithUnit(rp, "m")}`,
14257
+ `${t("annotation.area")}:&nbsp;&nbsp;${getWithUnit(ra, "m²")}`
14258
+ ],
14259
+ firstTag == null ? void 0 : firstTag.value
14292
14260
  );
14293
- const circleCircumference = 2 * Math.PI * circleRadius;
14294
- const circleArea = Math.PI * Math.pow(circleRadius, 2);
14295
- if (firstTag) {
14296
- foreignObject.innerHTML = `
14297
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14298
-
14299
- <div class="a9s-shape-label">
14300
- <p>
14301
- ${t(`annotation.radius`)}:&nbsp;&nbsp;${getWithUnit(
14302
- circleRadius,
14303
- "m"
14304
- )}&nbsp;&nbsp;</p><p>
14305
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14306
- circleCircumference,
14307
- "m"
14308
- )}&nbsp;&nbsp;</p><p>
14309
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14310
- circleArea,
14311
- "m²"
14312
- )}&nbsp;&nbsp;</p><p>
14313
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14314
- </p>
14315
- </div>
14316
- </div>`;
14317
- } else {
14318
- foreignObject.innerHTML = `
14319
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14320
- <div class="a9s-shape-label">
14321
- <p>
14322
- ${t(`annotation.radius`)}:&nbsp;&nbsp;${getWithUnit(
14323
- circleRadius,
14324
- "m"
14325
- )}&nbsp;&nbsp;</p><p>
14326
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14327
- circleCircumference,
14328
- "m"
14329
- )}&nbsp;&nbsp;</p><p>
14330
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14331
- circleArea,
14332
- "m²"
14333
- )}&nbsp;&nbsp;
14334
-
14335
- </p>
14336
- </div>
14337
- </div>`;
14338
- }
14339
14261
  break;
14340
- case "ellipse":
14341
- let ellipseDiv = document.createElement("div");
14342
- ellipseDiv.innerHTML = annotation.target.selector.value;
14343
- let ellipse = ellipseDiv.getElementsByTagName("ellipse")[0];
14344
- let rx = pixelsToPerMeter(
14345
- Number(ellipse.getAttribute("rx")),
14346
- pixelsPerMeter
14262
+ }
14263
+ case "circle": {
14264
+ const div = document.createElement("div");
14265
+ div.innerHTML = annotation.target.selector.value;
14266
+ const el = div.getElementsByTagName("circle")[0];
14267
+ const r2 = pixelsToMicrons(Number(el.getAttribute("r")), pixelsPerMeter);
14268
+ const circum = 2 * Math.PI * r2;
14269
+ const area = Math.PI * r2 * r2;
14270
+ foreignObject.innerHTML = wrapLabel(
14271
+ [
14272
+ `${t("annotation.radius")}:&nbsp;&nbsp;${getWithUnit(r2, "m")}`,
14273
+ `${t("annotation.perimeter")}:&nbsp;&nbsp;${getWithUnit(circum, "m")}`,
14274
+ `${t("annotation.area")}:&nbsp;&nbsp;${getWithUnit(area, "m²")}`
14275
+ ],
14276
+ firstTag == null ? void 0 : firstTag.value
14347
14277
  );
14348
- let ry = pixelsToPerMeter(
14349
- Number(ellipse.getAttribute("ry")),
14350
- pixelsPerMeter
14278
+ break;
14279
+ }
14280
+ case "ellipse": {
14281
+ const div = document.createElement("div");
14282
+ div.innerHTML = annotation.target.selector.value;
14283
+ const el = div.getElementsByTagName("ellipse")[0];
14284
+ const rx = pixelsToMicrons(Number(el.getAttribute("rx")), pixelsPerMeter);
14285
+ const ry = pixelsToMicrons(Number(el.getAttribute("ry")), pixelsPerMeter);
14286
+ const majorAxis = Math.max(rx, ry);
14287
+ const minorAxis = Math.min(rx, ry);
14288
+ const perim = Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry)));
14289
+ const area = Math.PI * rx * ry;
14290
+ foreignObject.innerHTML = wrapLabel(
14291
+ [
14292
+ `${t("annotation.majorAxis")}:&nbsp;&nbsp;${getWithUnit(majorAxis, "m")}`,
14293
+ `${t("annotation.minorAxis")}:&nbsp;&nbsp;${getWithUnit(minorAxis, "m")}`,
14294
+ `${t("annotation.perimeter")}:&nbsp;&nbsp;${getWithUnit(perim, "m")}`,
14295
+ `${t("annotation.area")}:&nbsp;&nbsp;${getWithUnit(area, "m²")}`
14296
+ ],
14297
+ firstTag == null ? void 0 : firstTag.value
14351
14298
  );
14352
- let majorAxis = null;
14353
- let minorAxis = null;
14354
- if (rx >= ry) {
14355
- majorAxis = rx;
14356
- minorAxis = ry;
14357
- } else {
14358
- majorAxis = ry;
14359
- minorAxis = rx;
14360
- }
14361
- const ellipsePerimeter = Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry)));
14362
- const ellipseArea = Math.PI * rx * ry;
14363
- if (firstTag) {
14364
- foreignObject.innerHTML = `
14365
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14366
- <div class="a9s-shape-label">
14367
- <p>
14368
- ${t(`annotation.majorAxis`)}:&nbsp;&nbsp;${getWithUnit(
14369
- majorAxis,
14370
- "m"
14371
- )}&nbsp;&nbsp;</p> <p>
14372
-
14373
- ${t(`annotation.minorAxis`)}:&nbsp;&nbsp;${getWithUnit(
14374
- minorAxis,
14375
- "m"
14376
- )}&nbsp;&nbsp;</p> <p>
14377
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14378
- ellipsePerimeter,
14379
- "m"
14380
- )}&nbsp;&nbsp;</p> <p>
14381
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14382
- ellipseArea,
14383
- "m²"
14384
- )}&nbsp;&nbsp;</p> <p>
14385
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14386
- </p>
14387
- </div>
14388
- </div>`;
14389
- } else {
14390
- foreignObject.innerHTML = `
14391
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14392
- <div class="a9s-shape-label">
14393
- <p>
14394
- ${t(`annotation.majorAxis`)}:&nbsp;&nbsp;${getWithUnit(
14395
- majorAxis,
14396
- "m"
14397
- )}&nbsp;&nbsp;</p><p>
14398
-
14399
- ${t(`annotation.minorAxis`)}:&nbsp;&nbsp;${getWithUnit(
14400
- minorAxis,
14401
- "m"
14402
- )}&nbsp;&nbsp;</p><p>
14403
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14404
- ellipsePerimeter,
14405
- "m"
14406
- )}&nbsp;&nbsp;</p><p>
14407
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14408
- ellipseArea,
14409
- "m²"
14410
- )}&nbsp;&nbsp;
14411
- </p>
14412
- </div>
14413
- </div>`;
14414
- }
14415
14299
  break;
14416
- case "polygon":
14417
- let polygonDiv = document.createElement("div");
14418
- polygonDiv.innerHTML = annotation.target.selector.value;
14419
- let polygon = polygonDiv.getElementsByTagName("polygon")[0];
14420
- let pointsAttribute = polygon.getAttribute("points");
14421
- const points = pointsAttribute.split(" ").map((point2) => {
14422
- const [x3, y3] = point2.split(",").map(parseFloat);
14423
- return {
14424
- x: pixelsToPerMeter(x3, pixelsPerMeter),
14425
- y: pixelsToPerMeter(y3, pixelsPerMeter)
14426
- };
14300
+ }
14301
+ case "polygon": {
14302
+ const div = document.createElement("div");
14303
+ div.innerHTML = annotation.target.selector.value;
14304
+ const el = div.getElementsByTagName("polygon")[0];
14305
+ const pts = (el.getAttribute("points") ?? "").trim().split(/\s+/).map((p2) => {
14306
+ const [x2, y2] = p2.split(",").map(parseFloat);
14307
+ return [
14308
+ pixelsToMicrons(x2, pixelsPerMeter),
14309
+ pixelsToMicrons(y2, pixelsPerMeter)
14310
+ ];
14427
14311
  });
14428
- let polygonPerimeter = 0;
14429
- for (let i2 = 0; i2 < points.length; i2++) {
14430
- const currentPoint = points[i2];
14431
- const nextPoint = points[(i2 + 1) % points.length];
14432
- const dx = nextPoint.x - currentPoint.x;
14433
- const dy = nextPoint.y - currentPoint.y;
14434
- polygonPerimeter += Math.sqrt(dx * dx + dy * dy);
14435
- }
14436
- let polygonArea = 0;
14437
- for (let i2 = 0; i2 < points.length; i2++) {
14438
- const currentPoint = points[i2];
14439
- const nextPoint = points[(i2 + 1) % points.length];
14440
- polygonArea += currentPoint.x * nextPoint.y - nextPoint.x * currentPoint.y;
14441
- }
14442
- polygonArea = Math.abs(polygonArea) / 2;
14443
- if (firstTag) {
14444
- foreignObject.innerHTML = `
14445
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14446
- <div class="a9s-shape-label">
14447
- <p>
14448
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14449
- polygonPerimeter,
14450
- "m"
14451
- )}&nbsp;&nbsp;</p> <p>
14452
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14453
- polygonArea,
14454
- "m²"
14455
- )}&nbsp;&nbsp;</p> <p>
14456
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14457
- </p>
14458
- </div>
14459
- </div>`;
14460
- } else {
14461
- foreignObject.innerHTML = `
14462
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14463
-
14464
- <div class="a9s-shape-label">
14465
- <p>
14466
- ${t(`annotation.perimeter`)}:&nbsp;&nbsp;${getWithUnit(
14467
- polygonPerimeter,
14468
- "m"
14469
- )}&nbsp;&nbsp;</p><p>
14470
- ${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(
14471
- polygonArea,
14472
- "m²"
14473
- )}&nbsp;&nbsp;
14474
- </p>
14475
- </div>
14476
- </div>`;
14477
- }
14312
+ let polyPerim = 0;
14313
+ for (let i2 = 0; i2 < pts.length; i2++) {
14314
+ const [ax, ay] = pts[i2];
14315
+ const [bx, by] = pts[(i2 + 1) % pts.length];
14316
+ polyPerim += Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
14317
+ }
14318
+ const polyArea = computePolygonArea(pts);
14319
+ foreignObject.innerHTML = wrapLabel(
14320
+ [
14321
+ `${t("annotation.perimeter")}:&nbsp;&nbsp;${getWithUnit(polyPerim, "m")}`,
14322
+ `${t("annotation.area")}:&nbsp;&nbsp;${getWithUnit(polyArea, "m²")}`
14323
+ ],
14324
+ firstTag == null ? void 0 : firstTag.value
14325
+ );
14478
14326
  break;
14479
- case "freehand":
14480
- let computeFreehandArea = function(freehandPoints2) {
14481
- let sum = 0;
14482
- for (let i2 = 0; i2 < freehandPoints2.length - 1; i2++) {
14483
- const [x12, y12] = freehandPoints2[i2];
14484
- const [x22, y22] = freehandPoints2[i2 + 1];
14485
- sum += x12 * y22 - x22 * y12;
14486
- }
14487
- return Math.abs(sum / 2);
14488
- };
14489
- let pathDiv = document.createElement("div");
14490
- pathDiv.innerHTML = annotation.target.selector.value;
14491
- let path = pathDiv.getElementsByTagName("path")[0];
14492
- let d2 = path.getAttribute("d");
14493
- const properties = new N(d2);
14494
- let pixelPerimeter = properties.getTotalLength();
14495
- let steps = 300;
14496
- let freehandPoints = [];
14327
+ }
14328
+ case "freehand": {
14329
+ const div = document.createElement("div");
14330
+ div.innerHTML = annotation.target.selector.value;
14331
+ const el = div.getElementsByTagName("path")[0];
14332
+ const d2 = el.getAttribute("d") ?? "";
14333
+ const props = new N(d2);
14334
+ const pixelPerim = props.getTotalLength();
14335
+ const steps = 300;
14336
+ const fhPts = [];
14497
14337
  for (let i2 = 0; i2 <= steps; i2++) {
14498
- let pos = properties.getPointAtLength(i2 / steps * pixelPerimeter);
14499
- freehandPoints.push([pos.x, pos.y]);
14500
- }
14501
- let areaPixel = computeFreehandArea(freehandPoints);
14502
- let realPerimeter = pixelsToPerMeter(pixelPerimeter, pixelsPerMeter);
14503
- let pixelToMicro = pixelsToPerMeter(1, pixelsPerMeter);
14504
- let realArea = areaPixel * pixelToMicro * pixelToMicro;
14505
- if (firstTag) {
14506
- foreignObject.innerHTML = `
14507
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14508
- <div class="a9s-shape-label">
14509
- <p>${t(`annotation.length`)}:&nbsp;&nbsp;${getWithUnit(realPerimeter, "m")}</p>
14510
- <p>${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(realArea, "m²")}</p>
14511
- <p>${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}</p>
14512
- </div>
14513
- </div>`;
14514
- } else {
14515
- foreignObject.innerHTML = `
14516
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14517
- <div class="a9s-shape-label">
14518
- <p>${t(`annotation.length`)}:&nbsp;&nbsp;${getWithUnit(realPerimeter, "m")}</p>
14519
- <p>${t(`annotation.area`)}:&nbsp;&nbsp;${getWithUnit(realArea, "m²")}</p>
14520
- </div>
14521
- </div>`;
14522
- }
14338
+ const pos = props.getPointAtLength(i2 / steps * pixelPerim);
14339
+ fhPts.push([pos.x, pos.y]);
14340
+ }
14341
+ const areaPixel = computePolygonArea(fhPts);
14342
+ const realPerim = pixelsToMicrons(pixelPerim, pixelsPerMeter);
14343
+ const pixelToMicro = pixelsToMicrons(1, pixelsPerMeter);
14344
+ const realArea = areaPixel * pixelToMicro * pixelToMicro;
14345
+ foreignObject.innerHTML = wrapLabel(
14346
+ [
14347
+ `${t("annotation.length")}:&nbsp;&nbsp;${getWithUnit(realPerim, "m")}`,
14348
+ `${t("annotation.area")}:&nbsp;&nbsp;${getWithUnit(realArea, "")}`
14349
+ ],
14350
+ firstTag == null ? void 0 : firstTag.value
14351
+ );
14523
14352
  break;
14353
+ }
14524
14354
  default:
14525
14355
  if (firstTag) {
14526
- foreignObject.innerHTML = `
14527
- <div xmlns="http://www.w3.org/1999/xhtml" class="a9s-shape-label-wrapper">
14528
- <div class="a9s-shape-label">
14529
- <p>
14530
- ${t(`annotation.remark`)}:&nbsp;&nbsp;${firstTag.value}&nbsp;&nbsp;
14531
- </p>
14532
- </div>
14533
- </div>`;
14356
+ foreignObject.innerHTML = wrapLabel(
14357
+ [],
14358
+ firstTag.value
14359
+ );
14534
14360
  }
14535
14361
  }
14536
- return {
14537
- element: foreignObject
14538
- };
14362
+ return { element: foreignObject };
14539
14363
  };
14540
- const injectShapeLabelStyles = () => {
14364
+ function injectShapeLabelStyles() {
14541
14365
  const styleId = "med-anno-default-shapeLabelsFormatter-overrides";
14542
14366
  if (document.getElementById(styleId))
14543
14367
  return;
14544
14368
  const style = document.createElement("style");
14545
14369
  style.id = styleId;
14546
14370
  style.innerHTML = `
14547
-
14548
14371
  .a9s-annotationlayer .a9s-formatter-el,
14549
14372
  .a9s-annotationlayer .a9s-formatter-el foreignObject {
14550
14373
  overflow: visible;
14551
14374
  pointer-events: none;
14552
14375
  }
14553
-
14554
14376
  .a9s-annotationlayer .a9s-formatter-el foreignObject .a9s-shape-label-wrapper {
14555
14377
  position: relative;
14556
14378
  transform: translateY(-100%);
14557
14379
  padding-bottom: 4px;
14558
14380
  }
14559
-
14560
- .a9s-annotationlayer
14561
- .a9s-formatter-el
14562
- foreignObject
14563
- .a9s-shape-label-wrapper
14564
- .a9s-shape-label {
14381
+ .a9s-annotationlayer .a9s-formatter-el foreignObject .a9s-shape-label-wrapper .a9s-shape-label {
14565
14382
  display: inline-block;
14566
14383
  max-width: 24vw !important;
14567
14384
  color: #000;
14568
- /* min-width: 10vw !important; */
14569
-
14570
14385
  word-wrap: break-word;
14571
14386
  word-break: keep-all;
14572
- /* white-space: nowrap; */
14573
-
14574
14387
  padding: 3px 5px;
14575
14388
  margin-bottom: 2px;
14576
14389
  background-color: rgba(255, 255, 255, 0.85);
14577
14390
  border-radius: 3px;
14578
14391
  font-size: 14px;
14579
14392
  }
14580
-
14581
- .a9s-annotationlayer
14582
- .a9s-formatter-el
14583
- foreignObject
14584
- .a9s-shape-label-wrapper
14585
- .a9s-shape-label
14586
- p {
14393
+ .a9s-annotationlayer .a9s-formatter-el foreignObject .a9s-shape-label-wrapper .a9s-shape-label p {
14587
14394
  margin: 5px !important;
14588
14395
  }
14589
- `;
14396
+ `;
14590
14397
  document.head.appendChild(style);
14591
- };
14398
+ }
14592
14399
  var MagnificationPosition = /* @__PURE__ */ ((MagnificationPosition2) => {
14593
14400
  MagnificationPosition2["TOP_LEFT"] = "TOP_LEFT";
14594
14401
  MagnificationPosition2["TOP_CENTER"] = "TOP_CENTER";
@@ -16063,6 +15870,12 @@ var ToolbarPosition = /* @__PURE__ */ ((ToolbarPosition2) => {
16063
15870
  return ToolbarPosition2;
16064
15871
  })(ToolbarPosition || {});
16065
15872
  const createAnnoDropdownContent = (engine, hide) => {
15873
+ if (!engine.anno) {
15874
+ const tip = document.createElement("div");
15875
+ tip.className = "med-toolbar-dropdown-inner med-plugin-unavailable";
15876
+ tip.innerHTML = `<p>标注插件未启用,请在 plugins.annotorious 中开启</p>`;
15877
+ return tip;
15878
+ }
16066
15879
  const container = document.createElement("div");
16067
15880
  container.className = "med-toolbar-dropdown-inner";
16068
15881
  let selectedColor = "#ff0000";
@@ -16127,6 +15940,12 @@ const debounce = (fn, delay) => {
16127
15940
  };
16128
15941
  const createColorAdjustDropdownContent = (engine, hide) => {
16129
15942
  var _a2;
15943
+ if (!engine.colorAdjust) {
15944
+ const tip = document.createElement("div");
15945
+ tip.className = "med-toolbar-dropdown-inner med-plugin-unavailable";
15946
+ tip.innerHTML = `<p>颜色调整插件未启用,请在 plugins.colorAdjust 中开启</p>`;
15947
+ return tip;
15948
+ }
16130
15949
  const container = document.createElement("div");
16131
15950
  container.className = "med-toolbar-dropdown-inner med-color-adjust-dropdown";
16132
15951
  if (engine.anno)
@@ -16468,9 +16287,13 @@ const DEFAULT_BUTTONS = [
16468
16287
  icon: buttonSelection,
16469
16288
  label: t("toolbar.screenshot"),
16470
16289
  onClick: (engine, hide) => {
16471
- var _a2;
16290
+ if (!engine.selection) {
16291
+ console.warn("[MedToolbar] 截图插件未启用,请在 plugins.selection 中开启");
16292
+ hide();
16293
+ return;
16294
+ }
16472
16295
  console.log("selection toggleState");
16473
- (_a2 = engine.selection) == null ? void 0 : _a2.toggleState();
16296
+ engine.selection.toggleState();
16474
16297
  if (engine.anno) {
16475
16298
  engine.anno.setEnabled(false);
16476
16299
  }
@@ -17013,6 +16836,17 @@ class MedToolbar {
17013
16836
  .med-reset-btn:hover {
17014
16837
  background: ${cssVar("dangerBgHigh")};
17015
16838
  }
16839
+ .med-plugin-unavailable {
16840
+ min-width: 200px;
16841
+ padding: 16px 12px;
16842
+ text-align: center;
16843
+ }
16844
+ .med-plugin-unavailable p {
16845
+ margin: 0;
16846
+ font-size: 13px;
16847
+ color: ${cssVar("textMuted")};
16848
+ line-height: 1.5;
16849
+ }
17016
16850
  `;
17017
16851
  document.head.appendChild(style);
17018
16852
  }
@@ -17102,6 +16936,7 @@ class MedViewerEngine {
17102
16936
  this.options = options;
17103
16937
  this.viewer = OpenSeadragon(osdOptions);
17104
16938
  this.themeManager = new ThemeManager(this.viewer.element, options.theme);
16939
+ this.injectNavigatorStyles();
17105
16940
  this.viewer.addOnceHandler("open", () => {
17106
16941
  this.viewer.viewport.goHome();
17107
16942
  this.emit("ready");
@@ -17332,6 +17167,23 @@ class MedViewerEngine {
17332
17167
  var _a2;
17333
17168
  return ((_a2 = this.themeManager) == null ? void 0 : _a2.getThemeName()) ?? null;
17334
17169
  }
17170
+ /**
17171
+ * 为 Navigator 小图添加圆角样式
17172
+ */
17173
+ injectNavigatorStyles() {
17174
+ const STYLE_ID2 = "med-navigator-styles";
17175
+ if (document.getElementById(STYLE_ID2))
17176
+ return;
17177
+ const style = document.createElement("style");
17178
+ style.id = STYLE_ID2;
17179
+ style.textContent = `
17180
+ .navigator {
17181
+ border-radius: 8px;
17182
+ overflow: hidden;
17183
+ }
17184
+ `;
17185
+ document.head.appendChild(style);
17186
+ }
17335
17187
  /**
17336
17188
  * 销毁引擎与所有插件
17337
17189
  */