Skip to content

Commit a28c8f4

Browse files
committed
greatly simplify graphical konva synchronization, by incorporating it into ChangeManager
1 parent 5a75a53 commit a28c8f4

4 files changed

Lines changed: 106 additions & 158 deletions

File tree

src/core/Collage.js

Lines changed: 21 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,21 @@ export default class Collage extends SmartPallet {
9999
x: konvaObj.x(),
100100
y: konvaObj.y()
101101
};
102-
const syncSmartObject = (loc) => {
102+
103+
const applySmartObjectChange = (loc) => {
103104
const scene = this.scenes.find( (scene) => scene.id === id );
104105
scene.x = loc.x;
105106
scene.y = loc.y;
106107
return scene;
107108
}
108-
const syncKonva = (loc) => {
109-
const konvaObj = this.containingKonvaStage.findOne(`#${id}`);
110-
konvaObj.x(loc.x);
111-
konvaObj.y(loc.y);
112-
this.containingKonvaStage.draw();
113-
}
114109

115110
// apply our change
116-
// ... should be able to OMIT `.getPkgEntry()` node (below) BECAUSE this Collage should always be a PkgEntry
117-
this.getPkgEntry().changeManager.applyChange({
118-
changeFn(redo) {
119-
const scene = syncSmartObject(newLoc);
120-
redo && syncKonva(newLoc);
121-
return scene;
111+
this.changeManager.applyChange({
112+
changeFn() {
113+
return applySmartObjectChange(newLoc);
122114
},
123115
undoFn() {
124-
const scene = syncSmartObject(oldLoc);
125-
syncKonva(oldLoc);
126-
return scene;
116+
return applySmartObjectChange(oldLoc);
127117
}
128118
});
129119

@@ -169,7 +159,7 @@ export default class Collage extends SmartPallet {
169159
type,
170160
key: e.dataTransfer.getData(type),
171161
};
172-
console.log(`?? pasting: `, {copySrc, onto: this});
162+
// console.log(`?? pasting: `, {copySrc, onto: this});
173163

174164
// NOTE: we know the supplied copySrc references a Scene pseudo class master (see pastable() method)
175165

@@ -180,30 +170,15 @@ export default class Collage extends SmartPallet {
180170
const [pkgId, className] = copySrc.key.split('/');
181171
const sceneClassRef = pkgManager.getClassRef(pkgId, className);
182172
const sceneId = `${className}-copy-${Date.now()}`; // ... unique id (for now use current time)
183-
184-
// ?? have to break this up
185-
// ... ?? test again and see why?
186-
// ... ?? may prefer to fix that problem rather than break this out (too complex)
187-
// ... ?? also consider making this a SmartObject utility method ... say: remount() ... requires to be previously mounted ... would have to be implemented throughout major points in the hierarchy because of specifics
188-
const syncKonva = () => {
189-
const containingKonvaStage = this.containingKonvaStage;
190-
this.unmount();
191-
this.mount(containingKonvaStage);
192-
}
193173

194-
// ?? will this work in subsequent undo? ... I think so, because `this` is retained in the closure
174+
// retain selfCollage `this` alias
175+
// ... NOTE: `this` IS retained in our closure,
176+
// HOWEVER unless changeFn() is an arrow function, it has a different `this` context
195177
const selfCollage = this;
196178

197179
// apply our change
198-
// ... should be able to OMIT `.getPkgEntry()` node (below) BECAUSE this Collage should always be a PkgEntry
199-
this.getPkgEntry().changeManager.applyChange({
200-
changeFn(redo) { // ... we do NOT use redo, because we must sync konva 100% of the time
201-
202-
console.log(`?? redo paste operation`);
203-
204-
// unmount konvo (Part I of the konva sync process)
205-
const containingKonvaStage = selfCollage.containingKonvaStage;
206-
selfCollage.unmount();
180+
this.changeManager.applyChange({
181+
changeFn() {
207182

208183
// ?? once we get this working, modularize it and make it a real utility
209184
function relativeCoords(event) {
@@ -216,56 +191,23 @@ export default class Collage extends SmartPallet {
216191

217192
const coord = relativeCoords(e);
218193
console.log(`?? let's set the x/y from event: `, {event: e, coord});
219-
// change SmartObj model ... by adding the new scene
194+
195+
// add a new scene (from the DnD drop) to our collage
220196
const newScene = sceneClassRef.createSmartObject({
221197
id: sceneId,
222-
x: coord.x, // ?? pull from event
223-
y: coord.y,
198+
x: coord.x,
199+
y: coord.y,
224200
});
225-
selfCollage.addScene(newScene); // ?? this is NOT the correct `this`
226-
227-
// mount konvo (Part II of the konva sync process)
228-
selfCollage.mount(containingKonvaStage);
201+
selfCollage.addScene(newScene);
229202

230-
// ??$$ SPECIAL LOGIC
231-
// re-establish our pkgEntry DispMode
232-
// ... this resets all our event handlers given the re-mount :-)
233-
// ... ?? this should be pkgEntry ... no need for this.getPkgEntry()
234-
const pkgEntry = selfCollage.getPkgEntry();
235-
pkgEntry.changeManager.changeDispMode( pkgEntry.getDispMode() );
236-
237-
// sync our Konva model ?? TRASH
238-
//? syncKonva();
239-
240-
return newScene;
203+
return newScene; // promote the new scene as our change target
241204
},
242205

243206
undoFn() {
207+
// remove the scene from our collage
208+
selfCollage.removeScene(sceneId);
244209

245-
console.log(`?? undo paste operation`);
246-
// debugger; ??
247-
248-
// unmount konvo (Part I of the konva sync process)
249-
const containingKonvaStage = selfCollage.containingKonvaStage;
250-
selfCollage.unmount();
251-
252-
// change SmartObj model ... by removing the scene
253-
selfCollage.removeScene(sceneId)
254-
255-
// mount konvo (Part II of the konva sync process)
256-
selfCollage.mount(containingKonvaStage);
257-
258-
// ??$$ SPECIAL LOGIC
259-
// re-establish our pkgEntry DispMode
260-
// ... this resets all our event handlers given the re-mount :-)
261-
// ... ?? this should be pkgEntry ... no need for this.getPkgEntry()
262-
const pkgEntry = selfCollage.getPkgEntry();
263-
pkgEntry.changeManager.changeDispMode( pkgEntry.getDispMode() );
264-
265-
// sync our Konva model ?? TRASH
266-
//? syncKonva();
267-
268-
return selfCollage; // ?? our collage has changed
210+
return selfCollage; // promote our collage as our change target
269211
}
270212
});
271213
}

src/core/Scene.js

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -179,31 +179,20 @@ export default class Scene extends SmartPallet {
179179
x: konvaObj.x(),
180180
y: konvaObj.y()
181181
};
182-
const syncSmartObject = (loc) => {
182+
const applySmartObjectChange = (loc) => {
183183
const comp = this.comps.find( (comp) => comp.id === id );
184184
comp.x = loc.x;
185185
comp.y = loc.y;
186186
return comp;
187187
}
188-
const syncKonva = (loc) => {
189-
const konvaObj = this.konvaSceneLayer.findOne(`#${id}`);
190-
konvaObj.x(loc.x);
191-
konvaObj.y(loc.y);
192-
this.konvaSceneLayer.draw();
193-
}
194188

195189
// apply our change
196-
// ... should be able to OMIT `.getPkgEntry()` node (below) BECAUSE this Scene should always be a PkgEntry
197-
this.getPkgEntry().changeManager.applyChange({
198-
changeFn(redo) {
199-
const comp = syncSmartObject(newLoc);
200-
redo && syncKonva(newLoc);
201-
return comp;
190+
this.changeManager.applyChange({
191+
changeFn() {
192+
return applySmartObjectChange(newLoc);
202193
},
203194
undoFn() {
204-
const comp = syncSmartObject(oldLoc);
205-
syncKonva(oldLoc);
206-
return comp;
195+
return applySmartObjectChange(oldLoc);
207196
}
208197
});
209198

@@ -252,7 +241,6 @@ export default class Scene extends SmartPallet {
252241
// ... KJB: I really don't like how Konva does selection in it's Transformer
253242
// - KJB: WORK-AROUND: no-op when Konva/SmartObject have the same transformation
254243

255-
256244
// locate our component matching the target Konva.Group
257245
// ... we correlate the id's between Konva/SmartObject
258246
const konvaObj = e.target;
@@ -287,7 +275,7 @@ export default class Scene extends SmartPallet {
287275
return;
288276
}
289277

290-
const syncSmartObject = (trans) => {
278+
const applySmartObjectChange = (trans) => {
291279
const comp = this.comps.find( (comp) => comp.id === id );
292280
comp.x = trans.x;
293281
comp.y = trans.y;
@@ -296,28 +284,14 @@ export default class Scene extends SmartPallet {
296284
comp.scaleY = trans.scaleY;
297285
return comp;
298286
}
299-
const syncKonva = (trans) => {
300-
const konvaObj = this.konvaSceneLayer.findOne(`#${id}`);
301-
konvaObj.x(trans.x);
302-
konvaObj.y(trans.y);
303-
konvaObj.rotation(trans.rotation);
304-
konvaObj.scaleX(trans.scaleX);
305-
konvaObj.scaleY(trans.scaleY);
306-
this.konvaSceneLayer.draw();
307-
}
308287

309288
// apply our change
310-
// ... should be able to OMIT `.getPkgEntry()` node (below) BECAUSE this Scene should always be a PkgEntry
311-
this.getPkgEntry().changeManager.applyChange({
312-
changeFn(redo) {
313-
const comp = syncSmartObject(newTrans);
314-
redo && syncKonva(newTrans);
315-
return comp;
289+
this.changeManager.applyChange({
290+
changeFn() {
291+
return applySmartObjectChange(newTrans);
316292
},
317293
undoFn() {
318-
const comp = syncSmartObject(oldTrans);
319-
syncKonva(oldTrans);
320-
return comp;
294+
return applySmartObjectChange(oldTrans);
321295
}
322296
});
323297

src/core/changeManager/ChangeManager.js

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,27 @@ import {isEPkg,
1515
* ChangeManager objects are retained in the corresponding EPkg
1616
* smartObject, as a convenient cataloging mechanism.
1717
*
18+
* **Auto Synchronization**:
19+
*
20+
* ChangeManager greatly simplifies the change process by
21+
* automatically applying the required synchronization to the:
22+
*
23+
* - graphical representation (i.e. the Konva state)
24+
* ... app logic focuses on SmartObject changes,
25+
* and ChangeManager auto syncs the visual graphics
26+
*
27+
* - SmartObject parentage
28+
* ... app logic merely changes a "focused" target object
29+
* and ChangeManager auto syncs it's parentage.
30+
* This is accomplished via SmartObject.trickleUpChange(),
31+
* propagating things like crc computations, and dynamic container size.
32+
*
33+
* - ChangeMonitor state (see ChangeMonitor Object below)
34+
* ... of course self's reflective ChangeMonitor state is auto synced.
35+
* This is accomplished through the syncMonitoredChange() method,
36+
* invoked at the appropriate places.
37+
*
38+
*
1839
* **API**:
1940
*
2041
* There are two distinct APIs you should be aware of (as in all
@@ -27,19 +48,23 @@ import {isEPkg,
2748
* + changeDispMode(dispMode): void - change the dispMode of self's PkgEntry (view/edit/animate)
2849
*
2950
* + syncMonitoredChange(): void - synchronize self's ChangeMonitor (store value),
30-
* due to a change that has just been made to self's ePkg.
31-
* ... as detected in CRC computations:
32-
* - SmartObject.resetCrc(): void
33-
* - SmartObject.resetBaseCrc(): void
51+
* due to a change that has just been made to self's ePkg
52+
* impacting items monitored by ChangeManger {dispMode, inSync, undoAvail, redoAvail},
53+
* for example:
54+
* * CRC computations (impacting: {inSync, undoAvail, redoAvail}):
55+
* - SmartObject.resetCrc(): void ... via SmartObject.trickleUpChange() driven by changeManager.applyChange()
56+
* - SmartObject.resetBaseCrc(): void ... via SmartPkg-constructor() and pkgPersist-savePkg()
57+
* * DispMode changes (impacting: {dispMode}):
58+
* - changeManager.changeDispMode(dispMode)
3459
*
3560
* + applyChange({changeFn, undoFn}): void - apply a change to our system, registering the change to our undo/redo stack,
36-
* auto-syncing the parentage -and- our ChangeMonitor state.
61+
* auto-syncing required state (see "Auto Synchronization" above).
3762
*
3863
* + applyUndo(): void - apply an "undo" operation to the PkgEntry on whose behalf we are managing,
39-
* auto-syncing the parentage -and- our ChangeMonitor state.
64+
* auto-syncing required state (see "Auto Synchronization" above).
4065
*
4166
* + applyRedo(): void - apply an "redo" operation to the PkgEntry on whose behalf we are managing,
42-
* auto-syncing the parentage -and- our ChangeMonitor state.
67+
* auto-syncing required state (see "Auto Synchronization" above).
4368
* ```
4469
*
4570
* 2. ChangeMonitor Object (the store value, accessible via
@@ -107,7 +132,7 @@ export default class ChangeManager {
107132
redoAvail: this.undoRedoMgr.isRedoAvail(),
108133
});
109134

110-
// demark this object a svelte custom store
135+
// demark this object as a svelte custom store
111136
this.subscribe = this.baseStore.subscribe;
112137
}
113138

@@ -172,8 +197,8 @@ export default class ChangeManager {
172197

173198
/**
174199
* Apply a change to our system, registering the change to our
175-
* undo/redo stack, auto-syncing the parentage -and- our
176-
* ChangeMonitor state.
200+
* undo/redo stack, auto-syncing required state (see "Auto
201+
* Synchronization" above).
177202
*
178203
* - Changes are registered to the PkgEntry on whose behalf we
179204
* manage/monitor (i.e. this.ePkg). This must be consistent with
@@ -184,15 +209,10 @@ export default class ChangeManager {
184209
* `changeFn()` / `undoFn()` is as follows:
185210
*
186211
* ```js
187-
* + changeFn(redoIndicator: <boolean>): targetObj
188-
* + undoFn(): targetObj
212+
* + changeFn(): targetObj
213+
* + undoFn(): targetObj
189214
* ```
190215
*
191-
* - The `redoIndicator` param is an indicator as to whether the invocation
192-
* is a **redo** operation, verses the initial execution.
193-
* Typically a redo requires more work (for example syncing
194-
* **both** the SmartObject and Konva realms).
195-
*
196216
* - Both functions return the targetObj of the operation. This is
197217
* used to seed the synchronization of other parts of the model
198218
* ... via the `SmartModel.trickleUpChange()` method.
@@ -206,11 +226,9 @@ export default class ChangeManager {
206226
* active object.
207227
*
208228
* - Also, these change functions should only be concerned with the
209-
* modification of a given low-level object. ChangeManager will
210-
* orchestrate additional detail to insure conformity. For
211-
* example, the service will issue the `targetObj.trickleUpChange()`
212-
* which syncs the change to it parentage (synchronizing size and
213-
* crc, etc.).
229+
* modification of a given low-level SmartObject. ChangeManager
230+
* will orchestrate additional detail to insure conformity (see
231+
* "Auto Synchronization" above).
214232
*
215233
* **Please Note** this service uses named parameters.
216234
*
@@ -239,34 +257,28 @@ export default class ChangeManager {
239257
this.undoRedoMgr.registerOp(undoFn, changeFn);
240258

241259
// apply the initial change
242-
// NOTE: The change process auto-syncs our parentage -and- our ChangeMonitor state
243-
// (via the trickleUpChange() mechanism)
244-
applyChange(check, this.ePkg, changeFn, false/*NOT a redo (rather our initial change)*/);
260+
applyChange(check, this.ePkg, changeFn);
245261
}
246262

247263

248264
/**
249265
* Apply an "undo" operation to the PkgEntry on whose behalf we are
250-
* managing, auto-syncing the parentage -and- our ChangeMonitor
251-
* state.
266+
* managing, auto-syncing required state (see "Auto Synchronization"
267+
* above).
252268
*/
253269
applyUndo() {
254270
// simply propagate request into our undoRedoMgr
255-
// NOTE: This process auto-syncs our parentage -and- our ChangeMonitor state
256-
// (via the trickleUpChange() mechanism)
257271
this.undoRedoMgr.applyUndo();
258272
}
259273

260274

261275
/**
262276
* Apply an "redo" operation to the PkgEntry on whose behalf we are
263-
* managing, auto-syncing the parentage -and- our ChangeMonitor
264-
* state.
277+
* managing, auto-syncing required state (see "Auto Synchronization"
278+
* above).
265279
*/
266280
applyRedo() {
267281
// simply propagate request into our undoRedoMgr
268-
// NOTE: This process auto-syncs our parentage -and- our ChangeMonitor state
269-
// (via the trickleUpChange() mechanism)
270282
this.undoRedoMgr.applyRedo();
271283
}
272284

0 commit comments

Comments
 (0)