@sequent-org/moodboard 1.2.119 → 1.3.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/package.json +11 -1
- package/src/assets/icons/rotate-icon.svg +1 -1
- package/src/core/HistoryManager.js +16 -16
- package/src/core/KeyboardManager.js +48 -539
- package/src/core/PixiEngine.js +9 -9
- package/src/core/SaveManager.js +56 -31
- package/src/core/bootstrap/CoreInitializer.js +65 -0
- package/src/core/commands/DeleteObjectCommand.js +8 -0
- package/src/core/commands/GroupDeleteCommand.js +75 -0
- package/src/core/commands/GroupRotateCommand.js +6 -0
- package/src/core/commands/UpdateContentCommand.js +52 -0
- package/src/core/commands/UpdateFramePropertiesCommand.js +98 -0
- package/src/core/commands/UpdateFrameTypeCommand.js +85 -0
- package/src/core/commands/UpdateNoteStyleCommand.js +88 -0
- package/src/core/commands/UpdateTextStyleCommand.js +90 -0
- package/src/core/commands/index.js +6 -0
- package/src/core/events/Events.js +6 -0
- package/src/core/flows/ClipboardFlow.js +553 -0
- package/src/core/flows/LayerAndViewportFlow.js +283 -0
- package/src/core/flows/ObjectLifecycleFlow.js +336 -0
- package/src/core/flows/SaveFlow.js +34 -0
- package/src/core/flows/TransformFlow.js +277 -0
- package/src/core/flows/TransformFlowResizeHelpers.js +83 -0
- package/src/core/index.js +41 -1773
- package/src/core/keyboard/KeyboardClipboardImagePaste.js +190 -0
- package/src/core/keyboard/KeyboardContextGuards.js +35 -0
- package/src/core/keyboard/KeyboardEventRouter.js +92 -0
- package/src/core/keyboard/KeyboardSelectionActions.js +103 -0
- package/src/core/keyboard/KeyboardShortcutMap.js +31 -0
- package/src/core/keyboard/KeyboardToolSwitching.js +26 -0
- package/src/core/rendering/ObjectRenderer.js +3 -7
- package/src/grid/BaseGrid.js +26 -0
- package/src/grid/CrossGrid.js +7 -6
- package/src/grid/DotGrid.js +89 -33
- package/src/grid/DotGridZoomPhases.js +42 -0
- package/src/grid/LineGrid.js +22 -21
- package/src/moodboard/MoodBoard.js +31 -532
- package/src/moodboard/bootstrap/MoodBoardInitializer.js +47 -0
- package/src/moodboard/bootstrap/MoodBoardManagersFactory.js +38 -0
- package/src/moodboard/bootstrap/MoodBoardUiFactory.js +109 -0
- package/src/moodboard/integration/MoodBoardEventBindings.js +65 -0
- package/src/moodboard/integration/MoodBoardLoadApi.js +82 -0
- package/src/moodboard/integration/MoodBoardScreenshotApi.js +33 -0
- package/src/moodboard/integration/MoodBoardScreenshotCanvas.js +98 -0
- package/src/moodboard/lifecycle/MoodBoardDestroyer.js +97 -0
- package/src/objects/FileObject.js +17 -6
- package/src/objects/FrameObject.js +50 -10
- package/src/objects/NoteObject.js +5 -4
- package/src/services/BoardService.js +42 -2
- package/src/services/FrameService.js +83 -42
- package/src/services/ResizePolicyService.js +152 -0
- package/src/services/SettingsApplier.js +7 -2
- package/src/services/ZoomPanController.js +35 -9
- package/src/tools/ToolManager.js +30 -537
- package/src/tools/board-tools/PanTool.js +5 -11
- package/src/tools/manager/ToolActivationController.js +49 -0
- package/src/tools/manager/ToolEventRouter.js +396 -0
- package/src/tools/manager/ToolManagerGuards.js +33 -0
- package/src/tools/manager/ToolManagerLifecycle.js +110 -0
- package/src/tools/manager/ToolRegistry.js +33 -0
- package/src/tools/object-tools/DrawingTool.js +48 -14
- package/src/tools/object-tools/PlacementTool.js +50 -1049
- package/src/tools/object-tools/PlacementToolV2.js +88 -0
- package/src/tools/object-tools/SelectTool.js +174 -2681
- package/src/tools/object-tools/placement/GhostController.js +504 -0
- package/src/tools/object-tools/placement/PlacementCoordinateResolver.js +20 -0
- package/src/tools/object-tools/placement/PlacementEventsBridge.js +91 -0
- package/src/tools/object-tools/placement/PlacementInputRouter.js +267 -0
- package/src/tools/object-tools/placement/PlacementPayloadFactory.js +111 -0
- package/src/tools/object-tools/placement/PlacementSessionStore.js +18 -0
- package/src/tools/object-tools/selection/BoxSelectController.js +0 -5
- package/src/tools/object-tools/selection/CloneFlowController.js +71 -0
- package/src/tools/object-tools/selection/CoordinateMapper.js +10 -0
- package/src/tools/object-tools/selection/CursorController.js +78 -0
- package/src/tools/object-tools/selection/FileNameInlineEditorController.js +184 -0
- package/src/tools/object-tools/selection/HitTestService.js +102 -0
- package/src/tools/object-tools/selection/InlineEditorController.js +24 -0
- package/src/tools/object-tools/selection/InlineEditorDomFactory.js +50 -0
- package/src/tools/object-tools/selection/InlineEditorListenersRegistry.js +14 -0
- package/src/tools/object-tools/selection/InlineEditorPositioningService.js +25 -0
- package/src/tools/object-tools/selection/NoteInlineEditorController.js +113 -0
- package/src/tools/object-tools/selection/SelectInputRouter.js +267 -0
- package/src/tools/object-tools/selection/SelectToolLifecycleController.js +128 -0
- package/src/tools/object-tools/selection/SelectToolSetup.js +134 -0
- package/src/tools/object-tools/selection/SelectionOverlayService.js +81 -0
- package/src/tools/object-tools/selection/SelectionStateController.js +91 -0
- package/src/tools/object-tools/selection/TextEditorDomFactory.js +65 -0
- package/src/tools/object-tools/selection/TextEditorInteractionController.js +266 -0
- package/src/tools/object-tools/selection/TextEditorLifecycleRegistry.js +90 -0
- package/src/tools/object-tools/selection/TextEditorPositioningService.js +158 -0
- package/src/tools/object-tools/selection/TextEditorSyncService.js +110 -0
- package/src/tools/object-tools/selection/TextInlineEditorController.js +457 -0
- package/src/tools/object-tools/selection/TransformInteractionController.js +466 -0
- package/src/ui/FilePropertiesPanel.js +61 -32
- package/src/ui/FramePropertiesPanel.js +176 -101
- package/src/ui/HtmlHandlesLayer.js +121 -999
- package/src/ui/MapPanel.js +12 -7
- package/src/ui/NotePropertiesPanel.js +17 -2
- package/src/ui/TextPropertiesPanel.js +124 -738
- package/src/ui/Toolbar.js +71 -1180
- package/src/ui/Topbar.js +23 -25
- package/src/ui/ZoomPanel.js +16 -5
- package/src/ui/handles/GroupSelectionHandlesController.js +29 -0
- package/src/ui/handles/HandlesDomRenderer.js +278 -0
- package/src/ui/handles/HandlesEventBridge.js +102 -0
- package/src/ui/handles/HandlesInteractionController.js +772 -0
- package/src/ui/handles/HandlesPositioningService.js +206 -0
- package/src/ui/handles/SingleSelectionHandlesController.js +22 -0
- package/src/ui/styles/toolbar.css +2 -0
- package/src/ui/styles/workspace.css +13 -6
- package/src/ui/text-properties/TextPropertiesPanelBindings.js +92 -0
- package/src/ui/text-properties/TextPropertiesPanelEventBridge.js +77 -0
- package/src/ui/text-properties/TextPropertiesPanelMapper.js +173 -0
- package/src/ui/text-properties/TextPropertiesPanelRenderer.js +434 -0
- package/src/ui/text-properties/TextPropertiesPanelState.js +39 -0
- package/src/ui/toolbar/ToolbarActionRouter.js +193 -0
- package/src/ui/toolbar/ToolbarDialogsController.js +186 -0
- package/src/ui/toolbar/ToolbarPopupsController.js +662 -0
- package/src/ui/toolbar/ToolbarRenderer.js +97 -0
- package/src/ui/toolbar/ToolbarStateController.js +79 -0
- package/src/ui/toolbar/ToolbarTooltipController.js +52 -0
- package/src/utils/emojiLoaderNoBundler.js +1 -1
package/src/grid/DotGrid.js
CHANGED
|
@@ -1,47 +1,98 @@
|
|
|
1
1
|
import { BaseGrid } from './BaseGrid.js';
|
|
2
|
+
import { getActivePhases, getEffectiveSize } from './DotGridZoomPhases.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* Точечная сетка
|
|
5
|
+
* Точечная сетка с фазовым переключением при зуме (как в Miro).
|
|
6
|
+
* При переходе между фазами точки затухают, на смену приходит другой набор.
|
|
5
7
|
*/
|
|
6
8
|
export class DotGrid extends BaseGrid {
|
|
7
9
|
constructor(options = {}) {
|
|
8
10
|
super(options);
|
|
9
11
|
this.type = 'dot';
|
|
10
12
|
|
|
11
|
-
// Настройки точек
|
|
12
|
-
this.dotSize = options.dotSize || 2;
|
|
13
13
|
this.dotStyle = options.dotStyle || 'circle'; // 'circle' | 'square'
|
|
14
14
|
this.highlightIntersections = options.highlightIntersections ?? true;
|
|
15
|
-
|
|
16
|
-
this.
|
|
17
|
-
|
|
15
|
+
this.dotSize = options.dotSize ?? 1; // для serialize/setDotSize; фазы переопределяют при отрисовке
|
|
16
|
+
this.snapSize = options.snapSize ?? 20; // фиксированный шаг привязки в world-координатах
|
|
17
|
+
// Порог видимости точки на экране и лимит плотности отрисовки.
|
|
18
|
+
this.minScreenDotRadius = options.minScreenDotRadius ?? 0.45;
|
|
19
|
+
this.minScreenSpacing = options.minScreenSpacing ?? 8;
|
|
20
|
+
this.maxDotsPerPhase = options.maxDotsPerPhase ?? 25000;
|
|
21
|
+
this.intersectionSize = options.intersectionSize ?? this.dotSize;
|
|
22
|
+
this.intersectionColor = options.intersectionColor ?? this.color;
|
|
23
|
+
|
|
24
|
+
/** Текущий zoom (scale) для выбора фазы. 1 = 100%. */
|
|
25
|
+
this._zoom = 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Устанавливает текущий масштаб (для фазового переключения).
|
|
30
|
+
* @param {number} scale - world.scale.x (1 = 100%)
|
|
31
|
+
*/
|
|
32
|
+
setZoom(scale) {
|
|
33
|
+
this._zoom = Math.max(0.02, Math.min(5, scale));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** @returns {Array<{ phase: object, alpha: number }>} */
|
|
37
|
+
_getActivePhases() {
|
|
38
|
+
return getActivePhases(this._zoom);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** @returns {number} */
|
|
42
|
+
_getEffectiveSize() {
|
|
43
|
+
return getEffectiveSize(this._zoom);
|
|
18
44
|
}
|
|
19
45
|
|
|
20
46
|
/**
|
|
21
47
|
* Создает визуальное представление точечной сетки
|
|
22
48
|
*/
|
|
23
49
|
createVisual() {
|
|
24
|
-
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// }
|
|
50
|
+
this.size = this._getEffectiveSize();
|
|
51
|
+
const phases = this._getActivePhases();
|
|
52
|
+
const baseOpacity = this.opacity ?? 0.7;
|
|
53
|
+
for (const { phase, alpha } of phases) {
|
|
54
|
+
this._drawPhaseDots(phase, baseOpacity * alpha);
|
|
55
|
+
}
|
|
31
56
|
}
|
|
32
|
-
|
|
57
|
+
|
|
33
58
|
/**
|
|
34
|
-
* Рисует
|
|
59
|
+
* Рисует точки одной фазы с заданной прозрачностью.
|
|
35
60
|
*/
|
|
36
|
-
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
_drawPhaseDots(phase, alpha) {
|
|
62
|
+
const b = this.getDrawBounds();
|
|
63
|
+
const scale = Math.max(0.001, this._zoom || 1);
|
|
64
|
+
const baseSize = phase.size;
|
|
65
|
+
const minWorldSpacing = this.minScreenSpacing / scale;
|
|
66
|
+
let size = Math.max(baseSize, minWorldSpacing);
|
|
67
|
+
|
|
68
|
+
const widthWorld = Math.max(0, b.right - b.left);
|
|
69
|
+
const heightWorld = Math.max(0, b.bottom - b.top);
|
|
70
|
+
const estimateDots = () => {
|
|
71
|
+
const nx = Math.floor(widthWorld / size) + 3;
|
|
72
|
+
const ny = Math.floor(heightWorld / size) + 3;
|
|
73
|
+
return nx * ny;
|
|
74
|
+
};
|
|
75
|
+
const dots = estimateDots();
|
|
76
|
+
if (dots > this.maxDotsPerPhase) {
|
|
77
|
+
const densityFactor = Math.sqrt(dots / this.maxDotsPerPhase);
|
|
78
|
+
size *= Math.max(1, densityFactor);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const startX = Math.floor(b.left / size) * size;
|
|
82
|
+
const startY = Math.floor(b.top / size) * size;
|
|
83
|
+
const endX = Math.ceil(b.right / size) * size;
|
|
84
|
+
const endY = Math.ceil(b.bottom / size) * size;
|
|
85
|
+
|
|
86
|
+
const minWorldRadius = this.minScreenDotRadius / scale;
|
|
87
|
+
const maxWorldRadius = size * 0.2;
|
|
88
|
+
const dotSize = Math.min(Math.max(phase.dotSize, minWorldRadius), maxWorldRadius);
|
|
89
|
+
|
|
90
|
+
this.graphics.beginFill(this.color, alpha);
|
|
91
|
+
for (let x = startX; x <= endX; x += size) {
|
|
92
|
+
for (let y = startY; y <= endY; y += size) {
|
|
93
|
+
this.drawDot(x, y, dotSize);
|
|
42
94
|
}
|
|
43
95
|
}
|
|
44
|
-
|
|
45
96
|
this.graphics.endFill();
|
|
46
97
|
}
|
|
47
98
|
|
|
@@ -50,16 +101,17 @@ export class DotGrid extends BaseGrid {
|
|
|
50
101
|
*/
|
|
51
102
|
drawIntersections() {
|
|
52
103
|
const intersectionStep = this.size * 5;
|
|
53
|
-
|
|
54
|
-
|
|
104
|
+
const b = this.getDrawBounds();
|
|
105
|
+
const startX = Math.floor(b.left / intersectionStep) * intersectionStep;
|
|
106
|
+
const startY = Math.floor(b.top / intersectionStep) * intersectionStep;
|
|
107
|
+
const endX = Math.ceil(b.right / intersectionStep) * intersectionStep;
|
|
108
|
+
const endY = Math.ceil(b.bottom / intersectionStep) * intersectionStep;
|
|
55
109
|
this.graphics.beginFill(this.color);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
for (let y = 0; y <= this.height; y += intersectionStep) {
|
|
110
|
+
for (let x = startX; x <= endX; x += intersectionStep) {
|
|
111
|
+
for (let y = startY; y <= endY; y += intersectionStep) {
|
|
59
112
|
this.drawDot(x, y, this.dotSize);
|
|
60
113
|
}
|
|
61
114
|
}
|
|
62
|
-
|
|
63
115
|
this.graphics.endFill();
|
|
64
116
|
}
|
|
65
117
|
|
|
@@ -79,8 +131,9 @@ export class DotGrid extends BaseGrid {
|
|
|
79
131
|
* Вычисляет точку привязки для точечной сетки
|
|
80
132
|
*/
|
|
81
133
|
calculateSnapPoint(x, y) {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
134
|
+
const step = this.snapSize || this.size;
|
|
135
|
+
const snapX = Math.round(x / step) * step;
|
|
136
|
+
const snapY = Math.round(y / step) * step;
|
|
84
137
|
|
|
85
138
|
return { x: snapX, y: snapY };
|
|
86
139
|
}
|
|
@@ -98,11 +151,10 @@ export class DotGrid extends BaseGrid {
|
|
|
98
151
|
}
|
|
99
152
|
|
|
100
153
|
/**
|
|
101
|
-
* Устанавливает размер точек
|
|
154
|
+
* Устанавливает размер точек (для совместимости; при фазовом зуме фазы переопределяют размер).
|
|
102
155
|
*/
|
|
103
156
|
setDotSize(size) {
|
|
104
|
-
this.dotSize = Math.max(
|
|
105
|
-
// Синхронизируем размер точек пересечений
|
|
157
|
+
this.dotSize = Math.max(0.5, size);
|
|
106
158
|
this.intersectionSize = this.dotSize;
|
|
107
159
|
this.updateVisual();
|
|
108
160
|
}
|
|
@@ -140,6 +192,10 @@ export class DotGrid extends BaseGrid {
|
|
|
140
192
|
...super.serialize(),
|
|
141
193
|
dotSize: this.dotSize,
|
|
142
194
|
dotStyle: this.dotStyle,
|
|
195
|
+
snapSize: this.snapSize,
|
|
196
|
+
minScreenDotRadius: this.minScreenDotRadius,
|
|
197
|
+
minScreenSpacing: this.minScreenSpacing,
|
|
198
|
+
maxDotsPerPhase: this.maxDotsPerPhase,
|
|
143
199
|
highlightIntersections: this.highlightIntersections,
|
|
144
200
|
intersectionSize: this.intersectionSize,
|
|
145
201
|
intersectionColor: this.intersectionColor
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Логика фаз точечной сетки при зуме (чистые функции, тестируемые без PIXI).
|
|
3
|
+
* Фазы подобраны по зафиксированным checkpoint'ам Miro:
|
|
4
|
+
* - high zoom: базовый шаг 20 world units;
|
|
5
|
+
* - low zoom: шаг укрупняется, чтобы избежать перегруза при отрисовке.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** @type {{ zoomMin: number, zoomMax: number, size: number, dotSize: number }[]} */
|
|
9
|
+
export const PHASES = [
|
|
10
|
+
{ zoomMin: 0.02, zoomMax: 0.12, size: 160, dotSize: 0.7 },
|
|
11
|
+
{ zoomMin: 0.12, zoomMax: 0.25, size: 80, dotSize: 0.8 },
|
|
12
|
+
{ zoomMin: 0.25, zoomMax: 0.5, size: 40, dotSize: 0.9 },
|
|
13
|
+
{ zoomMin: 0.5, zoomMax: 5, size: 20, dotSize: 1 }
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Возвращает активные фазы и их alpha для crossfade.
|
|
18
|
+
* @param {number} zoom - world.scale.x (1 = 100%)
|
|
19
|
+
* @returns {Array<{ phase: object, alpha: number }>}
|
|
20
|
+
*/
|
|
21
|
+
export function getActivePhases(zoom) {
|
|
22
|
+
const z = Math.max(0.02, Math.min(5, zoom));
|
|
23
|
+
for (let i = 0; i < PHASES.length; i++) {
|
|
24
|
+
const phase = PHASES[i];
|
|
25
|
+
const inRange = i === PHASES.length - 1
|
|
26
|
+
? (z >= phase.zoomMin && z <= phase.zoomMax)
|
|
27
|
+
: (z >= phase.zoomMin && z < phase.zoomMax);
|
|
28
|
+
if (inRange) {
|
|
29
|
+
return [{ phase, alpha: 1 }];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return [{ phase: PHASES[PHASES.length - 1], alpha: 1 }];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Эффективный size для snap (доминирующая фаза).
|
|
37
|
+
* @param {number} zoom
|
|
38
|
+
* @returns {number}
|
|
39
|
+
*/
|
|
40
|
+
export function getEffectiveSize(zoom) {
|
|
41
|
+
return getActivePhases(zoom)[0].phase.size;
|
|
42
|
+
}
|
package/src/grid/LineGrid.js
CHANGED
|
@@ -47,23 +47,24 @@ export class LineGrid extends BaseGrid {
|
|
|
47
47
|
* Рисует основную сетку
|
|
48
48
|
*/
|
|
49
49
|
drawMainGrid() {
|
|
50
|
-
const
|
|
51
|
-
const h = this.height;
|
|
50
|
+
const b = this.getDrawBounds();
|
|
52
51
|
const step = this.size;
|
|
53
52
|
const half = this.lineWidth / 2;
|
|
54
|
-
|
|
53
|
+
const startX = Math.floor(b.left / step) * step;
|
|
54
|
+
const endX = Math.ceil(b.right / step) * step;
|
|
55
|
+
const startY = Math.floor(b.top / step) * step;
|
|
56
|
+
const endY = Math.ceil(b.bottom / step) * step;
|
|
55
57
|
// Вертикальные линии
|
|
56
|
-
for (let x =
|
|
58
|
+
for (let x = startX; x <= endX; x += step) {
|
|
57
59
|
const px = Math.round(x) + (Number.isFinite(half) ? 0.5 : 0);
|
|
58
|
-
this.graphics.moveTo(px,
|
|
59
|
-
this.graphics.lineTo(px,
|
|
60
|
+
this.graphics.moveTo(px, b.top);
|
|
61
|
+
this.graphics.lineTo(px, b.bottom);
|
|
60
62
|
}
|
|
61
|
-
|
|
62
63
|
// Горизонтальные линии
|
|
63
|
-
for (let y =
|
|
64
|
+
for (let y = startY; y <= endY; y += step) {
|
|
64
65
|
const py = Math.round(y) + (Number.isFinite(half) ? 0.5 : 0);
|
|
65
|
-
this.graphics.moveTo(
|
|
66
|
-
this.graphics.lineTo(
|
|
66
|
+
this.graphics.moveTo(b.left, py);
|
|
67
|
+
this.graphics.lineTo(b.right, py);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -77,23 +78,23 @@ export class LineGrid extends BaseGrid {
|
|
|
77
78
|
} catch (_) {
|
|
78
79
|
this.graphics.lineStyle(0.5, this.subGridColor, this.subGridOpacity);
|
|
79
80
|
}
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const b = this.getDrawBounds();
|
|
82
|
+
const startX = Math.floor(b.left / subSize) * subSize;
|
|
83
|
+
const endX = Math.ceil(b.right / subSize) * subSize;
|
|
84
|
+
const startY = Math.floor(b.top / subSize) * subSize;
|
|
85
|
+
const endY = Math.ceil(b.bottom / subSize) * subSize;
|
|
86
|
+
for (let x = startX; x <= endX; x += subSize) {
|
|
84
87
|
if (x % this.size !== 0) {
|
|
85
88
|
const px = Math.round(x) + 0.5;
|
|
86
|
-
this.graphics.moveTo(px,
|
|
87
|
-
this.graphics.lineTo(px,
|
|
89
|
+
this.graphics.moveTo(px, b.top);
|
|
90
|
+
this.graphics.lineTo(px, b.bottom);
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
// Горизонтальные подлинии
|
|
92
|
-
for (let y = subSize; y < h; y += subSize) {
|
|
93
|
+
for (let y = startY; y <= endY; y += subSize) {
|
|
93
94
|
if (y % this.size !== 0) {
|
|
94
95
|
const py = Math.round(y) + 0.5;
|
|
95
|
-
this.graphics.moveTo(
|
|
96
|
-
this.graphics.lineTo(
|
|
96
|
+
this.graphics.moveTo(b.left, py);
|
|
97
|
+
this.graphics.lineTo(b.right, py);
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
}
|