Input handling library for Zdog.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial commit

Different55 8d3736dc

+668
+373
LICENSE
··· 1 + Mozilla Public License Version 2.0 2 + ================================== 3 + 4 + 1. Definitions 5 + -------------- 6 + 7 + 1.1. "Contributor" 8 + means each individual or legal entity that creates, contributes to 9 + the creation of, or owns Covered Software. 10 + 11 + 1.2. "Contributor Version" 12 + means the combination of the Contributions of others (if any) used 13 + by a Contributor and that particular Contributor's Contribution. 14 + 15 + 1.3. "Contribution" 16 + means Covered Software of a particular Contributor. 17 + 18 + 1.4. "Covered Software" 19 + means Source Code Form to which the initial Contributor has attached 20 + the notice in Exhibit A, the Executable Form of such Source Code 21 + Form, and Modifications of such Source Code Form, in each case 22 + including portions thereof. 23 + 24 + 1.5. "Incompatible With Secondary Licenses" 25 + means 26 + 27 + (a) that the initial Contributor has attached the notice described 28 + in Exhibit B to the Covered Software; or 29 + 30 + (b) that the Covered Software was made available under the terms of 31 + version 1.1 or earlier of the License, but not also under the 32 + terms of a Secondary License. 33 + 34 + 1.6. "Executable Form" 35 + means any form of the work other than Source Code Form. 36 + 37 + 1.7. "Larger Work" 38 + means a work that combines Covered Software with other material, in 39 + a separate file or files, that is not Covered Software. 40 + 41 + 1.8. "License" 42 + means this document. 43 + 44 + 1.9. "Licensable" 45 + means having the right to grant, to the maximum extent possible, 46 + whether at the time of the initial grant or subsequently, any and 47 + all of the rights conveyed by this License. 48 + 49 + 1.10. "Modifications" 50 + means any of the following: 51 + 52 + (a) any file in Source Code Form that results from an addition to, 53 + deletion from, or modification of the contents of Covered 54 + Software; or 55 + 56 + (b) any new file in Source Code Form that contains any Covered 57 + Software. 58 + 59 + 1.11. "Patent Claims" of a Contributor 60 + means any patent claim(s), including without limitation, method, 61 + process, and apparatus claims, in any patent Licensable by such 62 + Contributor that would be infringed, but for the grant of the 63 + License, by the making, using, selling, offering for sale, having 64 + made, import, or transfer of either its Contributions or its 65 + Contributor Version. 66 + 67 + 1.12. "Secondary License" 68 + means either the GNU General Public License, Version 2.0, the GNU 69 + Lesser General Public License, Version 2.1, the GNU Affero General 70 + Public License, Version 3.0, or any later versions of those 71 + licenses. 72 + 73 + 1.13. "Source Code Form" 74 + means the form of the work preferred for making modifications. 75 + 76 + 1.14. "You" (or "Your") 77 + means an individual or a legal entity exercising rights under this 78 + License. For legal entities, "You" includes any entity that 79 + controls, is controlled by, or is under common control with You. For 80 + purposes of this definition, "control" means (a) the power, direct 81 + or indirect, to cause the direction or management of such entity, 82 + whether by contract or otherwise, or (b) ownership of more than 83 + fifty percent (50%) of the outstanding shares or beneficial 84 + ownership of such entity. 85 + 86 + 2. License Grants and Conditions 87 + -------------------------------- 88 + 89 + 2.1. Grants 90 + 91 + Each Contributor hereby grants You a world-wide, royalty-free, 92 + non-exclusive license: 93 + 94 + (a) under intellectual property rights (other than patent or trademark) 95 + Licensable by such Contributor to use, reproduce, make available, 96 + modify, display, perform, distribute, and otherwise exploit its 97 + Contributions, either on an unmodified basis, with Modifications, or 98 + as part of a Larger Work; and 99 + 100 + (b) under Patent Claims of such Contributor to make, use, sell, offer 101 + for sale, have made, import, and otherwise transfer either its 102 + Contributions or its Contributor Version. 103 + 104 + 2.2. Effective Date 105 + 106 + The licenses granted in Section 2.1 with respect to any Contribution 107 + become effective for each Contribution on the date the Contributor first 108 + distributes such Contribution. 109 + 110 + 2.3. Limitations on Grant Scope 111 + 112 + The licenses granted in this Section 2 are the only rights granted under 113 + this License. No additional rights or licenses will be implied from the 114 + distribution or licensing of Covered Software under this License. 115 + Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 + Contributor: 117 + 118 + (a) for any code that a Contributor has removed from Covered Software; 119 + or 120 + 121 + (b) for infringements caused by: (i) Your and any other third party's 122 + modifications of Covered Software, or (ii) the combination of its 123 + Contributions with other software (except as part of its Contributor 124 + Version); or 125 + 126 + (c) under Patent Claims infringed by Covered Software in the absence of 127 + its Contributions. 128 + 129 + This License does not grant any rights in the trademarks, service marks, 130 + or logos of any Contributor (except as may be necessary to comply with 131 + the notice requirements in Section 3.4). 132 + 133 + 2.4. Subsequent Licenses 134 + 135 + No Contributor makes additional grants as a result of Your choice to 136 + distribute the Covered Software under a subsequent version of this 137 + License (see Section 10.2) or under the terms of a Secondary License (if 138 + permitted under the terms of Section 3.3). 139 + 140 + 2.5. Representation 141 + 142 + Each Contributor represents that the Contributor believes its 143 + Contributions are its original creation(s) or it has sufficient rights 144 + to grant the rights to its Contributions conveyed by this License. 145 + 146 + 2.6. Fair Use 147 + 148 + This License is not intended to limit any rights You have under 149 + applicable copyright doctrines of fair use, fair dealing, or other 150 + equivalents. 151 + 152 + 2.7. Conditions 153 + 154 + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 + in Section 2.1. 156 + 157 + 3. Responsibilities 158 + ------------------- 159 + 160 + 3.1. Distribution of Source Form 161 + 162 + All distribution of Covered Software in Source Code Form, including any 163 + Modifications that You create or to which You contribute, must be under 164 + the terms of this License. You must inform recipients that the Source 165 + Code Form of the Covered Software is governed by the terms of this 166 + License, and how they can obtain a copy of this License. You may not 167 + attempt to alter or restrict the recipients' rights in the Source Code 168 + Form. 169 + 170 + 3.2. Distribution of Executable Form 171 + 172 + If You distribute Covered Software in Executable Form then: 173 + 174 + (a) such Covered Software must also be made available in Source Code 175 + Form, as described in Section 3.1, and You must inform recipients of 176 + the Executable Form how they can obtain a copy of such Source Code 177 + Form by reasonable means in a timely manner, at a charge no more 178 + than the cost of distribution to the recipient; and 179 + 180 + (b) You may distribute such Executable Form under the terms of this 181 + License, or sublicense it under different terms, provided that the 182 + license for the Executable Form does not attempt to limit or alter 183 + the recipients' rights in the Source Code Form under this License. 184 + 185 + 3.3. Distribution of a Larger Work 186 + 187 + You may create and distribute a Larger Work under terms of Your choice, 188 + provided that You also comply with the requirements of this License for 189 + the Covered Software. If the Larger Work is a combination of Covered 190 + Software with a work governed by one or more Secondary Licenses, and the 191 + Covered Software is not Incompatible With Secondary Licenses, this 192 + License permits You to additionally distribute such Covered Software 193 + under the terms of such Secondary License(s), so that the recipient of 194 + the Larger Work may, at their option, further distribute the Covered 195 + Software under the terms of either this License or such Secondary 196 + License(s). 197 + 198 + 3.4. Notices 199 + 200 + You may not remove or alter the substance of any license notices 201 + (including copyright notices, patent notices, disclaimers of warranty, 202 + or limitations of liability) contained within the Source Code Form of 203 + the Covered Software, except that You may alter any license notices to 204 + the extent required to remedy known factual inaccuracies. 205 + 206 + 3.5. Application of Additional Terms 207 + 208 + You may choose to offer, and to charge a fee for, warranty, support, 209 + indemnity or liability obligations to one or more recipients of Covered 210 + Software. However, You may do so only on Your own behalf, and not on 211 + behalf of any Contributor. You must make it absolutely clear that any 212 + such warranty, support, indemnity, or liability obligation is offered by 213 + You alone, and You hereby agree to indemnify every Contributor for any 214 + liability incurred by such Contributor as a result of warranty, support, 215 + indemnity or liability terms You offer. You may include additional 216 + disclaimers of warranty and limitations of liability specific to any 217 + jurisdiction. 218 + 219 + 4. Inability to Comply Due to Statute or Regulation 220 + --------------------------------------------------- 221 + 222 + If it is impossible for You to comply with any of the terms of this 223 + License with respect to some or all of the Covered Software due to 224 + statute, judicial order, or regulation then You must: (a) comply with 225 + the terms of this License to the maximum extent possible; and (b) 226 + describe the limitations and the code they affect. Such description must 227 + be placed in a text file included with all distributions of the Covered 228 + Software under this License. Except to the extent prohibited by statute 229 + or regulation, such description must be sufficiently detailed for a 230 + recipient of ordinary skill to be able to understand it. 231 + 232 + 5. Termination 233 + -------------- 234 + 235 + 5.1. The rights granted under this License will terminate automatically 236 + if You fail to comply with any of its terms. However, if You become 237 + compliant, then the rights granted under this License from a particular 238 + Contributor are reinstated (a) provisionally, unless and until such 239 + Contributor explicitly and finally terminates Your grants, and (b) on an 240 + ongoing basis, if such Contributor fails to notify You of the 241 + non-compliance by some reasonable means prior to 60 days after You have 242 + come back into compliance. Moreover, Your grants from a particular 243 + Contributor are reinstated on an ongoing basis if such Contributor 244 + notifies You of the non-compliance by some reasonable means, this is the 245 + first time You have received notice of non-compliance with this License 246 + from such Contributor, and You become compliant prior to 30 days after 247 + Your receipt of the notice. 248 + 249 + 5.2. If You initiate litigation against any entity by asserting a patent 250 + infringement claim (excluding declaratory judgment actions, 251 + counter-claims, and cross-claims) alleging that a Contributor Version 252 + directly or indirectly infringes any patent, then the rights granted to 253 + You by any and all Contributors for the Covered Software under Section 254 + 2.1 of this License shall terminate. 255 + 256 + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 + end user license agreements (excluding distributors and resellers) which 258 + have been validly granted by You or Your distributors under this License 259 + prior to termination shall survive termination. 260 + 261 + ************************************************************************ 262 + * * 263 + * 6. Disclaimer of Warranty * 264 + * ------------------------- * 265 + * * 266 + * Covered Software is provided under this License on an "as is" * 267 + * basis, without warranty of any kind, either expressed, implied, or * 268 + * statutory, including, without limitation, warranties that the * 269 + * Covered Software is free of defects, merchantable, fit for a * 270 + * particular purpose or non-infringing. The entire risk as to the * 271 + * quality and performance of the Covered Software is with You. * 272 + * Should any Covered Software prove defective in any respect, You * 273 + * (not any Contributor) assume the cost of any necessary servicing, * 274 + * repair, or correction. This disclaimer of warranty constitutes an * 275 + * essential part of this License. No use of any Covered Software is * 276 + * authorized under this License except under this disclaimer. * 277 + * * 278 + ************************************************************************ 279 + 280 + ************************************************************************ 281 + * * 282 + * 7. Limitation of Liability * 283 + * -------------------------- * 284 + * * 285 + * Under no circumstances and under no legal theory, whether tort * 286 + * (including negligence), contract, or otherwise, shall any * 287 + * Contributor, or anyone who distributes Covered Software as * 288 + * permitted above, be liable to You for any direct, indirect, * 289 + * special, incidental, or consequential damages of any character * 290 + * including, without limitation, damages for lost profits, loss of * 291 + * goodwill, work stoppage, computer failure or malfunction, or any * 292 + * and all other commercial damages or losses, even if such party * 293 + * shall have been informed of the possibility of such damages. This * 294 + * limitation of liability shall not apply to liability for death or * 295 + * personal injury resulting from such party's negligence to the * 296 + * extent applicable law prohibits such limitation. Some * 297 + * jurisdictions do not allow the exclusion or limitation of * 298 + * incidental or consequential damages, so this exclusion and * 299 + * limitation may not apply to You. * 300 + * * 301 + ************************************************************************ 302 + 303 + 8. Litigation 304 + ------------- 305 + 306 + Any litigation relating to this License may be brought only in the 307 + courts of a jurisdiction where the defendant maintains its principal 308 + place of business and such litigation shall be governed by laws of that 309 + jurisdiction, without reference to its conflict-of-law provisions. 310 + Nothing in this Section shall prevent a party's ability to bring 311 + cross-claims or counter-claims. 312 + 313 + 9. Miscellaneous 314 + ---------------- 315 + 316 + This License represents the complete agreement concerning the subject 317 + matter hereof. If any provision of this License is held to be 318 + unenforceable, such provision shall be reformed only to the extent 319 + necessary to make it enforceable. Any law or regulation which provides 320 + that the language of a contract shall be construed against the drafter 321 + shall not be used to construe this License against a Contributor. 322 + 323 + 10. Versions of the License 324 + --------------------------- 325 + 326 + 10.1. New Versions 327 + 328 + Mozilla Foundation is the license steward. Except as provided in Section 329 + 10.3, no one other than the license steward has the right to modify or 330 + publish new versions of this License. Each version will be given a 331 + distinguishing version number. 332 + 333 + 10.2. Effect of New Versions 334 + 335 + You may distribute the Covered Software under the terms of the version 336 + of the License under which You originally received the Covered Software, 337 + or under the terms of any subsequent version published by the license 338 + steward. 339 + 340 + 10.3. Modified Versions 341 + 342 + If you create software not governed by this License, and you want to 343 + create a new license for such software, you may create and use a 344 + modified version of this License if you rename the license and remove 345 + any references to the name of the license steward (except to note that 346 + such modified license differs from this License). 347 + 348 + 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 + Licenses 350 + 351 + If You choose to distribute Source Code Form that is Incompatible With 352 + Secondary Licenses under the terms of this version of the License, the 353 + notice described in Exhibit B of this License must be attached. 354 + 355 + Exhibit A - Source Code Form License Notice 356 + ------------------------------------------- 357 + 358 + This Source Code Form is subject to the terms of the Mozilla Public 359 + License, v. 2.0. If a copy of the MPL was not distributed with this 360 + file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 + 362 + If it is not possible or desirable to put the notice in a particular 363 + file, then You may include the notice in a location (such as a LICENSE 364 + file in a relevant directory) where a recipient would be likely to look 365 + for such a notice. 366 + 367 + You may add additional accurate notices of copyright ownership. 368 + 369 + Exhibit B - "Incompatible With Secondary Licenses" Notice 370 + --------------------------------------------------------- 371 + 372 + This Source Code Form is "Incompatible With Secondary Licenses", as 373 + defined by the Mozilla Public License, v. 2.0.
+25
README.md
··· 1 + # Zfetch 2 + 3 + *Better input handling for Zdog, the pseudo-3D engine.* 4 + 5 + ## Status 6 + 7 + Currently un-minified and under active development. 8 + 9 + ## About Zfetch 10 + 11 + I'm working on an application built on Zdog and I needed better input handling 12 + that was aware of Zdog and its quirks. What Zfetch does is allow you to set 13 + event event handlers for `click` and `pointerdown/move/up` events and have 14 + those handlers be aware of exactly which Zdog shape the mouse is over. 15 + 16 + In the future, I'd like to support setting event handlers on arbitrary Zdog 17 + objects and have events bubble up the Zdog hierarchy. Currently, all events 18 + pass through the root SVG or Canvas and must be delegated from there. 19 + 20 + Current limitations: 21 + - Canvas is not supported, only SVG. (This wouldn't be a large task) 22 + 23 + Pull requests and suggestions are welcome! 24 + 25 + This is currently being actively developed alongside [Zoodle](https://github.com/different55/zoodle).
+270
zfetch.js
··· 1 + /** Zfetch 2 + * Input handler for Zdog 3 + */ 4 + 5 + ( function( root, factory ) { 6 + // module definition 7 + if ( typeof module == 'object' && module.exports ) { 8 + // CommonJS 9 + module.exports = factory(); 10 + } else { 11 + // browser global 12 + root.Zfetch = factory(); 13 + } 14 + }( this, function factory() { 15 + var DEBUG = false; 16 + if ( typeof window == 'undefined' || !window.PointerEvent ) { 17 + console.error( 'Zfetch requires PointerEvent support.' ); 18 + return; 19 + } 20 + 21 + function noop() {} 22 + 23 + Zfetch.prototype.rotateStart = function( pointer ) { 24 + this.rotateStartX = this.scene.rotate.x; 25 + this.rotateStartY = this.scene.rotate.y; 26 + } 27 + 28 + Zfetch.prototype.rotateMove = function( pointer, target, moveX, moveY ) { 29 + let displaySize = Math.min( this.scene.width, this.scene.height ); 30 + let moveRY = moveX / displaySize * Math.PI * Zdog.TAU; 31 + let moveRX = moveY / displaySize * Math.PI * Zdog.TAU; 32 + this.scene.rotate.x = this.rotateStartX - moveRX; 33 + this.scene.rotate.y = this.rotateStartY - moveRY; 34 + } 35 + 36 + function Zfetch( options ) { 37 + this.init( options || {} ); 38 + } 39 + 40 + Zfetch.prototype.init = function( options ) { 41 + this.click = options.click || noop; 42 + this.dragStart = options.dragStart || (options.dragRotate ? this.rotateStart : noop); 43 + this.dragMove = options.dragMove || (options.dragRotate ? this.rotateMove : noop); 44 + this.dragEnd = options.dragEnd || noop; 45 + this.capture = options.capture || false; 46 + this.dragRotate = options.dragRotate; 47 + this.scene = options.scene; 48 + this.startElement = options.scene.element; 49 + 50 + this.bindListeners( this.startElement ); 51 + this.initGhost( options.scene ); 52 + }; 53 + 54 + Zfetch.prototype.bindListeners = function( element ) { 55 + element = this.getQueryElement( element ); 56 + if ( !element ) { 57 + console.error( 'Zfetch: startElement not found: ' + element ); 58 + return; 59 + } 60 + // disable browser gestures 61 + // issue #53 on Zdog GitHub 62 + element.style.touchAction = 'none'; 63 + element.addEventListener( 'pointerdown', this ); 64 + }; 65 + 66 + Zfetch.prototype.getQueryElement = function( element ) { 67 + if ( typeof element == 'string' ) { 68 + // with string, use query selector 69 + return document.querySelector( element ); 70 + } 71 + return element; 72 + }; 73 + 74 + Zfetch.prototype.handleEvent = function( event ) { 75 + if (DEBUG) console.log(event.type, event); 76 + var method = this[ 'on' + event.type ]; 77 + if ( method ) { 78 + method.call( this, event ); 79 + } 80 + }; 81 + 82 + Zfetch.prototype.down = function( event ) { 83 + if ( !event.isPrimary ) return; 84 + 85 + if (this.capture) { 86 + this.startElement.setPointerCapture( event.pointerId ); 87 + } 88 + 89 + this.downX = event.pageX; 90 + this.downY = event.pageY; 91 + this.moveX = 0; 92 + this.moveY = 0; 93 + this.downId = event.pointerId; 94 + 95 + this.dragEvent = event; 96 + this.onpointermove = this.moveDeadzone; 97 + 98 + this.startElement.addEventListener( 'pointermove', this ); 99 + this.startElement.addEventListener( 'pointerup', this ); 100 + this.startElement.addEventListener( 'pointercancel', this ); 101 + }; 102 + 103 + Zfetch.prototype.move = function( event ) { 104 + if ( event.pointerId != this.downId ) return; 105 + 106 + this.moveX = event.pageX - this.downX; 107 + this.moveY = event.pageY - this.downY; 108 + this.dispatchDragMove( event ); 109 + }; 110 + 111 + Zfetch.prototype.moveDeadzone = function( event ) { 112 + if ( event.pointerId != this.downId ) return; 113 + 114 + let moveX = event.pageX - this.downX; 115 + let moveY = event.pageY - this.downY; 116 + 117 + var deadzone = 5; 118 + if ( event.pointerType == 'mouse' ) 119 + deadzone = -1; 120 + if ( Math.abs( moveX ) > deadzone || Math.abs( moveY ) > deadzone ) { 121 + this.dispatchDragStart( this.dragEvent ); 122 + this.onpointermove = this.move; 123 + this.onpointermove( event ); 124 + } 125 + } 126 + 127 + Zfetch.prototype.up = function( event ) { 128 + if ( event.pointerId != this.downId ) return; 129 + 130 + if (DEBUG) console.log("going uuuuup", event); 131 + 132 + if ( this.moveX || this.moveY ) { 133 + this.dispatchDragEnd( event ); 134 + } else { 135 + this.dispatchClick( event ); 136 + } 137 + 138 + this.startElement.removeEventListener( 'pointermove', this ); 139 + this.startElement.removeEventListener( 'pointerup', this ); 140 + this.startElement.removeEventListener( 'pointercancel', this ); 141 + }; 142 + 143 + Zfetch.prototype.onpointerdown = Zfetch.prototype.down; 144 + Zfetch.prototype.onpointermove = Zfetch.prototype.move; 145 + Zfetch.prototype.onpointerup = 146 + Zfetch.prototype.onpointercancel = Zfetch.prototype.up; 147 + 148 + Zfetch.prototype.dispatchDragStart = function( event ) { 149 + this.dragEvent = null; 150 + this.dispatch( "dragStart", event ); 151 + }; 152 + 153 + Zfetch.prototype.dispatchDragMove = function( event ) { 154 + this.dispatch( "dragMove", event ); 155 + }; 156 + 157 + Zfetch.prototype.dispatchDragEnd = function( event ) { 158 + this.dispatch( "dragEnd", event ); 159 + }; 160 + 161 + Zfetch.prototype.dispatchClick = function( event ) { 162 + this.dispatch( "click", event ); 163 + }; 164 + 165 + Zfetch.prototype.dispatch = function( event, pointer ) { 166 + if (DEBUG) console.log("dispatching", event, pointer); 167 + var moveX = this.moveX; 168 + var moveY = this.moveY; 169 + var target = this.getTargetShape( pointer ); 170 + target.element = this.startElement; 171 + if (DEBUG) console.log("pointer, target, x, y", pointer, target, moveX, moveY); 172 + this[ event ]( pointer, target, moveX, moveY ); 173 + }; 174 + 175 + Zfetch.prototype.initGhost = function( scene ) { 176 + if ( this.scene.isSvg ) { 177 + this.initSvgGhost( scene ); 178 + } else { 179 + this.initCanvasGhost( scene ); 180 + } 181 + this.updateGhost(); 182 + }; 183 + 184 + Zfetch.prototype.initSvgGhost = function() { 185 + this.ghostElem = document.createElement( 'svg' ); 186 + this.ghostElem.setAttribute( 'width', this.scene.element.clientWidth ); 187 + this.ghostElem.setAttribute( 'height', this.scene.element.clientHeight ); 188 + /*this.ghostElem.style.display = "none"; 189 + this.ghostElem = document.body.appendChild( this.ghostElem );*/ 190 + }; 191 + 192 + Zfetch.prototype.updateGhost = function() { 193 + this.ghost = this.scene.copyGraph({ element: this.ghostElem }); 194 + this.ghost.updateGraph(); 195 + for ( let i = 0; i < this.ghost.flatGraph.length; i++ ) { 196 + const shape = this.ghost.flatGraph[i]; 197 + shape.twin = this.scene.flatGraph[i]; 198 + shape.color = "#" + (i).toString(16).padStart(6, "0"); 199 + let faces = [ 200 + "leftFace", 201 + "rightFace", 202 + "topFace", 203 + "bottomFace", 204 + "frontFace", 205 + "rearFace", 206 + "backface" 207 + ]; 208 + // override overridden faces 209 + for ( let face of faces ) { 210 + if ( shape.twin[ face ] ) 211 + shape[ face ] = shape.color; 212 + } 213 + } 214 + this.ghost.renderGraph(); 215 + }; 216 + 217 + Zfetch.prototype.getSvgPath = function( root, element ) { 218 + const path = []; 219 + let current = element; 220 + 221 + while ( current !== root ) { 222 + const parent = current.parentElement; 223 + const index = Array.from( parent.children ).indexOf( current ); 224 + path.unshift( index ); 225 + current = parent; 226 + } 227 + 228 + return path; 229 + }; 230 + 231 + Zfetch.prototype.getElementByPath = function( root, path ) { 232 + let current = root; 233 + 234 + for ( const index of path ) { 235 + current = current.children[ index ]; 236 + } 237 + 238 + return current; 239 + }; 240 + 241 + // TODO: This isn't returning correctly for the surface of cylinders. 242 + Zfetch.prototype.getTargetShape = function( pointer ) { 243 + if ( this.scene.isSvg ) 244 + return this.getTargetShapeSvg( pointer ); 245 + 246 + return this.getTargetShapeCanvas( pointer ); 247 + }; 248 + 249 + Zfetch.prototype.getTargetShapeSvg = function( pointer ) { 250 + // happy path: if we're on an svg 251 + if ( pointer.target.tagName == "svg" ) 252 + return this.scene; 253 + 254 + this.updateGhost(); 255 + let path = this.getSvgPath( this.scene.element, pointer.target ); 256 + let ghostElem = this.getElementByPath( this.ghostElem, path ); 257 + let color = ghostElem.getAttribute( "fill" ); 258 + if ( color == "none" ) 259 + color = ghostElem.getAttribute( "stroke" ); 260 + if ( color == "none" ) 261 + return this.scene; 262 + let ghostShape = Array.from( this.ghost.flatGraph ).find( shape => shape.color === color ); 263 + if ( !ghostShape ) 264 + return this.scene; 265 + return ghostShape.twin; 266 + }; 267 + 268 + return Zfetch; 269 + 270 + }) );