Mercurial > code > home > repos > light9
annotate web/timeline/adjustable.ts @ 2450:a4052905ca7d default tip
notes about how rdfdb syncs, or should sync
author | drewp@bigasterisk.com |
---|---|
date | Mon, 03 Jun 2024 23:01:54 -0700 |
parents | 4556eebe5d73 |
children |
rev | line source |
---|---|
2062 | 1 import * as d3 from "d3"; |
2 import { debug } from "debug"; | |
3 import * as ko from "knockout"; | |
4 const log = debug("adjustable"); | |
1901
7fe81130b735
move web logging to https://github.com/visionmedia/debug/ so it can have channels that can be turned off
Drew Perttula <drewp@bigasterisk.com>
parents:
1815
diff
changeset
|
5 |
2062 | 6 interface Config { |
7 // getTarget -> vec2 of current target position | |
8 getTarget: () => Vector; | |
9 // getSuggestedTargetOffset -> vec2 pixel offset from target | |
10 getSuggestedTargetOffset: () => Vector; | |
11 // emptyBox -> true if you want no value display | |
12 emptyBox: boolean; | |
13 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
14 |
2062 | 15 export class Adjustable { |
16 config: any; | |
17 handle: any; | |
18 initialTarget: any; | |
19 targetDraggedTo: any; | |
20 root: any; | |
21 // Some value you can edit in the UI, probably by dragging | |
22 // stuff. Drawn by light9-adjusters-canvas. This object does the | |
23 // layout and positioning. | |
24 // | |
25 // The way dragging should work is that you start in the yellow *adj | |
26 // widget*, wherever it is, but your drag is moving the *target*. The | |
27 // adj will travel around too, but it may do extra moves to not bump | |
28 // into stuff or to get out from under your finger. | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
29 |
2062 | 30 constructor(config: any) { |
31 this.config = config; | |
32 this.ctor2(); | |
33 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
34 |
2062 | 35 ctor2() { |
36 // updated later by layout algoritm | |
37 return (this.handle = $V([0, 0])); | |
38 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
39 |
2062 | 40 getDisplayValue() { |
41 if (this.config.emptyBox) { | |
42 return ""; | |
43 } | |
44 const defaultFormat = d3.format(".4g")(this._getValue()); | |
45 if (this.config.getDisplayValue != null) { | |
46 return this.config.getDisplayValue(this._getValue(), defaultFormat); | |
47 } | |
48 return defaultFormat; | |
49 } | |
50 _getValue(): any { | |
51 throw new Error("Method not implemented."); | |
52 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
53 |
2062 | 54 getSuggestedHandle() { |
55 return this.getTarget().add(this.config.getSuggestedTargetOffset()); | |
56 } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
57 |
2062 | 58 getHandle() { |
59 // vec2 of pixels | |
60 return this.handle; | |
61 } | |
62 | |
63 getTarget() { | |
64 // vec2 of pixels | |
65 return this.config.getTarget(); | |
66 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
67 |
2062 | 68 subscribe(onChange: any) { |
69 // change could be displayValue or center or target. This likely | |
70 // calls onChange right away if there's any data yet. | |
71 throw new Error("not implemented"); | |
72 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
73 |
2062 | 74 startDrag() { |
75 return (this.initialTarget = this.getTarget()); | |
76 } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
77 |
2062 | 78 continueDrag(pos: { add: (arg0: any) => any }) { |
79 //# pos is vec2 of pixels relative to the drag start | |
80 return (this.targetDraggedTo = pos.add(this.initialTarget)); | |
81 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
82 |
2062 | 83 endDrag() {} |
84 // override | |
85 | |
86 _editorCoordinates() { | |
87 // vec2 of mouse relative to <l9-t-editor> | |
88 let rootElem: { getBoundingClientRect: () => any }; | |
89 return this.targetDraggedTo; | |
90 // let ev = d3.event.sourceEvent; | |
1328
e4825767a4bf
fixes to RDF adjusters. put graph load in an element.
Drew Perttula <drewp@bigasterisk.com>
parents:
1327
diff
changeset
|
91 |
2062 | 92 // if (ev.target.tagName === "LIGHT9-TIMELINE-EDITOR") { |
93 // rootElem = ev.target; | |
94 // } else { | |
95 // rootElem = ev.target.closest("light9-timeline-editor"); | |
96 // } | |
1328
e4825767a4bf
fixes to RDF adjusters. put graph load in an element.
Drew Perttula <drewp@bigasterisk.com>
parents:
1327
diff
changeset
|
97 |
2062 | 98 // if (ev.touches != null ? ev.touches.length : undefined) { |
99 // ev = ev.touches[0]; | |
100 // } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
101 |
2062 | 102 // // storing root on the object to remember it across calls in case |
103 // // you drag outside the editor. | |
104 // if (rootElem) { | |
105 // this.root = rootElem.getBoundingClientRect(); | |
106 // } | |
107 // const offsetParentPos = $V([ev.pageX - this.root.left, ev.pageY - this.root.top]); | |
1328
e4825767a4bf
fixes to RDF adjusters. put graph load in an element.
Drew Perttula <drewp@bigasterisk.com>
parents:
1327
diff
changeset
|
108 |
2062 | 109 // return offsetParentPos; |
110 } | |
111 } | |
1328
e4825767a4bf
fixes to RDF adjusters. put graph load in an element.
Drew Perttula <drewp@bigasterisk.com>
parents:
1327
diff
changeset
|
112 |
2062 | 113 class AdjustableFloatObservable extends Adjustable { |
114 constructor(config: any) { | |
115 // config also has: | |
116 // observable -> ko.observable we will read and write | |
117 // getValueForPos(pos) -> what should we set to if the user | |
118 // moves target to this coord? | |
119 this.config = config; | |
120 super(); | |
121 this.ctor2(); | |
122 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
123 |
2062 | 124 _getValue() { |
125 return this.config.observable(); | |
126 } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
127 |
2062 | 128 continueDrag(pos: any) { |
129 // pos is vec2 of pixels relative to the drag start. | |
130 super.continueDrag(pos); | |
131 const epos = this._editorCoordinates(); | |
132 const newValue = this.config.getValueForPos(epos); | |
133 return this.config.observable(newValue); | |
134 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
135 |
2062 | 136 subscribe(onChange: () => any) { |
137 log("AdjustableFloatObservable subscribe", this.config); | |
138 return ko.computed(() => { | |
139 this.config.observable(); | |
140 return onChange(); | |
141 }); | |
142 } | |
143 } | |
144 | |
145 class AdjustableFloatObject extends Adjustable { | |
146 _currentValue: any; | |
147 _onChange: any; | |
148 constructor(config: any) { | |
149 // config also has: | |
150 // graph | |
151 // subj | |
152 // pred | |
153 // ctx | |
154 // getTargetPosForValue(value) -> getTarget result for value | |
155 // getValueForPos | |
156 this.config = config; | |
157 super(); | |
158 this.ctor2(); | |
159 if (this.config.ctx == null) { | |
160 throw new Error("missing ctx"); | |
161 } | |
162 // this seems to not fire enough. | |
163 this.config.graph.runHandler(this._syncValue.bind(this), `adj sync ${this.config.subj.value} ${this.config.pred.value}`); | |
164 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
165 |
2062 | 166 _syncValue() { |
167 this._currentValue = this.config.graph.floatValue(this.config.subj, this.config.pred); | |
168 if (this._onChange) { | |
169 return this._onChange(); | |
170 } | |
171 } | |
172 | |
173 _getValue() { | |
174 // this is a big speedup- callers use _getValue about 4x as much as | |
175 // the graph changes and graph.floatValue is slow | |
176 return this._currentValue; | |
177 } | |
178 | |
179 getTarget() { | |
180 return this.config.getTargetPosForValue(this._getValue()); | |
181 } | |
1385
748a2e8afd30
rdf graph adjuster, use new runHandler api
Drew Perttula <drewp@bigasterisk.com>
parents:
1380
diff
changeset
|
182 |
2062 | 183 subscribe(onChange: any) { |
184 // only works on one subscription at a time | |
185 if (this._onChange) { | |
186 throw new Error("multi subscribe not implemented"); | |
187 } | |
188 return (this._onChange = onChange); | |
189 } | |
1327
d6396679c121
move to adjustable.coffee and also simplify the getTarget code
Drew Perttula <drewp@bigasterisk.com>
parents:
diff
changeset
|
190 |
2062 | 191 continueDrag(pos: any) { |
192 // pos is vec2 of pixels relative to the drag start | |
193 super.continueDrag(pos); | |
194 const newValue = this.config.getValueForPos(this._editorCoordinates()); | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
195 |
2062 | 196 return this.config.graph.patchObject(this.config.subj, this.config.pred, this.config.graph.LiteralRoundedFloat(newValue), this.config.ctx); |
197 //@_syncValue() | |
198 } | |
199 } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
200 |
2062 | 201 class AdjustableFade extends Adjustable { |
202 yForV: any; | |
203 zoomInX: any; | |
204 i0: any; | |
205 i1: any; | |
206 note: any; | |
207 constructor(yForV: any, zoomInX: any, i0: any, i1: any, note: any, offset: any, ctx: any) { | |
208 this.yForV = yForV; | |
209 this.zoomInX = zoomInX; | |
210 this.i0 = i0; | |
211 this.i1 = i1; | |
212 this.note = note; | |
213 super(); | |
214 this.config = { | |
215 getSuggestedTargetOffset() { | |
216 return offset; | |
217 }, | |
218 getTarget: this.getTarget.bind(this), | |
219 ctx, | |
220 }; | |
221 this.ctor2(); | |
222 } | |
1753
3c997bc6d380
fix some coffee lint
Drew Perttula <drewp@bigasterisk.com>
parents:
1740
diff
changeset
|
223 |
2062 | 224 getTarget() { |
225 const mid = this.note.midPoint(this.i0, this.i1); | |
226 return $V([this.zoomInX(mid.e(1)), this.yForV(mid.e(2))]); | |
227 } | |
1644 | 228 |
2062 | 229 _getValue() { |
230 return this.note.midPoint(this.i0, this.i1).e(1); | |
231 } | |
1644 | 232 |
2062 | 233 continueDrag(pos: { e: (arg0: number) => any }) { |
234 // pos is vec2 of pixels relative to the drag start | |
235 super.continueDrag(pos); | |
236 const { graph } = this.note; | |
237 const U = (x: string) => graph.Uri(x); | |
238 | |
239 const goalCenterSec = this.zoomInX.invert(this.initialTarget.e(1) + pos.e(1)); | |
1644 | 240 |
2062 | 241 const diamSec = this.note.worldPts[this.i1].e(1) - this.note.worldPts[this.i0].e(1); |
242 const newSec0 = goalCenterSec - diamSec / 2; | |
243 const newSec1 = goalCenterSec + diamSec / 2; | |
1644 | 244 |
2062 | 245 const originSec = graph.floatValue(this.note.uri, U(":originTime")); |
1644 | 246 |
2062 | 247 const p0 = this._makePatch(graph, this.i0, newSec0, originSec, this.config.ctx); |
248 const p1 = this._makePatch(graph, this.i1, newSec1, originSec, this.config.ctx); | |
1644 | 249 |
2062 | 250 return graph.applyAndSendPatch(this._addPatches(p0, p1)); |
251 } | |
1644 | 252 |
2062 | 253 _makePatch( |
254 graph: { getObjectPatch: (arg0: any, arg1: any, arg2: any, arg3: any) => any; Uri: (arg0: string) => any; LiteralRoundedFloat: (arg0: number) => any }, | |
255 idx: string | number, | |
256 newSec: number, | |
257 originSec: number, | |
258 ctx: any | |
259 ) { | |
260 return graph.getObjectPatch(this.note.worldPts[idx].uri, graph.Uri(":time"), graph.LiteralRoundedFloat(newSec - originSec), ctx); | |
261 } | |
1644 | 262 |
2062 | 263 _addPatches(p0: { addQuads: { concat: (arg0: any) => any }; delQuads: { concat: (arg0: any) => any } }, p1: { addQuads: any; delQuads: any }) { |
264 return { | |
1644 | 265 addQuads: p0.addQuads.concat(p1.addQuads), |
2062 | 266 delQuads: p0.delQuads.concat(p1.delQuads), |
267 }; | |
268 } | |
269 } |