@embedpdf/plugin-measurement 3.0.0-next.14 → 3.0.0-next.15
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 +57 -43
- package/dist/contract-BGn30CU9.d.cts +185 -0
- package/dist/contract-BHj3w9WF.cjs +178 -0
- package/dist/contract-BHj3w9WF.cjs.map +1 -0
- package/dist/contract-CSnWNeXI.d.ts +185 -0
- package/dist/contract-DyqqYfyE.js +131 -0
- package/dist/contract-DyqqYfyE.js.map +1 -0
- package/dist/contract.cjs +4 -1
- package/dist/contract.d.cts +2 -2
- package/dist/contract.d.ts +2 -2
- package/dist/contract.js +2 -2
- package/dist/index.cjs +554 -396
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -3
- package/dist/index.d.ts +31 -3
- package/dist/index.js +553 -399
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
- package/dist/contract-BnLRuw-Z.d.cts +0 -101
- package/dist/contract-C_ugpRGJ.d.ts +0 -101
- package/dist/contract-DO0emN-T.js +0 -7
- package/dist/contract-DO0emN-T.js.map +0 -1
- package/dist/contract-Dy7X9nSj.cjs +0 -11
- package/dist/contract-Dy7X9nSj.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,471 +1,629 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_contract = require("./contract-
|
|
2
|
+
const require_contract = require("./contract-BHj3w9WF.cjs");
|
|
3
3
|
let _embedpdf_core = require("@embedpdf/core");
|
|
4
4
|
let _embedpdf_plugin_annotation_contract_host = require("@embedpdf/plugin-annotation/contract/host");
|
|
5
5
|
let _embedpdf_plugin_interaction_contract = require("@embedpdf/plugin-interaction/contract");
|
|
6
|
-
let _embedpdf_plugin_annotation_contract = require("@embedpdf/plugin-annotation/contract");
|
|
7
6
|
let _embedpdf_engine_core_runtime = require("@embedpdf/engine-core/runtime");
|
|
8
|
-
//#region src/scale.ts
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
50,
|
|
15
|
-
100,
|
|
16
|
-
200
|
|
17
|
-
].map((real) => ({
|
|
18
|
-
id: `metric-${real}`,
|
|
19
|
-
label: `1:${real}`,
|
|
20
|
-
paper: 1,
|
|
21
|
-
real,
|
|
22
|
-
unit: "m"
|
|
23
|
-
})),
|
|
24
|
-
{
|
|
25
|
-
id: "imperial-quarter",
|
|
26
|
-
label: "1/4 in = 1 ft",
|
|
27
|
-
paper: 1,
|
|
28
|
-
real: 48,
|
|
29
|
-
unit: "ft"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: "imperial-eighth",
|
|
33
|
-
label: "1/8 in = 1 ft",
|
|
34
|
-
paper: 1,
|
|
35
|
-
real: 96,
|
|
36
|
-
unit: "ft"
|
|
37
|
-
}
|
|
7
|
+
//#region src/read/scale.ts
|
|
8
|
+
const UNITS = Object.keys(_embedpdf_engine_core_runtime.METRES);
|
|
9
|
+
const AREA_UNITS = [
|
|
10
|
+
...UNITS.map(_embedpdf_engine_core_runtime.squareOf),
|
|
11
|
+
"ha",
|
|
12
|
+
"acre"
|
|
38
13
|
];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
14
|
+
function createScaleReads(ctx, { siblings }, { scaleOf }) {
|
|
15
|
+
const { annotation } = siblings;
|
|
16
|
+
const settings = ctx.settings();
|
|
17
|
+
const state = () => ctx.state.get();
|
|
18
|
+
const readouts = /* @__PURE__ */ new WeakMap();
|
|
19
|
+
const getReadout = (ref) => {
|
|
20
|
+
const raw = annotation.get(ref);
|
|
21
|
+
if (!raw) return require_contract.NO_READOUT;
|
|
22
|
+
let readout = readouts.get(raw);
|
|
23
|
+
if (!readout) {
|
|
24
|
+
readout = (0, _embedpdf_engine_core_runtime.measurementReadout)(raw);
|
|
25
|
+
readouts.set(raw, readout);
|
|
26
|
+
}
|
|
27
|
+
return readout;
|
|
28
|
+
};
|
|
29
|
+
const measureDistance = (page, from, to) => (0, _embedpdf_engine_core_runtime.measurementReadout)({
|
|
30
|
+
subtype: "line",
|
|
31
|
+
intent: "line-dimension",
|
|
32
|
+
measure: scaleOf(page).measure,
|
|
33
|
+
linePoints: {
|
|
34
|
+
start: from,
|
|
35
|
+
end: to
|
|
36
|
+
}
|
|
44
37
|
});
|
|
38
|
+
const measureArea = (page, vertices) => (0, _embedpdf_engine_core_runtime.measurementReadout)({
|
|
39
|
+
subtype: "polygon",
|
|
40
|
+
intent: "polygon-dimension",
|
|
41
|
+
measure: scaleOf(page).measure,
|
|
42
|
+
vertices: [...vertices]
|
|
43
|
+
});
|
|
44
|
+
return { api: {
|
|
45
|
+
canMeasure: (page) => ctx.allows("annotations:create") && scaleOf(page).ready,
|
|
46
|
+
getPageScale: scaleOf,
|
|
47
|
+
isBusy: () => state().pending > 0,
|
|
48
|
+
listLastReports: () => state().reports,
|
|
49
|
+
listPresets: () => settings.get().presets,
|
|
50
|
+
listUnits: () => UNITS,
|
|
51
|
+
listAreaUnits: () => AREA_UNITS,
|
|
52
|
+
getReadout,
|
|
53
|
+
measureDistance,
|
|
54
|
+
measureArea,
|
|
55
|
+
getCalibrationRequest: () => state().calibration
|
|
56
|
+
} };
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/services/events.ts
|
|
60
|
+
function createEvents(ctx) {
|
|
45
61
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
scaleChanged: ctx.events.source(),
|
|
63
|
+
calibrationRequested: ctx.events.source(),
|
|
64
|
+
calibrationCompleted: ctx.events.source(),
|
|
65
|
+
calibrationDismissed: ctx.events.source()
|
|
50
66
|
};
|
|
51
67
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const precision = previous?.fraction === "fraction" ? 100 : previous?.precision ?? 100;
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/services/siblings.ts
|
|
70
|
+
/** The sibling plugins: annotation (host lens) and the interaction hub. */
|
|
71
|
+
function resolveSiblings(ctx) {
|
|
57
72
|
return {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
unit,
|
|
61
|
-
conversion: _embedpdf_engine_core_runtime.METRES[basis] / _embedpdf_engine_core_runtime.METRES[unit],
|
|
62
|
-
precision,
|
|
63
|
-
fraction: "decimal"
|
|
64
|
-
}],
|
|
65
|
-
area: [{
|
|
66
|
-
unit: (0, _embedpdf_engine_core_runtime.areaUnitLabel)(area),
|
|
67
|
-
conversion: _embedpdf_engine_core_runtime.METRES[basis] ** 2 / (0, _embedpdf_engine_core_runtime.squareMetres)(area),
|
|
68
|
-
precision,
|
|
69
|
-
fraction: "decimal"
|
|
70
|
-
}]
|
|
73
|
+
annotation: ctx.get(_embedpdf_plugin_annotation_contract_host.AnnotationToken),
|
|
74
|
+
interaction: ctx.get(_embedpdf_plugin_interaction_contract.InteractionToken)
|
|
71
75
|
};
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/services/store.ts
|
|
79
|
+
/** Changing a page's scale rewrites its measurement annotations. */
|
|
80
|
+
const SCALE_PERMISSION = "doc.annotate.modify";
|
|
81
|
+
function createStore(ctx) {
|
|
82
|
+
/** A page argument of a verb, as a ref or an index: the page, or `not-found`. */
|
|
83
|
+
const requirePage = (page) => ctx.pageOf(page);
|
|
84
|
+
const canCalibrate = () => ctx.allows(SCALE_PERMISSION);
|
|
85
|
+
/** The pages a verb changes, each resolved: a page that isn't there refuses the whole call. */
|
|
86
|
+
const targets = (pages) => {
|
|
87
|
+
if (pages === "all") return (ctx.document()?.pages ?? []).map((layout) => layout.ref);
|
|
88
|
+
return (Array.isArray(pages) ? pages : [pages]).map((page) => ctx.pageOf(page).ref);
|
|
89
|
+
};
|
|
80
90
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
requirePage,
|
|
92
|
+
canCalibrate,
|
|
93
|
+
targets
|
|
84
94
|
};
|
|
85
95
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!(basis in _embedpdf_engine_core_runtime.METRES)) throw new RangeError("This scale has an unknown base unit; calibrate it first");
|
|
90
|
-
const previous = measure.area[measure.area.length - 1];
|
|
91
|
-
const precision = previous?.fraction === "fraction" ? 100 : previous?.precision ?? 100;
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/services/index.ts
|
|
98
|
+
function createServices(ctx) {
|
|
92
99
|
return {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
conversion: _embedpdf_engine_core_runtime.METRES[basis] ** 2 / (0, _embedpdf_engine_core_runtime.squareMetres)(unit),
|
|
97
|
-
precision,
|
|
98
|
-
fraction: "decimal"
|
|
99
|
-
}]
|
|
100
|
+
events: createEvents(ctx),
|
|
101
|
+
store: createStore(ctx),
|
|
102
|
+
siblings: resolveSiblings(ctx)
|
|
100
103
|
};
|
|
101
104
|
}
|
|
102
105
|
//#endregion
|
|
103
|
-
//#region src/
|
|
104
|
-
|
|
106
|
+
//#region src/model.ts
|
|
107
|
+
/**
|
|
108
|
+
* The measurement session: scale changes in flight, the pending calibration,
|
|
109
|
+
* the last change's reports, why a page's viewport read failed, and the
|
|
110
|
+
* session-only viewports of engines that cannot persist a scale. The pages'
|
|
111
|
+
* viewports themselves are engine data held by a page mirror. Every
|
|
112
|
+
* transition below is pure; the controller applies them with
|
|
113
|
+
* `ctx.state.update`. `selectPageScale` and `pageScaleOf` are the pure
|
|
114
|
+
* projections from viewports to the public {@link PageScale}.
|
|
115
|
+
*/
|
|
116
|
+
/** No reports yet: the same array every time. */
|
|
117
|
+
const NO_REPORTS = Object.freeze([]);
|
|
118
|
+
const initialMeasurementState = () => ({
|
|
119
|
+
pending: 0,
|
|
120
|
+
calibration: null,
|
|
121
|
+
reports: NO_REPORTS,
|
|
122
|
+
loadErrors: {},
|
|
123
|
+
localViewports: {}
|
|
124
|
+
});
|
|
125
|
+
const beginScaleChange = (state) => ({
|
|
126
|
+
...state,
|
|
127
|
+
pending: state.pending + 1
|
|
128
|
+
});
|
|
129
|
+
const endScaleChange = (state) => state.pending === 0 ? state : {
|
|
130
|
+
...state,
|
|
131
|
+
pending: state.pending - 1
|
|
132
|
+
};
|
|
133
|
+
const setCalibration = (state, calibration) => state.calibration === calibration ? state : {
|
|
134
|
+
...state,
|
|
135
|
+
calibration
|
|
136
|
+
};
|
|
137
|
+
const setReports = (state, reports) => state.reports === reports ? state : {
|
|
138
|
+
...state,
|
|
139
|
+
reports
|
|
140
|
+
};
|
|
141
|
+
const recordLoadError = (state, pageObjectNumber, error) => ({
|
|
142
|
+
...state,
|
|
143
|
+
loadErrors: {
|
|
144
|
+
...state.loadErrors,
|
|
145
|
+
[pageObjectNumber]: error
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
const clearLoadError = (state, pageObjectNumber) => {
|
|
149
|
+
if (!(pageObjectNumber in state.loadErrors)) return state;
|
|
150
|
+
const { [pageObjectNumber]: _cleared, ...loadErrors } = state.loadErrors;
|
|
151
|
+
return {
|
|
152
|
+
...state,
|
|
153
|
+
loadErrors
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
const setLocalViewports = (state, pageObjectNumber, viewports) => ({
|
|
157
|
+
...state,
|
|
158
|
+
localViewports: {
|
|
159
|
+
...state.localViewports,
|
|
160
|
+
[pageObjectNumber]: viewports
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* The scale a page's viewports resolve to: the owned viewport, else the one
|
|
165
|
+
* containing the page's center, else the fallback.
|
|
166
|
+
*/
|
|
167
|
+
function selectPageScale(viewports, size, fallback, persistent) {
|
|
168
|
+
const selected = viewports.find((viewport) => viewport.owned) ?? (0, _embedpdf_engine_core_runtime.viewportForPoint)(viewports, {
|
|
169
|
+
x: size.width / 2,
|
|
170
|
+
y: size.height / 2
|
|
171
|
+
});
|
|
172
|
+
return {
|
|
173
|
+
measure: selected ? selected.measure ?? null : fallback,
|
|
174
|
+
source: selected ? selected.owned ? "owned" : "foreign" : "default",
|
|
175
|
+
ready: true,
|
|
176
|
+
persistent
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The public page scale. A page is ready once its viewports were read; a
|
|
181
|
+
* failed re-read keeps the last confirmed viewports in effect and reports
|
|
182
|
+
* its error alongside them.
|
|
183
|
+
*/
|
|
184
|
+
function pageScaleOf(inputs) {
|
|
185
|
+
const error = inputs.status === "error" && inputs.error ? { error: inputs.error } : {};
|
|
186
|
+
if (!inputs.viewports || !inputs.size) return {
|
|
187
|
+
measure: null,
|
|
188
|
+
source: "default",
|
|
189
|
+
ready: false,
|
|
190
|
+
persistent: inputs.persistent,
|
|
191
|
+
...error
|
|
192
|
+
};
|
|
193
|
+
return {
|
|
194
|
+
...selectPageScale(inputs.viewports, inputs.size, inputs.fallback, inputs.persistent),
|
|
195
|
+
...error
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/sync/viewports.ts
|
|
200
|
+
/**
|
|
201
|
+
* The pages' viewports: a page mirror re-read whenever a confirmed
|
|
202
|
+
* `pages.scaleSet` names a loaded page, from this session or another
|
|
203
|
+
* (stream gaps and version moves re-read every loaded page). Its `changed`
|
|
204
|
+
* callback tells the annotation plugin a page's viewports, and a new
|
|
205
|
+
* `defaultScale` setting tells it again. `connect` loads every page in the
|
|
206
|
+
* registry, including pages inserted later.
|
|
207
|
+
*/
|
|
208
|
+
/** The scale of a page index past the end: none, and never ready. */
|
|
209
|
+
const NO_PAGE = Object.freeze({
|
|
105
210
|
measure: null,
|
|
106
211
|
source: "default",
|
|
107
212
|
ready: false,
|
|
108
213
|
persistent: false
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
isBusy: () => ctx.getState().pending > 0,
|
|
127
|
-
lastReports: () => ctx.getState().reports,
|
|
128
|
-
prepare: effects.prepare,
|
|
129
|
-
setPageScale: (pon, measure, opts = {}) => effects.change(pons(pon, opts), () => measure, opts),
|
|
130
|
-
calibrate: (pon, from, to, real, opts = {}) => {
|
|
131
|
-
const a = (0, _embedpdf_engine_core_runtime.measurementPoint)(from);
|
|
132
|
-
const b = (0, _embedpdf_engine_core_runtime.measurementPoint)(to);
|
|
133
|
-
const scale = (0, _embedpdf_engine_core_runtime.measureFromKnownLength)(Math.hypot(b.x - a.x, b.y - a.y), real);
|
|
134
|
-
return effects.change(pons(pon, opts), () => scale, opts);
|
|
135
|
-
},
|
|
136
|
-
setUnit: (pon, unit, areaUnit, opts = {}) => effects.change(pons(pon, opts), (p) => withUnit(scaleOf(p), unit, areaUnit), {
|
|
137
|
-
...opts,
|
|
138
|
-
allPages: pon === "all" || opts.allPages
|
|
139
|
-
}),
|
|
140
|
-
setPrecision: (pon, precision, opts = {}) => effects.change(pons(pon, opts), (p) => withPrecision(scaleOf(p), precision), {
|
|
141
|
-
...opts,
|
|
142
|
-
allPages: pon === "all" || opts.allPages
|
|
143
|
-
}),
|
|
144
|
-
setPreset: (pon, id, opts = {}) => {
|
|
145
|
-
const preset = presets.find((p) => p.id === id);
|
|
146
|
-
if (!preset) return Promise.reject(/* @__PURE__ */ new RangeError("Unknown scale preset"));
|
|
147
|
-
return effects.change(pons(pon, opts), (p) => (0, _embedpdf_engine_core_runtime.measureFromRatio)(preset.paper, preset.real, preset.unit, ctx.document()?.pages.find((page) => page.pageObjectNumber === p)?.userUnit ?? 1), opts);
|
|
148
|
-
},
|
|
149
|
-
presets: () => presets,
|
|
150
|
-
units: () => UNITS,
|
|
151
|
-
areaUnits: () => [
|
|
152
|
-
...UNITS.map(_embedpdf_engine_core_runtime.squareOf),
|
|
153
|
-
"ha",
|
|
154
|
-
"acre"
|
|
155
|
-
],
|
|
156
|
-
setAreaUnit: (pon, unit, opts = {}) => effects.change(pons(pon, opts), (p) => withAreaUnit(scaleOf(p), unit), opts),
|
|
157
|
-
readout: (ref) => {
|
|
158
|
-
const dto = anno.get(ref);
|
|
159
|
-
return dto ? (0, _embedpdf_engine_core_runtime.measurementReadout)(dto) : { unavailable: "not-dimension" };
|
|
160
|
-
},
|
|
161
|
-
startCalibration: () => {
|
|
162
|
-
if (canCalibrate()) {
|
|
163
|
-
ctx.dispatch({
|
|
164
|
-
type: "CALIBRATION",
|
|
165
|
-
request: null
|
|
166
|
-
});
|
|
167
|
-
interaction.activateTool("calibrate");
|
|
214
|
+
});
|
|
215
|
+
function createViewportSync(ctx, { siblings }) {
|
|
216
|
+
const { annotation } = siblings;
|
|
217
|
+
const settings = ctx.settings();
|
|
218
|
+
/** The scale of a page without one: the `defaultScale` setting, in the page's user unit. */
|
|
219
|
+
const fallbackOf = (layout) => require_contract.defaultMeasure(settings.get().defaultScale, layout?.userUnit ?? 1);
|
|
220
|
+
const viewports = ctx.pageMirror({
|
|
221
|
+
name: "viewports",
|
|
222
|
+
load: async (doc, page, signal) => {
|
|
223
|
+
ctx.assertPageRef(page);
|
|
224
|
+
const service = doc.page(page).measure;
|
|
225
|
+
if (!service) return ctx.state.get().localViewports[page.objectNumber] ?? [];
|
|
226
|
+
try {
|
|
227
|
+
return (await service.listViewports()).viewports;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (!signal.aborted) ctx.state.update(recordLoadError, page.objectNumber, (0, _embedpdf_engine_core_runtime.serializeError)(error));
|
|
230
|
+
throw error;
|
|
168
231
|
}
|
|
169
232
|
},
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
effects.calibrationListeners.add(cb);
|
|
177
|
-
return () => {
|
|
178
|
-
effects.calibrationListeners.delete(cb);
|
|
179
|
-
};
|
|
180
|
-
},
|
|
181
|
-
onScaleChanged: (cb) => {
|
|
182
|
-
effects.scaleListeners.add(cb);
|
|
183
|
-
return () => {
|
|
184
|
-
effects.scaleListeners.delete(cb);
|
|
185
|
-
};
|
|
233
|
+
affected: (event) => event.type === "pages.scaleSet" ? [event.page] : null,
|
|
234
|
+
changed: ({ page, cause, next }) => {
|
|
235
|
+
if (cause === "drop" || next === void 0) return;
|
|
236
|
+
ctx.state.update(clearLoadError, page.objectNumber);
|
|
237
|
+
const layout = ctx.getPage(page);
|
|
238
|
+
if (layout) annotation.setPageViewports(page, [...next], fallbackOf(layout));
|
|
186
239
|
}
|
|
240
|
+
});
|
|
241
|
+
/** The engine can persist a scale into the document. */
|
|
242
|
+
const isPersistent = (page) => ctx.doc.page(page).measure !== void 0;
|
|
243
|
+
/** The page's public scale, the same object until its viewports, read state or layout change. */
|
|
244
|
+
const scaleOfPage = (0, _embedpdf_core.memoByKey)((pageObjectNumber) => {
|
|
245
|
+
const page = (0, _embedpdf_core.toPageRef)(pageObjectNumber);
|
|
246
|
+
const layout = ctx.getPage(page);
|
|
247
|
+
return [
|
|
248
|
+
viewports.get(page),
|
|
249
|
+
viewports.getStatus(page),
|
|
250
|
+
ctx.state.get().loadErrors[pageObjectNumber],
|
|
251
|
+
layout,
|
|
252
|
+
layout ? isPersistent(page) : false,
|
|
253
|
+
settings.get().defaultScale
|
|
254
|
+
];
|
|
255
|
+
}, (_pageObjectNumber, pageViewports, status, error, layout, persistent) => pageScaleOf({
|
|
256
|
+
viewports: pageViewports,
|
|
257
|
+
status,
|
|
258
|
+
error,
|
|
259
|
+
size: layout?.size,
|
|
260
|
+
fallback: fallbackOf(layout),
|
|
261
|
+
persistent
|
|
262
|
+
}));
|
|
263
|
+
/** A page's scale, by ref or index; a page that isn't there has none, and isn't ready. */
|
|
264
|
+
const scaleOf = (page) => {
|
|
265
|
+
if (typeof page !== "number") return scaleOfPage(page.objectNumber);
|
|
266
|
+
const layout = ctx.getPage(page);
|
|
267
|
+
return layout ? scaleOfPage(layout.ref.objectNumber) : NO_PAGE;
|
|
268
|
+
};
|
|
269
|
+
const ensureLoaded = (page, options) => {
|
|
270
|
+
const layout = ctx.getPage(page);
|
|
271
|
+
if (!layout) return Promise.reject(new _embedpdf_core.PluginError("not-found", "measurement", "no such page"));
|
|
272
|
+
return ctx.cancellable(options?.signal, viewports.ensureLoaded(layout.ref));
|
|
273
|
+
};
|
|
274
|
+
const connect = () => {
|
|
275
|
+
const hydrate = (layouts) => {
|
|
276
|
+
for (const layout of layouts ?? []) {
|
|
277
|
+
if (viewports.getStatus(layout.ref) !== "idle") continue;
|
|
278
|
+
viewports.ensureLoaded(layout.ref).catch(() => {});
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
hydrate(ctx.document()?.pages);
|
|
282
|
+
ctx.watch(() => ctx.document()?.pages, hydrate);
|
|
283
|
+
ctx.listen(settings.api.onSettingsChanged, ({ changed }) => {
|
|
284
|
+
if (!changed.includes("defaultScale")) return;
|
|
285
|
+
for (const layout of ctx.document()?.pages ?? []) {
|
|
286
|
+
const known = viewports.get(layout.ref);
|
|
287
|
+
if (known) annotation.setPageViewports(layout.ref, [...known], fallbackOf(layout));
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
return {
|
|
292
|
+
ensureLoaded,
|
|
293
|
+
scaleOf,
|
|
294
|
+
/** Re-read one page; for session-only scales, which no engine event announces. */
|
|
295
|
+
refresh: (page) => viewports.refresh(page),
|
|
296
|
+
connect
|
|
187
297
|
};
|
|
188
298
|
}
|
|
189
299
|
//#endregion
|
|
190
|
-
//#region src/
|
|
191
|
-
/**
|
|
192
|
-
*
|
|
193
|
-
function
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const scaleListeners = /* @__PURE__ */ new Set();
|
|
202
|
-
const meta = (pon) => ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);
|
|
203
|
-
const live = () => {
|
|
204
|
-
if (disposed || !ctx.doc) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.DocNotOpen);
|
|
300
|
+
//#region src/write/calibration.ts
|
|
301
|
+
/** The calibrate flow: arm the tool, turn a captured distance draft into a
|
|
302
|
+
* request (page space), and dismiss it. */
|
|
303
|
+
function createCalibration(ctx, { events, store, siblings }) {
|
|
304
|
+
const { calibrationRequested, calibrationDismissed } = events;
|
|
305
|
+
const { canCalibrate } = store;
|
|
306
|
+
const { annotation, interaction } = siblings;
|
|
307
|
+
const startCalibration = () => {
|
|
308
|
+
ctx.assertAllowed(SCALE_PERMISSION, "measurement.startCalibration");
|
|
309
|
+
ctx.state.update(setCalibration, null);
|
|
310
|
+
interaction.activateTool("calibrate");
|
|
205
311
|
};
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
312
|
+
const dismissCalibration = () => {
|
|
313
|
+
if (!ctx.state.get().calibration) return;
|
|
314
|
+
ctx.state.update(setCalibration, null);
|
|
315
|
+
calibrationDismissed.emit({});
|
|
209
316
|
};
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
317
|
+
/** A distance draft from the calibrate tool becomes the pending request. */
|
|
318
|
+
const connect = () => {
|
|
319
|
+
ctx.listen(annotation.onDraftCaptured, (draft) => {
|
|
320
|
+
if (draft.tool !== "calibrate" || !canCalibrate()) return;
|
|
321
|
+
const from = (0, _embedpdf_engine_core_runtime.measurementPoint)(draft.from);
|
|
322
|
+
const to = (0, _embedpdf_engine_core_runtime.measurementPoint)(draft.to);
|
|
323
|
+
const userSpaceLength = Math.hypot(to.x - from.x, to.y - from.y);
|
|
324
|
+
if (!(userSpaceLength > 0)) return;
|
|
325
|
+
const request = {
|
|
326
|
+
page: draft.page,
|
|
327
|
+
from,
|
|
328
|
+
to,
|
|
329
|
+
userSpaceLength
|
|
330
|
+
};
|
|
331
|
+
interaction.activateTool("pointer");
|
|
332
|
+
ctx.state.update(setCalibration, request);
|
|
333
|
+
calibrationRequested.emit({ request });
|
|
221
334
|
});
|
|
222
335
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
336
|
+
return {
|
|
337
|
+
connect,
|
|
338
|
+
api: {
|
|
339
|
+
startCalibration,
|
|
340
|
+
dismissCalibration
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/write/create.ts
|
|
346
|
+
/** Measurement creation: a measurement annotation with the page's scale, through the annotation plugin. */
|
|
347
|
+
function createMeasuring(ctx, { siblings }, { scaleOf }) {
|
|
348
|
+
const { annotation } = siblings;
|
|
349
|
+
/**
|
|
350
|
+
* The measurement's engine draft: the tool's current defaults (style,
|
|
351
|
+
* caption and leader), the dimension intent, and the page's scale. The
|
|
352
|
+
* engine works out the label from the points and the scale.
|
|
353
|
+
*/
|
|
354
|
+
const draftOf = (input, page, tool) => {
|
|
355
|
+
const style = annotation.tools.getDefaults(tool);
|
|
356
|
+
const shared = {
|
|
357
|
+
color: style.color,
|
|
358
|
+
strokeWidth: style.strokeWidth,
|
|
359
|
+
opacity: style.opacity,
|
|
360
|
+
measure: scaleOf(page).measure,
|
|
361
|
+
captionEnabled: style.captionEnabled ?? true
|
|
362
|
+
};
|
|
363
|
+
switch (input.kind) {
|
|
364
|
+
case "distance": {
|
|
365
|
+
const [from, to] = input.points;
|
|
366
|
+
if (!from || !to || input.points.length !== 2) return new _embedpdf_core.PluginError("invalid-input", "measurement", "a distance needs exactly two points");
|
|
367
|
+
return {
|
|
368
|
+
subtype: "line",
|
|
369
|
+
intent: "line-dimension",
|
|
370
|
+
linePoints: {
|
|
371
|
+
start: from,
|
|
372
|
+
end: to
|
|
373
|
+
},
|
|
374
|
+
lineEndings: style.lineEndings,
|
|
375
|
+
interiorColor: style.interiorColor ?? style.color,
|
|
376
|
+
...shared,
|
|
377
|
+
captionPosition: style.captionPosition ?? "inline",
|
|
378
|
+
...style.leader ? { leader: style.leader } : {}
|
|
379
|
+
};
|
|
265
380
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
381
|
+
case "perimeter": return {
|
|
382
|
+
subtype: "polyline",
|
|
383
|
+
intent: "polyline-dimension",
|
|
384
|
+
vertices: input.points,
|
|
385
|
+
lineEndings: style.lineEndings,
|
|
386
|
+
...shared
|
|
387
|
+
};
|
|
388
|
+
case "area": return {
|
|
389
|
+
subtype: "polygon",
|
|
390
|
+
intent: "polygon-dimension",
|
|
391
|
+
vertices: input.points,
|
|
392
|
+
interiorColor: style.interiorColor,
|
|
393
|
+
...shared
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
const createMeasurement = async (input, options) => {
|
|
398
|
+
ctx.assertAllowed("annotations:create", "measurement.createMeasurement");
|
|
399
|
+
const page = ctx.pageOf(input.page).ref;
|
|
400
|
+
if (!scaleOf(page).ready) throw new _embedpdf_core.PluginError("not-ready", "measurement", "the page scale is not known yet");
|
|
401
|
+
const draft = draftOf(input, page, input.tool ?? input.kind);
|
|
402
|
+
if (draft instanceof Error) throw draft;
|
|
403
|
+
return annotation.create(page, draft, void 0, { signal: options?.signal });
|
|
269
404
|
};
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
405
|
+
return { api: { createMeasurement } };
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/write/scale.ts
|
|
409
|
+
/**
|
|
410
|
+
* Scale writes. Every change serializes per page, loads the page first, and
|
|
411
|
+
* re-measures the page's measurement annotations unless told not to. A
|
|
412
|
+
* multi-page change reports per-page failures; a single-page change rejects.
|
|
413
|
+
*/
|
|
414
|
+
function createScaleWrites(ctx, { events, store, siblings }, { ensureLoaded, refresh, scaleOf }) {
|
|
415
|
+
const { scaleChanged, calibrationCompleted } = events;
|
|
416
|
+
const { requirePage, targets } = store;
|
|
417
|
+
const { annotation } = siblings;
|
|
418
|
+
const settings = ctx.settings();
|
|
419
|
+
/** One write queue per page, so a page's scale changes land in order. */
|
|
420
|
+
const pageQueues = /* @__PURE__ */ new Map();
|
|
421
|
+
const queueOf = (page) => {
|
|
422
|
+
let queue = pageQueues.get(page.objectNumber);
|
|
423
|
+
if (!queue) {
|
|
424
|
+
queue = ctx.serialQueue(`scale:${page.objectNumber}`);
|
|
425
|
+
pageQueues.set(page.objectNumber, queue);
|
|
426
|
+
}
|
|
427
|
+
return queue;
|
|
278
428
|
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
429
|
+
ctx.onSettle(async () => {
|
|
430
|
+
await Promise.all([...pageQueues.values()].map((queue) => queue.idle()));
|
|
431
|
+
});
|
|
432
|
+
/** Write one page's scale (`null` = back to the default) and re-measure. */
|
|
433
|
+
const save = async (page, scale, options) => {
|
|
434
|
+
const { signal } = options;
|
|
435
|
+
ctx.assertAllowed(SCALE_PERMISSION, "changing a scale");
|
|
436
|
+
await ensureLoaded(page, { signal });
|
|
437
|
+
ctx.assertAllowed(SCALE_PERMISSION, "changing a scale");
|
|
438
|
+
const service = ctx.doc.page(page).measure;
|
|
284
439
|
if (service) {
|
|
285
|
-
await service.setScale(scale);
|
|
286
|
-
|
|
287
|
-
await refresh(pon);
|
|
440
|
+
await ctx.cancellable(signal, service.setScale(scale));
|
|
441
|
+
await ensureLoaded(page);
|
|
288
442
|
} else {
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
bbox:
|
|
443
|
+
const layout = requirePage(page);
|
|
444
|
+
const kept = (ctx.state.get().localViewports[page.objectNumber] ?? []).filter((viewport) => !viewport.owned);
|
|
445
|
+
ctx.state.update(setLocalViewports, page.objectNumber, [...kept, ...scale ? [{
|
|
446
|
+
bbox: {
|
|
447
|
+
x: 0,
|
|
448
|
+
y: 0,
|
|
449
|
+
...layout.size
|
|
450
|
+
},
|
|
293
451
|
name: "EmbedPDF",
|
|
294
452
|
owned: true,
|
|
295
453
|
measure: scale
|
|
296
|
-
}]);
|
|
454
|
+
}] : []]);
|
|
455
|
+
await refresh(page);
|
|
297
456
|
}
|
|
298
|
-
|
|
299
|
-
const report =
|
|
300
|
-
|
|
301
|
-
scale,
|
|
457
|
+
const effective = scale ?? require_contract.defaultMeasure(settings.get().defaultScale, requirePage(page).userUnit);
|
|
458
|
+
const report = options.recalculate === false ? {
|
|
459
|
+
page,
|
|
460
|
+
scale: effective,
|
|
302
461
|
updated: [],
|
|
303
462
|
skipped: [],
|
|
304
463
|
failed: []
|
|
305
|
-
} : await
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
report
|
|
311
|
-
});
|
|
312
|
-
} catch {}
|
|
464
|
+
} : await ctx.cancellable(signal, annotation.remeasurePage(page, effective));
|
|
465
|
+
scaleChanged.emit({
|
|
466
|
+
page,
|
|
467
|
+
report
|
|
468
|
+
});
|
|
313
469
|
return report;
|
|
314
470
|
};
|
|
315
|
-
const change = async (
|
|
316
|
-
assertAllowed();
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
471
|
+
const change = async (pages, measure, options = {}) => {
|
|
472
|
+
ctx.assertAllowed(SCALE_PERMISSION, "changing a scale");
|
|
473
|
+
const target = targets(pages);
|
|
474
|
+
if (options.signal?.aborted) throw new _embedpdf_core.PluginError("operation-cancelled", "measurement", "operation cancelled", { cause: options.signal.reason });
|
|
475
|
+
const tolerant = pages === "all" || target.length > 1;
|
|
476
|
+
ctx.state.update(beginScaleChange);
|
|
321
477
|
try {
|
|
322
|
-
const reports = await Promise.all(
|
|
478
|
+
const reports = await Promise.all(target.map((page) => queueOf(page)(async () => {
|
|
323
479
|
try {
|
|
324
|
-
await
|
|
325
|
-
const scale = measure(
|
|
326
|
-
(0, _embedpdf_engine_core_runtime.assertWritableMeasure)(scale);
|
|
327
|
-
return await save(
|
|
480
|
+
await ensureLoaded(page, { signal: options.signal });
|
|
481
|
+
const scale = measure(page);
|
|
482
|
+
if (scale) (0, _embedpdf_engine_core_runtime.assertWritableMeasure)(scale);
|
|
483
|
+
return await save(page, scale, options);
|
|
328
484
|
} catch (error) {
|
|
329
|
-
|
|
485
|
+
const refused = (0, _embedpdf_core.toPluginError)("measurement", error);
|
|
486
|
+
if (!tolerant || refused.code === "operation-cancelled") throw refused;
|
|
330
487
|
return {
|
|
331
|
-
|
|
488
|
+
page,
|
|
332
489
|
updated: [],
|
|
333
490
|
skipped: [],
|
|
334
491
|
failed: [],
|
|
335
492
|
scaleError: (0, _embedpdf_engine_core_runtime.serializeError)(error)
|
|
336
493
|
};
|
|
337
494
|
}
|
|
338
|
-
})));
|
|
339
|
-
|
|
340
|
-
ctx.dispatch({
|
|
341
|
-
type: "REPORTS",
|
|
342
|
-
reports
|
|
343
|
-
});
|
|
495
|
+
}, options)));
|
|
496
|
+
ctx.state.update(setReports, reports);
|
|
344
497
|
return reports;
|
|
345
498
|
} finally {
|
|
346
|
-
|
|
347
|
-
type: "PENDING",
|
|
348
|
-
delta: -1
|
|
349
|
-
});
|
|
499
|
+
ctx.state.update(endScaleChange);
|
|
350
500
|
}
|
|
351
501
|
};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
epochs.clear();
|
|
358
|
-
queues.clear();
|
|
359
|
-
calibrationListeners.clear();
|
|
360
|
-
scaleListeners.clear();
|
|
361
|
-
});
|
|
362
|
-
ctx.cleanup(anno.onDraftCaptured((draft) => {
|
|
363
|
-
if (draft.tool !== "calibrate" || !doc.security.allows("doc.annotate.modify")) return;
|
|
364
|
-
const a = (0, _embedpdf_engine_core_runtime.measurementPoint)(draft.from);
|
|
365
|
-
const b = (0, _embedpdf_engine_core_runtime.measurementPoint)(draft.to);
|
|
366
|
-
const userSpaceLength = Math.hypot(b.x - a.x, b.y - a.y);
|
|
367
|
-
if (!(userSpaceLength > 0)) return;
|
|
368
|
-
const request = {
|
|
369
|
-
pon: draft.pon,
|
|
370
|
-
from: a,
|
|
371
|
-
to: b,
|
|
372
|
-
userSpaceLength
|
|
373
|
-
};
|
|
374
|
-
interaction.activateTool("pointer");
|
|
375
|
-
ctx.dispatch({
|
|
376
|
-
type: "CALIBRATION",
|
|
377
|
-
request
|
|
378
|
-
});
|
|
379
|
-
for (const cb of calibrationListeners) try {
|
|
380
|
-
cb(request);
|
|
381
|
-
} catch {}
|
|
382
|
-
}));
|
|
383
|
-
const hydrate = () => {
|
|
384
|
-
for (const page of ctx.document()?.pages ?? []) refresh(page.pageObjectNumber).catch(() => {});
|
|
385
|
-
};
|
|
386
|
-
ctx.cleanup(doc.events.subscribe((event) => {
|
|
387
|
-
if (event.type === "page.viewportsChanged") refresh(event.pageObjectNumber).catch(() => {});
|
|
388
|
-
else if (event.type === "stream.desynced" || event.type === "document.versioned") hydrate();
|
|
389
|
-
}));
|
|
390
|
-
let pages = "";
|
|
391
|
-
const reconcile = () => {
|
|
392
|
-
const next = (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber).join(",");
|
|
393
|
-
if (next === pages) return;
|
|
394
|
-
pages = next;
|
|
395
|
-
for (const page of ctx.document()?.pages ?? []) if (!ctx.getState().pages[page.pageObjectNumber]) prepare(page.pageObjectNumber).catch(() => {});
|
|
396
|
-
};
|
|
397
|
-
ctx.cleanup(ctx.subscribe(reconcile));
|
|
398
|
-
reconcile();
|
|
502
|
+
/** The page's current rectilinear scale, for unit and precision edits. */
|
|
503
|
+
const rectilinearOf = (page) => {
|
|
504
|
+
const scale = scaleOf(page).measure;
|
|
505
|
+
if (!scale || scale.subtype !== "rectilinear") throw new _embedpdf_core.PluginError("not-ready", "measurement", "calibrate this page before changing its units or precision");
|
|
506
|
+
return scale;
|
|
399
507
|
};
|
|
400
|
-
|
|
401
|
-
start,
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
508
|
+
const calibrate = async (input, options = {}) => {
|
|
509
|
+
const start = (0, _embedpdf_engine_core_runtime.measurementPoint)(input.from);
|
|
510
|
+
const end = (0, _embedpdf_engine_core_runtime.measurementPoint)(input.to);
|
|
511
|
+
let scale;
|
|
512
|
+
try {
|
|
513
|
+
scale = (0, _embedpdf_engine_core_runtime.measureFromKnownLength)(Math.hypot(end.x - start.x, end.y - start.y), input.distance);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
throw new _embedpdf_core.PluginError("invalid-input", "measurement", String(error.message ?? error));
|
|
516
|
+
}
|
|
517
|
+
const { applyTo, ...rest } = options;
|
|
518
|
+
const page = requirePage(input.page).ref;
|
|
519
|
+
const reports = await change(applyTo ?? page, () => scale, rest);
|
|
520
|
+
const request = ctx.state.get().calibration;
|
|
521
|
+
if (request && (0, _embedpdf_engine_core_runtime.pageRefsEqual)(request.page, page)) ctx.state.update(setCalibration, null);
|
|
522
|
+
calibrationCompleted.emit({ page });
|
|
523
|
+
return reports;
|
|
406
524
|
};
|
|
525
|
+
return { api: {
|
|
526
|
+
setScale: (pages, measure, options) => change(pages, () => measure, options),
|
|
527
|
+
calibrate,
|
|
528
|
+
setUnit: (pages, unit, options) => change(pages, (page) => require_contract.withUnit(rectilinearOf(page), unit), options),
|
|
529
|
+
setAreaUnit: (pages, unit, options) => change(pages, (page) => require_contract.withAreaUnit(rectilinearOf(page), unit), options),
|
|
530
|
+
setPrecision: (pages, precision, options) => change(pages, (page) => require_contract.withPrecision(rectilinearOf(page), precision), options),
|
|
531
|
+
setPreset: (pages, presetId, options) => {
|
|
532
|
+
const preset = settings.get().presets.find((candidate) => candidate.id === presetId);
|
|
533
|
+
if (!preset) return Promise.reject(new _embedpdf_core.PluginError("not-found", "measurement", `unknown scale preset '${presetId}'`));
|
|
534
|
+
return change(pages, (page) => (0, _embedpdf_engine_core_runtime.measureFromRatio)(preset.paper, preset.real, preset.unit, { userUnit: ctx.getPage(page)?.userUnit ?? 1 }), options);
|
|
535
|
+
},
|
|
536
|
+
clearScale: (pages, options) => change(pages, () => null, options)
|
|
537
|
+
} };
|
|
407
538
|
}
|
|
408
539
|
//#endregion
|
|
409
|
-
//#region src/
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
function
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
540
|
+
//#region src/controller.ts
|
|
541
|
+
/**
|
|
542
|
+
* The measurement controller: the composition root. It builds the plugin's
|
|
543
|
+
* services once, wires each area with the services it declares, and
|
|
544
|
+
* assembles the capability from the areas' API slices. No behavior lives
|
|
545
|
+
* here: every verb and read has a home in `read/`, `write/` or `sync/`.
|
|
546
|
+
*/
|
|
547
|
+
function createMeasurementController(ctx) {
|
|
548
|
+
const services = createServices(ctx);
|
|
549
|
+
const { events, store } = services;
|
|
550
|
+
const settings = ctx.settings();
|
|
551
|
+
const viewports = createViewportSync(ctx, services);
|
|
552
|
+
const reads = createScaleReads(ctx, services, viewports);
|
|
553
|
+
const scale = createScaleWrites(ctx, services, viewports);
|
|
554
|
+
const calibration = createCalibration(ctx, services);
|
|
555
|
+
const measuring = createMeasuring(ctx, services, viewports);
|
|
556
|
+
return {
|
|
557
|
+
api: (0, _embedpdf_core.composeApi)("measurement", [
|
|
558
|
+
settings.api,
|
|
559
|
+
reads.api,
|
|
560
|
+
scale.api,
|
|
561
|
+
calibration.api,
|
|
562
|
+
measuring.api,
|
|
563
|
+
{
|
|
564
|
+
canCalibrate: store.canCalibrate,
|
|
565
|
+
ensureLoaded: viewports.ensureLoaded,
|
|
566
|
+
onScaleChanged: events.scaleChanged.on,
|
|
567
|
+
onCalibrationRequested: events.calibrationRequested.on,
|
|
568
|
+
onCalibrationCompleted: events.calibrationCompleted.on,
|
|
569
|
+
onCalibrationDismissed: events.calibrationDismissed.on
|
|
426
570
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
...s,
|
|
434
|
-
calibration: a.request
|
|
435
|
-
};
|
|
436
|
-
case "REPORTS": return {
|
|
437
|
-
...s,
|
|
438
|
-
reports: a.reports
|
|
439
|
-
};
|
|
440
|
-
}
|
|
571
|
+
]),
|
|
572
|
+
connect() {
|
|
573
|
+
calibration.connect();
|
|
574
|
+
viewports.connect();
|
|
575
|
+
}
|
|
576
|
+
};
|
|
441
577
|
}
|
|
442
578
|
//#endregion
|
|
443
579
|
//#region src/measurement.plugin.ts
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
580
|
+
/**
|
|
581
|
+
* Page scale, calibration and measurement readouts, document-scoped. The
|
|
582
|
+
* annotation plugin owns the measurement annotations; this plugin owns the
|
|
583
|
+
* page's viewports (the scale), keeps the annotation plugin's measure in step,
|
|
584
|
+
* and turns the calibrate tool's drafts into scale requests. `config` is the
|
|
585
|
+
* settings the app registers, over {@link MEASUREMENT_DEFAULTS}.
|
|
586
|
+
*/
|
|
587
|
+
const measurementPlugin = (config) => (0, _embedpdf_core.definePlugin)({
|
|
588
|
+
id: "measurement",
|
|
589
|
+
scope: "document",
|
|
590
|
+
token: require_contract.MeasurementToken,
|
|
591
|
+
requires: [_embedpdf_plugin_annotation_contract_host.AnnotationToken, _embedpdf_plugin_interaction_contract.InteractionToken],
|
|
592
|
+
state: initialMeasurementState,
|
|
593
|
+
settings: {
|
|
594
|
+
defaults: require_contract.MEASUREMENT_DEFAULTS,
|
|
595
|
+
registered: config,
|
|
596
|
+
whole: ["defaultScale"]
|
|
597
|
+
},
|
|
598
|
+
create: createMeasurementController
|
|
599
|
+
});
|
|
600
|
+
//#endregion
|
|
601
|
+
//#region src/state.ts
|
|
602
|
+
/**
|
|
603
|
+
* The measurements page's State table as code: what `useMeasurementState()`
|
|
604
|
+
* returns, and the same fields in every other framework. A page's scale and a
|
|
605
|
+
* measurement's readout are not here: `usePageScale(page)` and
|
|
606
|
+
* `useMeasurementReadout(ref)` read them, so a component re-renders only for
|
|
607
|
+
* its own page or measurement.
|
|
608
|
+
*/
|
|
609
|
+
const measurementState = (0, _embedpdf_core.defineState)(require_contract.MeasurementToken, {
|
|
610
|
+
read: (measurement) => ({
|
|
611
|
+
busy: measurement.isBusy(),
|
|
612
|
+
calibrationRequest: measurement.getCalibrationRequest(),
|
|
613
|
+
lastReports: measurement.listLastReports()
|
|
614
|
+
}),
|
|
615
|
+
empty: {
|
|
616
|
+
busy: false,
|
|
617
|
+
calibrationRequest: null,
|
|
618
|
+
lastReports: NO_REPORTS
|
|
619
|
+
}
|
|
620
|
+
});
|
|
467
621
|
//#endregion
|
|
622
|
+
exports.MEASUREMENT_DEFAULTS = require_contract.MEASUREMENT_DEFAULTS;
|
|
468
623
|
exports.MeasurementToken = require_contract.MeasurementToken;
|
|
624
|
+
exports.NO_PAGE_SCALE = require_contract.NO_PAGE_SCALE;
|
|
625
|
+
exports.NO_READOUT = require_contract.NO_READOUT;
|
|
469
626
|
exports.measurementPlugin = measurementPlugin;
|
|
627
|
+
exports.measurementState = measurementState;
|
|
470
628
|
|
|
471
629
|
//# sourceMappingURL=index.cjs.map
|