@baron1996/klinecharts-runtime 0.2.3 → 0.4.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 +1 -1
- package/dist/drawing/capabilities.d.ts +36 -0
- package/dist/drawing/capabilities.d.ts.map +1 -0
- package/dist/drawing/capabilities.js +1 -0
- package/dist/drawing/legacy-runtime-capability.d.ts +8 -0
- package/dist/drawing/legacy-runtime-capability.d.ts.map +1 -0
- package/dist/drawing/legacy-runtime-capability.js +92 -0
- package/dist/drawing/projection-service.d.ts +80 -0
- package/dist/drawing/projection-service.d.ts.map +1 -0
- package/dist/drawing/projection-service.js +523 -0
- package/dist/drawing/runtime-capability-descriptor.d.ts +28 -0
- package/dist/drawing/runtime-capability-descriptor.d.ts.map +1 -0
- package/dist/drawing/runtime-capability-descriptor.js +1 -0
- package/dist/drawing/scene-runtime-factory.d.ts +15 -0
- package/dist/drawing/scene-runtime-factory.d.ts.map +1 -0
- package/dist/drawing/scene-runtime-factory.js +27 -0
- package/dist/drawing/session-controller.d.ts +53 -0
- package/dist/drawing/session-controller.d.ts.map +1 -0
- package/dist/drawing/session-controller.js +339 -0
- package/dist/drawing/workspace-events.d.ts +66 -0
- package/dist/drawing/workspace-events.d.ts.map +1 -0
- package/dist/drawing/workspace-events.js +12 -0
- package/dist/drawing/workspace-runtime.d.ts +60 -0
- package/dist/drawing/workspace-runtime.d.ts.map +1 -0
- package/dist/drawing/workspace-runtime.js +328 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/runtime.d.ts +29 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +97 -1
- package/dist/time-series-runtime-styles.d.ts +2 -0
- package/dist/time-series-runtime-styles.d.ts.map +1 -0
- package/dist/time-series-runtime-styles.js +98 -0
- package/dist/time-series-runtime.d.ts +3 -0
- package/dist/time-series-runtime.d.ts.map +1 -0
- package/dist/time-series-runtime.js +301 -0
- package/dist/time-series-types.d.ts +42 -0
- package/dist/time-series-types.d.ts.map +1 -0
- package/dist/time-series-types.js +1 -0
- package/dist/toolbar/standard-toolbar-styles.d.ts.map +1 -1
- package/dist/toolbar/standard-toolbar-styles.js +18 -0
- package/dist/toolbar/standard-toolbar.d.ts +4 -2
- package/dist/toolbar/standard-toolbar.d.ts.map +1 -1
- package/dist/toolbar/standard-toolbar.js +187 -31
- package/dist/toolbar/toolbar-icons.d.ts +26 -0
- package/dist/toolbar/toolbar-icons.d.ts.map +1 -1
- package/dist/toolbar/toolbar-icons.js +13 -0
- package/dist/toolbar/toolbar-tools.d.ts +6 -1
- package/dist/toolbar/toolbar-tools.d.ts.map +1 -1
- package/dist/toolbar/toolbar-tools.js +6 -0
- package/dist/types.d.ts +7 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import { normalizeDecimalValue } from '@baron1996/kline-scene-schema';
|
|
3
|
+
import { DrawingProjectionError, KLineDrawingProjectionPolicy, TimeSeriesDrawingProjectionPolicy, } from '@baron1996/klinecharts-adapter';
|
|
4
|
+
const EPOCH_DATE = Temporal.PlainDate.from('1970-01-01');
|
|
5
|
+
function zoned(timestamp, timezone) {
|
|
6
|
+
return Temporal.Instant.fromEpochMilliseconds(timestamp).toZonedDateTimeISO(timezone);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 纯时间桶、22 种几何与反投影核心;不持有 Adapter/引擎,输入输出深拷贝。
|
|
10
|
+
*/
|
|
11
|
+
export class DrawingProjectionService {
|
|
12
|
+
#klinePolicy = new KLineDrawingProjectionPolicy();
|
|
13
|
+
#timeSeriesPolicy = new TimeSeriesDrawingProjectionPolicy();
|
|
14
|
+
addPeriod(timestamp, period, timezone) {
|
|
15
|
+
const duration = durationLike(period);
|
|
16
|
+
return zoned(timestamp, timezone).add(duration).epochMilliseconds;
|
|
17
|
+
}
|
|
18
|
+
#periodStart(timestamp, period, timezone) {
|
|
19
|
+
if (period.type === 'second' ||
|
|
20
|
+
period.type === 'minute' ||
|
|
21
|
+
period.type === 'hour') {
|
|
22
|
+
const unitMilliseconds = period.type === 'second'
|
|
23
|
+
? 1000
|
|
24
|
+
: period.type === 'minute'
|
|
25
|
+
? 60_000
|
|
26
|
+
: 3_600_000;
|
|
27
|
+
const bucketSize = unitMilliseconds * period.span;
|
|
28
|
+
return Math.floor(timestamp / bucketSize) * bucketSize;
|
|
29
|
+
}
|
|
30
|
+
const date = zoned(timestamp, timezone).toPlainDate();
|
|
31
|
+
if (period.type === 'day') {
|
|
32
|
+
const days = date.since(EPOCH_DATE, { largestUnit: 'day' }).days;
|
|
33
|
+
const bucket = Math.floor(days / period.span);
|
|
34
|
+
return dateStart(EPOCH_DATE.add({ days: bucket * period.span }), timezone);
|
|
35
|
+
}
|
|
36
|
+
if (period.type === 'week') {
|
|
37
|
+
const days = date.since(EPOCH_DATE, { largestUnit: 'day' }).days;
|
|
38
|
+
const bucket = Math.floor(days / (7 * period.span));
|
|
39
|
+
return dateStart(EPOCH_DATE.add({ days: bucket * 7 * period.span }), timezone);
|
|
40
|
+
}
|
|
41
|
+
if (period.type === 'month') {
|
|
42
|
+
const months = date.since(EPOCH_DATE, { largestUnit: 'month' }).months;
|
|
43
|
+
const bucket = Math.floor(months / period.span);
|
|
44
|
+
return dateStart(EPOCH_DATE.add({ months: bucket * period.span }), timezone);
|
|
45
|
+
}
|
|
46
|
+
const years = date.since(EPOCH_DATE, { largestUnit: 'year' }).years;
|
|
47
|
+
const bucket = Math.floor(years / period.span);
|
|
48
|
+
return dateStart(EPOCH_DATE.add({ years: bucket * period.span }), timezone);
|
|
49
|
+
}
|
|
50
|
+
#barRange(timestamp, data, scenePeriod, timezone) {
|
|
51
|
+
for (let index = 0; index < data.length; index++) {
|
|
52
|
+
const start = data[index].timestamp;
|
|
53
|
+
const end = index + 1 < data.length
|
|
54
|
+
? data[index + 1].timestamp
|
|
55
|
+
: this.addPeriod(start, scenePeriod, timezone);
|
|
56
|
+
if (timestamp >= start && timestamp < end) {
|
|
57
|
+
return { start, end, dataIndex: index };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
#projectAnchor(anchor, data, scenePeriod, timezone) {
|
|
63
|
+
const bar = this.#barRange(anchor.timestamp, data, scenePeriod, timezone);
|
|
64
|
+
const start = this.#periodStart(anchor.timestamp, anchor.granularity, timezone);
|
|
65
|
+
const end = this.addPeriod(start, anchor.granularity, timezone);
|
|
66
|
+
if (bar === null) {
|
|
67
|
+
return {
|
|
68
|
+
kind: 'outside-data-range',
|
|
69
|
+
startTimestamp: start,
|
|
70
|
+
endTimestamp: end,
|
|
71
|
+
dataIndex: null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (start === bar.start && end === bar.end) {
|
|
75
|
+
return {
|
|
76
|
+
kind: 'exact',
|
|
77
|
+
startTimestamp: start,
|
|
78
|
+
endTimestamp: end,
|
|
79
|
+
dataIndex: bar.dataIndex,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (start >= bar.start && end <= bar.end) {
|
|
83
|
+
return {
|
|
84
|
+
kind: 'first-child',
|
|
85
|
+
startTimestamp: start,
|
|
86
|
+
endTimestamp: end,
|
|
87
|
+
dataIndex: bar.dataIndex,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (start <= bar.start && end >= bar.end) {
|
|
91
|
+
return {
|
|
92
|
+
kind: 'containing-interval',
|
|
93
|
+
startTimestamp: start,
|
|
94
|
+
endTimestamp: end,
|
|
95
|
+
dataIndex: bar.dataIndex,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
kind: 'outside-data-range',
|
|
100
|
+
startTimestamp: start,
|
|
101
|
+
endTimestamp: end,
|
|
102
|
+
dataIndex: null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
projectDrawing(input) {
|
|
106
|
+
const policy = this.#policyFor(input.scene);
|
|
107
|
+
const binding = policy.resolveAxisBinding({
|
|
108
|
+
scene: input.scene,
|
|
109
|
+
drawing: input.drawing,
|
|
110
|
+
valueAxes: input.valueAxes,
|
|
111
|
+
path: input.path,
|
|
112
|
+
});
|
|
113
|
+
if (binding.scale === 'logarithmic' &&
|
|
114
|
+
geometryValues(input.drawing).some((value) => value <= 0)) {
|
|
115
|
+
throw new DrawingProjectionError('VALUE_AXIS_SCALE_UNSUPPORTED', input.path, 'Logarithmic value axes reject non-positive Drawing values.');
|
|
116
|
+
}
|
|
117
|
+
const data = input.scene.kind === 'chart'
|
|
118
|
+
? input.scene.document.data
|
|
119
|
+
: input.scene.document.data;
|
|
120
|
+
const scenePeriod = input.scene.kind === 'chart'
|
|
121
|
+
? input.scene.document.period
|
|
122
|
+
: input.scene.document.period;
|
|
123
|
+
const timezone = input.scene.kind === 'chart'
|
|
124
|
+
? input.scene.document.chart.timezone
|
|
125
|
+
: input.scene.document.chart.timezone;
|
|
126
|
+
const anchors = geometryAnchors(input.drawing, scenePeriod).map((entry) => ({
|
|
127
|
+
timestamp: entry.anchor.timestamp,
|
|
128
|
+
granularity: structuredClone(entry.anchor.granularity),
|
|
129
|
+
value: entry.value,
|
|
130
|
+
bucket: this.#projectAnchor(entry.anchor, data, scenePeriod, timezone),
|
|
131
|
+
}));
|
|
132
|
+
const visible = anchors.length === 0 ||
|
|
133
|
+
anchors.every((anchor) => anchor.bucket.kind !== 'outside-data-range');
|
|
134
|
+
return {
|
|
135
|
+
drawing: structuredClone(input.drawing),
|
|
136
|
+
binding,
|
|
137
|
+
anchors,
|
|
138
|
+
visible,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
projectDocument(input) {
|
|
142
|
+
const drawings = input.drawings.drawings.map((drawing, index) => this.projectDrawing({
|
|
143
|
+
scene: input.scene,
|
|
144
|
+
drawing,
|
|
145
|
+
valueAxes: input.drawings.coordinateSystem.valueAxes,
|
|
146
|
+
path: `/drawings/${index}`,
|
|
147
|
+
}));
|
|
148
|
+
return {
|
|
149
|
+
scopeKey: input.drawings.scopeKey,
|
|
150
|
+
timezone: input.drawings.coordinateSystem.timezone,
|
|
151
|
+
drawings,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
reverseProjectAnchor(input) {
|
|
155
|
+
const { original, editingScenePeriod, targetTimestamp, data, scenePeriod, timezone } = input;
|
|
156
|
+
const originalLength = this.addPeriod(original.timestamp, original.granularity, timezone) -
|
|
157
|
+
original.timestamp;
|
|
158
|
+
const editingLength = this.addPeriod(original.timestamp, editingScenePeriod, timezone) -
|
|
159
|
+
original.timestamp;
|
|
160
|
+
const bar = this.#barRange(targetTimestamp, data, scenePeriod, timezone);
|
|
161
|
+
if (bar === null) {
|
|
162
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', '/target', 'Target timestamp does not map to a Scene bar interval.');
|
|
163
|
+
}
|
|
164
|
+
if (editingLength < originalLength) {
|
|
165
|
+
return {
|
|
166
|
+
timestamp: bar.start,
|
|
167
|
+
granularity: structuredClone(editingScenePeriod),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (editingLength === originalLength) {
|
|
171
|
+
return {
|
|
172
|
+
timestamp: bar.start,
|
|
173
|
+
granularity: structuredClone(original.granularity),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const oldStart = this.#periodStart(original.timestamp, original.granularity, timezone);
|
|
177
|
+
const newStart = this.#periodStart(targetTimestamp, original.granularity, timezone);
|
|
178
|
+
const oldEnd = this.addPeriod(oldStart, original.granularity, timezone);
|
|
179
|
+
const newEnd = this.addPeriod(newStart, original.granularity, timezone);
|
|
180
|
+
const duration = zoned(original.timestamp, timezone).since(zoned(oldStart, timezone), {
|
|
181
|
+
largestUnit: original.granularity.type,
|
|
182
|
+
smallestUnit: 'millisecond',
|
|
183
|
+
roundingMode: 'trunc',
|
|
184
|
+
});
|
|
185
|
+
let candidate = zoned(newStart, timezone).add(duration).epochMilliseconds;
|
|
186
|
+
let iterations = 0;
|
|
187
|
+
while (candidate < newStart || candidate >= newEnd) {
|
|
188
|
+
if (iterations >= 100_000) {
|
|
189
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', '/target', 'Coarse-period reverse projection exceeded 100000 adjustments.');
|
|
190
|
+
}
|
|
191
|
+
iterations += 1;
|
|
192
|
+
if (candidate < newStart) {
|
|
193
|
+
const next = this.addPeriod(candidate, original.granularity, timezone);
|
|
194
|
+
if (next >= newEnd) {
|
|
195
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', '/target', 'Coarse-period reverse projection crossed the far boundary.');
|
|
196
|
+
}
|
|
197
|
+
candidate = next;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const next = zoned(candidate, timezone)
|
|
201
|
+
.subtract(durationLike(original.granularity))
|
|
202
|
+
.epochMilliseconds;
|
|
203
|
+
if (next < newStart) {
|
|
204
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', '/target', 'Coarse-period reverse projection crossed the near boundary.');
|
|
205
|
+
}
|
|
206
|
+
candidate = next;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
timestamp: candidate,
|
|
211
|
+
granularity: structuredClone(original.granularity),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
reverseProjectDrawing(input) {
|
|
215
|
+
const policy = this.#policyFor(input.scene);
|
|
216
|
+
const binding = policy.resolveAxisBinding({
|
|
217
|
+
scene: input.scene,
|
|
218
|
+
drawing: input.drawing,
|
|
219
|
+
valueAxes: input.valueAxes,
|
|
220
|
+
path: input.path,
|
|
221
|
+
});
|
|
222
|
+
const data = input.scene.kind === 'chart'
|
|
223
|
+
? input.scene.document.data
|
|
224
|
+
: input.scene.document.data;
|
|
225
|
+
const scenePeriod = input.scene.kind === 'chart'
|
|
226
|
+
? input.scene.document.period
|
|
227
|
+
: input.scene.document.period;
|
|
228
|
+
const timezone = input.scene.kind === 'chart'
|
|
229
|
+
? input.scene.document.chart.timezone
|
|
230
|
+
: input.scene.document.chart.timezone;
|
|
231
|
+
const candidate = structuredClone(input.drawing);
|
|
232
|
+
const horizontal = input.horizontal;
|
|
233
|
+
const vertical = input.vertical;
|
|
234
|
+
if (horizontal !== undefined) {
|
|
235
|
+
mapTimeAnchors(candidate, scenePeriod, (anchor) => this.reverseProjectAnchor({
|
|
236
|
+
original: anchor,
|
|
237
|
+
editingScenePeriod: horizontal.editingScenePeriod,
|
|
238
|
+
targetTimestamp: horizontal.targetTimestamp,
|
|
239
|
+
data,
|
|
240
|
+
scenePeriod,
|
|
241
|
+
timezone,
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
if (vertical !== undefined) {
|
|
245
|
+
let valueIndex = 0;
|
|
246
|
+
mapValueAnchors(candidate, (value) => {
|
|
247
|
+
const replacement = vertical.values[valueIndex];
|
|
248
|
+
valueIndex += 1;
|
|
249
|
+
if (replacement === undefined) {
|
|
250
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', input.path, 'Vertical edit values must match the Drawing value anchor count.');
|
|
251
|
+
}
|
|
252
|
+
return normalizeDecimalValue(replacement, binding.valuePrecision);
|
|
253
|
+
});
|
|
254
|
+
if (valueIndex !== vertical.values.length) {
|
|
255
|
+
throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', input.path, 'Vertical edit values must match the Drawing value anchor count.');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return candidate;
|
|
259
|
+
}
|
|
260
|
+
#policyFor(scene) {
|
|
261
|
+
return scene.kind === 'chart'
|
|
262
|
+
? this.#klinePolicy
|
|
263
|
+
: this.#timeSeriesPolicy;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function durationLike(period) {
|
|
267
|
+
switch (period.type) {
|
|
268
|
+
case 'second':
|
|
269
|
+
return { seconds: period.span };
|
|
270
|
+
case 'minute':
|
|
271
|
+
return { minutes: period.span };
|
|
272
|
+
case 'hour':
|
|
273
|
+
return { hours: period.span };
|
|
274
|
+
case 'day':
|
|
275
|
+
return { days: period.span };
|
|
276
|
+
case 'week':
|
|
277
|
+
return { weeks: period.span };
|
|
278
|
+
case 'month':
|
|
279
|
+
return { months: period.span };
|
|
280
|
+
case 'year':
|
|
281
|
+
return { years: period.span };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function dateStart(date, timezone) {
|
|
285
|
+
return date
|
|
286
|
+
.toZonedDateTime({ timeZone: timezone, plainTime: '00:00' })
|
|
287
|
+
.epochMilliseconds;
|
|
288
|
+
}
|
|
289
|
+
export function geometryAnchors(drawing, defaultGranularity) {
|
|
290
|
+
const result = [];
|
|
291
|
+
const add = (anchor, value = null) => {
|
|
292
|
+
result.push({ anchor, value });
|
|
293
|
+
};
|
|
294
|
+
switch (drawing.type) {
|
|
295
|
+
case 'horizontalStraightLine':
|
|
296
|
+
case 'priceLine':
|
|
297
|
+
case 'simpleTag':
|
|
298
|
+
break;
|
|
299
|
+
case 'verticalStraightLine':
|
|
300
|
+
add({
|
|
301
|
+
timestamp: drawing.geometry.time,
|
|
302
|
+
granularity: defaultGranularity,
|
|
303
|
+
});
|
|
304
|
+
break;
|
|
305
|
+
case 'horizontalRayLine':
|
|
306
|
+
case 'horizontalSegment':
|
|
307
|
+
add({
|
|
308
|
+
timestamp: drawing.geometry.startTime,
|
|
309
|
+
granularity: defaultGranularity,
|
|
310
|
+
}, drawing.geometry.value);
|
|
311
|
+
add({
|
|
312
|
+
timestamp: drawing.geometry.endTime,
|
|
313
|
+
granularity: defaultGranularity,
|
|
314
|
+
}, drawing.geometry.value);
|
|
315
|
+
break;
|
|
316
|
+
case 'verticalRayLine':
|
|
317
|
+
case 'verticalSegment':
|
|
318
|
+
add({
|
|
319
|
+
timestamp: drawing.geometry.time,
|
|
320
|
+
granularity: defaultGranularity,
|
|
321
|
+
}, null);
|
|
322
|
+
break;
|
|
323
|
+
case 'rayLine':
|
|
324
|
+
case 'segment':
|
|
325
|
+
case 'straightLine':
|
|
326
|
+
case 'fibonacciLine':
|
|
327
|
+
case 'priceChannelLine':
|
|
328
|
+
case 'parallelStraightLine':
|
|
329
|
+
case 'brush':
|
|
330
|
+
for (const point of drawing.geometry.points) {
|
|
331
|
+
add({ timestamp: point.timestamp, granularity: point.granularity }, point.value);
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
case 'simpleAnnotation':
|
|
335
|
+
case 'callout':
|
|
336
|
+
case 'text':
|
|
337
|
+
case 'crossLine':
|
|
338
|
+
add({
|
|
339
|
+
timestamp: drawing.geometry.point.timestamp,
|
|
340
|
+
granularity: drawing.geometry.point.granularity,
|
|
341
|
+
}, drawing.geometry.point.value);
|
|
342
|
+
break;
|
|
343
|
+
case 'rectangle':
|
|
344
|
+
case 'arrow':
|
|
345
|
+
case 'priceMeasurement':
|
|
346
|
+
add({
|
|
347
|
+
timestamp: drawing.geometry.start.timestamp,
|
|
348
|
+
granularity: drawing.geometry.start.granularity,
|
|
349
|
+
}, drawing.geometry.start.value);
|
|
350
|
+
add({
|
|
351
|
+
timestamp: drawing.geometry.end.timestamp,
|
|
352
|
+
granularity: drawing.geometry.end.granularity,
|
|
353
|
+
}, drawing.geometry.end.value);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
function mapTimeAnchors(drawing, defaultGranularity, transform) {
|
|
359
|
+
switch (drawing.type) {
|
|
360
|
+
case 'verticalStraightLine':
|
|
361
|
+
drawing.geometry.time = transform({
|
|
362
|
+
timestamp: drawing.geometry.time,
|
|
363
|
+
granularity: defaultGranularity,
|
|
364
|
+
}).timestamp;
|
|
365
|
+
break;
|
|
366
|
+
case 'horizontalRayLine':
|
|
367
|
+
case 'horizontalSegment':
|
|
368
|
+
drawing.geometry.startTime = transform({
|
|
369
|
+
timestamp: drawing.geometry.startTime,
|
|
370
|
+
granularity: defaultGranularity,
|
|
371
|
+
}).timestamp;
|
|
372
|
+
drawing.geometry.endTime = transform({
|
|
373
|
+
timestamp: drawing.geometry.endTime,
|
|
374
|
+
granularity: defaultGranularity,
|
|
375
|
+
}).timestamp;
|
|
376
|
+
break;
|
|
377
|
+
case 'verticalRayLine':
|
|
378
|
+
case 'verticalSegment':
|
|
379
|
+
drawing.geometry.time = transform({
|
|
380
|
+
timestamp: drawing.geometry.time,
|
|
381
|
+
granularity: defaultGranularity,
|
|
382
|
+
}).timestamp;
|
|
383
|
+
break;
|
|
384
|
+
case 'rayLine':
|
|
385
|
+
case 'segment':
|
|
386
|
+
case 'straightLine':
|
|
387
|
+
case 'fibonacciLine':
|
|
388
|
+
case 'priceChannelLine':
|
|
389
|
+
case 'parallelStraightLine':
|
|
390
|
+
case 'brush':
|
|
391
|
+
for (const point of drawing.geometry.points) {
|
|
392
|
+
const updated = transform({
|
|
393
|
+
timestamp: point.timestamp,
|
|
394
|
+
granularity: point.granularity,
|
|
395
|
+
});
|
|
396
|
+
point.timestamp = updated.timestamp;
|
|
397
|
+
point.granularity = updated.granularity;
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
400
|
+
case 'simpleAnnotation':
|
|
401
|
+
case 'callout':
|
|
402
|
+
case 'text':
|
|
403
|
+
case 'crossLine':
|
|
404
|
+
case 'rectangle':
|
|
405
|
+
case 'arrow':
|
|
406
|
+
case 'priceMeasurement': {
|
|
407
|
+
const point = 'point' in drawing.geometry
|
|
408
|
+
? drawing.geometry.point
|
|
409
|
+
: undefined;
|
|
410
|
+
if (point !== undefined) {
|
|
411
|
+
const updated = transform({
|
|
412
|
+
timestamp: point.timestamp,
|
|
413
|
+
granularity: point.granularity,
|
|
414
|
+
});
|
|
415
|
+
point.timestamp = updated.timestamp;
|
|
416
|
+
point.granularity = updated.granularity;
|
|
417
|
+
}
|
|
418
|
+
if ('start' in drawing.geometry) {
|
|
419
|
+
const updated = transform({
|
|
420
|
+
timestamp: drawing.geometry.start.timestamp,
|
|
421
|
+
granularity: drawing.geometry.start.granularity,
|
|
422
|
+
});
|
|
423
|
+
drawing.geometry.start.timestamp = updated.timestamp;
|
|
424
|
+
drawing.geometry.start.granularity = updated.granularity;
|
|
425
|
+
const endUpdated = transform({
|
|
426
|
+
timestamp: drawing.geometry.end.timestamp,
|
|
427
|
+
granularity: drawing.geometry.end.granularity,
|
|
428
|
+
});
|
|
429
|
+
drawing.geometry.end.timestamp = endUpdated.timestamp;
|
|
430
|
+
drawing.geometry.end.granularity = endUpdated.granularity;
|
|
431
|
+
}
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
case 'horizontalStraightLine':
|
|
435
|
+
case 'priceLine':
|
|
436
|
+
case 'simpleTag':
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function mapValueAnchors(drawing, transform) {
|
|
441
|
+
switch (drawing.type) {
|
|
442
|
+
case 'horizontalStraightLine':
|
|
443
|
+
case 'priceLine':
|
|
444
|
+
case 'simpleTag':
|
|
445
|
+
drawing.geometry.value = transform(drawing.geometry.value);
|
|
446
|
+
break;
|
|
447
|
+
case 'horizontalRayLine':
|
|
448
|
+
case 'horizontalSegment':
|
|
449
|
+
drawing.geometry.value = transform(drawing.geometry.value);
|
|
450
|
+
break;
|
|
451
|
+
case 'verticalRayLine':
|
|
452
|
+
case 'verticalSegment':
|
|
453
|
+
drawing.geometry.startValue = transform(drawing.geometry.startValue);
|
|
454
|
+
drawing.geometry.endValue = transform(drawing.geometry.endValue);
|
|
455
|
+
break;
|
|
456
|
+
case 'rayLine':
|
|
457
|
+
case 'segment':
|
|
458
|
+
case 'straightLine':
|
|
459
|
+
case 'fibonacciLine':
|
|
460
|
+
case 'priceChannelLine':
|
|
461
|
+
case 'parallelStraightLine':
|
|
462
|
+
case 'brush':
|
|
463
|
+
for (const point of drawing.geometry.points) {
|
|
464
|
+
point.value = transform(point.value);
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
case 'simpleAnnotation':
|
|
468
|
+
case 'callout':
|
|
469
|
+
case 'text':
|
|
470
|
+
case 'crossLine':
|
|
471
|
+
drawing.geometry.point.value = transform(drawing.geometry.point.value);
|
|
472
|
+
break;
|
|
473
|
+
case 'rectangle':
|
|
474
|
+
case 'arrow':
|
|
475
|
+
case 'priceMeasurement':
|
|
476
|
+
drawing.geometry.start.value = transform(drawing.geometry.start.value);
|
|
477
|
+
drawing.geometry.end.value = transform(drawing.geometry.end.value);
|
|
478
|
+
break;
|
|
479
|
+
case 'verticalStraightLine':
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function geometryValues(drawing) {
|
|
484
|
+
const values = [];
|
|
485
|
+
switch (drawing.type) {
|
|
486
|
+
case 'horizontalStraightLine':
|
|
487
|
+
case 'priceLine':
|
|
488
|
+
case 'simpleTag':
|
|
489
|
+
case 'horizontalRayLine':
|
|
490
|
+
case 'horizontalSegment':
|
|
491
|
+
values.push(drawing.geometry.value);
|
|
492
|
+
break;
|
|
493
|
+
case 'verticalRayLine':
|
|
494
|
+
case 'verticalSegment':
|
|
495
|
+
values.push(drawing.geometry.startValue, drawing.geometry.endValue);
|
|
496
|
+
break;
|
|
497
|
+
case 'rayLine':
|
|
498
|
+
case 'segment':
|
|
499
|
+
case 'straightLine':
|
|
500
|
+
case 'fibonacciLine':
|
|
501
|
+
case 'priceChannelLine':
|
|
502
|
+
case 'parallelStraightLine':
|
|
503
|
+
case 'brush':
|
|
504
|
+
for (const point of drawing.geometry.points) {
|
|
505
|
+
values.push(point.value);
|
|
506
|
+
}
|
|
507
|
+
break;
|
|
508
|
+
case 'simpleAnnotation':
|
|
509
|
+
case 'callout':
|
|
510
|
+
case 'text':
|
|
511
|
+
case 'crossLine':
|
|
512
|
+
values.push(drawing.geometry.point.value);
|
|
513
|
+
break;
|
|
514
|
+
case 'rectangle':
|
|
515
|
+
case 'arrow':
|
|
516
|
+
case 'priceMeasurement':
|
|
517
|
+
values.push(drawing.geometry.start.value, drawing.geometry.end.value);
|
|
518
|
+
break;
|
|
519
|
+
case 'verticalStraightLine':
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
return values;
|
|
523
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MainSeriesPresentation, ActiveMainSeriesType } from '@baron1996/klinecharts-adapter';
|
|
2
|
+
export interface RuntimeValueAxisCapability {
|
|
3
|
+
readonly supportedScales: readonly ('linear' | 'logarithmic')[];
|
|
4
|
+
readonly activeScale: 'linear' | 'logarithmic';
|
|
5
|
+
readonly mutable: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface RuntimeExportArtifactCapability {
|
|
8
|
+
readonly kind: 'chart-scene' | 'drawable-workspace';
|
|
9
|
+
readonly mediaType: 'application/json';
|
|
10
|
+
readonly defaultFileName: string;
|
|
11
|
+
}
|
|
12
|
+
export interface MainSeriesPresentationCapability {
|
|
13
|
+
readonly presentations: readonly MainSeriesPresentation[];
|
|
14
|
+
readonly activeType: ActiveMainSeriesType;
|
|
15
|
+
readonly mutable: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface HostActionDescriptor {
|
|
18
|
+
readonly actionId: string;
|
|
19
|
+
readonly label: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RuntimeCapabilityDescriptor {
|
|
22
|
+
readonly drawingTypes: readonly string[];
|
|
23
|
+
readonly valueAxis: RuntimeValueAxisCapability;
|
|
24
|
+
readonly exportArtifact: RuntimeExportArtifactCapability;
|
|
25
|
+
readonly mainSeriesPresentation: MainSeriesPresentationCapability | null;
|
|
26
|
+
readonly hostActions: readonly HostActionDescriptor[];
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=runtime-capability-descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-capability-descriptor.d.ts","sourceRoot":"","sources":["../../src/drawing/runtime-capability-descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC,QAAQ,GAAG,aAAa,CAAC,EAAE,CAAC;IAChE,QAAQ,CAAC,WAAW,EAAE,QAAQ,GAAG,aAAa,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,+BAA+B;IAC/C,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,oBAAoB,CAAC;IACpD,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC1D,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,0BAA0B,CAAC;IAC/C,QAAQ,CAAC,cAAc,EAAE,+BAA+B,CAAC;IACzD,QAAQ,CAAC,sBAAsB,EAAE,gCAAgC,GAAG,IAAI,CAAC;IACzE,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ChartScene, DrawableWorkspaceDocument, TimeSeriesScene } from '@baron1996/kline-scene-schema';
|
|
2
|
+
import { type DrawingEnginePort, type DrawingProjectionPolicy } from '@baron1996/klinecharts-adapter';
|
|
3
|
+
export interface SceneRuntimeRegistration {
|
|
4
|
+
readonly sceneKind: 'chart' | 'time-series';
|
|
5
|
+
parseScene(value: unknown): ChartScene | TimeSeriesScene;
|
|
6
|
+
createAdapter(container: HTMLElement, workspace: DrawableWorkspaceDocument): Promise<DrawingEnginePort>;
|
|
7
|
+
createPolicy(): DrawingProjectionPolicy;
|
|
8
|
+
readonly defaultTarget: {
|
|
9
|
+
readonly paneRole: string;
|
|
10
|
+
readonly yAxisRole: 'primary';
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function registerSceneRuntime(registration: SceneRuntimeRegistration): void;
|
|
14
|
+
export declare function getSceneRuntime(kind: 'chart' | 'time-series'): SceneRuntimeRegistration;
|
|
15
|
+
//# sourceMappingURL=scene-runtime-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-runtime-factory.d.ts","sourceRoot":"","sources":["../../src/drawing/scene-runtime-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,yBAAyB,EACzB,eAAe,EACf,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAKN,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,aAAa,CAAC;IAC5C,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,eAAe,CAAC;IACzD,aAAa,CACZ,SAAS,EAAE,WAAW,EACtB,SAAS,EAAE,yBAAyB,GAClC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,YAAY,IAAI,uBAAuB,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE;QACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;KAC9B,CAAC;CACF;AAID,wBAAgB,oBAAoB,CACnC,YAAY,EAAE,wBAAwB,GACpC,IAAI,CAEN;AAED,wBAAgB,eAAe,CAC9B,IAAI,EAAE,OAAO,GAAG,aAAa,GAC3B,wBAAwB,CAM1B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { parseChartScene, parseTimeSeriesScene } from '@baron1996/kline-scene-schema';
|
|
2
|
+
import { KLineChartsSceneAdapter, KLineDrawingProjectionPolicy, TimeSeriesChartsAdapter, TimeSeriesDrawingProjectionPolicy, } from '@baron1996/klinecharts-adapter';
|
|
3
|
+
const registrations = new Map();
|
|
4
|
+
export function registerSceneRuntime(registration) {
|
|
5
|
+
registrations.set(registration.sceneKind, registration);
|
|
6
|
+
}
|
|
7
|
+
export function getSceneRuntime(kind) {
|
|
8
|
+
const registration = registrations.get(kind);
|
|
9
|
+
if (registration === undefined) {
|
|
10
|
+
throw new Error(`No Scene Runtime registered for kind: ${kind}.`);
|
|
11
|
+
}
|
|
12
|
+
return registration;
|
|
13
|
+
}
|
|
14
|
+
registerSceneRuntime({
|
|
15
|
+
sceneKind: 'chart',
|
|
16
|
+
parseScene: (value) => parseChartScene(value),
|
|
17
|
+
createAdapter: (container, workspace) => KLineChartsSceneAdapter.createWorkspace(container, workspace),
|
|
18
|
+
createPolicy: () => new KLineDrawingProjectionPolicy(),
|
|
19
|
+
defaultTarget: { paneRole: 'candle', yAxisRole: 'primary' },
|
|
20
|
+
});
|
|
21
|
+
registerSceneRuntime({
|
|
22
|
+
sceneKind: 'time-series',
|
|
23
|
+
parseScene: (value) => parseTimeSeriesScene(value),
|
|
24
|
+
createAdapter: (container, workspace) => TimeSeriesChartsAdapter.createWorkspace(container, workspace),
|
|
25
|
+
createPolicy: () => new TimeSeriesDrawingProjectionPolicy(),
|
|
26
|
+
defaultTarget: { paneRole: 'time-series', yAxisRole: 'primary' },
|
|
27
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { DrawingDocument, ValueAxis } from '@baron1996/kline-scene-schema';
|
|
2
|
+
import type { DrawingEnginePort, EngineDrawingSnapshot } from '@baron1996/klinecharts-adapter';
|
|
3
|
+
import { DrawingProjectionService, type ProjectionScene } from './projection-service.js';
|
|
4
|
+
import type { WorkspaceRuntimeEvent } from './workspace-events.js';
|
|
5
|
+
export type DrawingSessionState = 'ready' | 'interacting' | 'awaiting-host-confirmation' | 'reprojecting' | 'terminal-error' | 'destroyed';
|
|
6
|
+
export type DrawingSessionErrorCode = 'DRAWING_CHANGE_IN_PROGRESS' | 'DRAWING_CHANGE_HASH_MISMATCH' | 'DRAWING_CHANGE_REJECTED' | 'DRAWING_PROJECTION_INVALID' | 'DRAWABLE_WORKSPACE_RUNTIME_DESTROYED';
|
|
7
|
+
export declare class DrawingSessionError extends Error {
|
|
8
|
+
readonly code: DrawingSessionErrorCode;
|
|
9
|
+
readonly path: string;
|
|
10
|
+
constructor(code: DrawingSessionErrorCode, path: string, message: string);
|
|
11
|
+
}
|
|
12
|
+
export interface DrawingSessionControllerOptions {
|
|
13
|
+
readonly runtimeId: string;
|
|
14
|
+
readonly commitMode: 'immediate' | 'host-confirmed';
|
|
15
|
+
readonly engine: DrawingEnginePort;
|
|
16
|
+
readonly projectionService: DrawingProjectionService;
|
|
17
|
+
readonly scene: ProjectionScene;
|
|
18
|
+
readonly valueAxes: readonly ValueAxis[];
|
|
19
|
+
readonly target: {
|
|
20
|
+
readonly paneRole: string;
|
|
21
|
+
readonly yAxisRole: 'primary';
|
|
22
|
+
};
|
|
23
|
+
readonly scopeKey: string;
|
|
24
|
+
readonly timezone: string;
|
|
25
|
+
readonly buildDocument: (drawings: readonly EngineDrawingSnapshot[]) => DrawingDocument;
|
|
26
|
+
readonly emit: (event: WorkspaceRuntimeEvent) => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 场景无关的 Drawing 会话状态机。
|
|
30
|
+
* 所有变更都走 candidate 校验/投影/展示/确认链;进度事件永不改 confirmed。
|
|
31
|
+
*/
|
|
32
|
+
export declare class DrawingSessionController {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(options: DrawingSessionControllerOptions);
|
|
35
|
+
get state(): DrawingSessionState;
|
|
36
|
+
get confirmedDrawings(): readonly EngineDrawingSnapshot[];
|
|
37
|
+
get selectedId(): string | null;
|
|
38
|
+
restoreConfirmed(drawings: readonly EngineDrawingSnapshot[]): void;
|
|
39
|
+
startCreate(type: string, options?: {
|
|
40
|
+
readonly text?: string;
|
|
41
|
+
readonly id?: string;
|
|
42
|
+
readonly styles?: EngineDrawingSnapshot['styles'];
|
|
43
|
+
}): string;
|
|
44
|
+
updateDrawingStyles(id: string, styles: EngineDrawingSnapshot['styles']): EngineDrawingSnapshot;
|
|
45
|
+
updateDrawingText(id: string, text: string): EngineDrawingSnapshot;
|
|
46
|
+
removeDrawing(id: string): boolean;
|
|
47
|
+
selectDrawing(id: string | null): void;
|
|
48
|
+
commitDrawingChange(requestId: string, canonicalHash: string): boolean;
|
|
49
|
+
rejectDrawingChange(requestId: string): boolean;
|
|
50
|
+
enterTerminalError(code: string, message: string): void;
|
|
51
|
+
destroy(): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=session-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-controller.d.ts","sourceRoot":"","sources":["../../src/drawing/session-controller.ts"],"names":[],"mappings":"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"}
|