@@ -16,13 +16,14 @@ tmpl.innerHTML = `
1616 </div>
1717`
1818
19- const startPositions = new WeakMap ( )
20- const dragStartPositions = new WeakMap ( )
21- const constructedElements = new WeakMap ( )
19+ const startPositions : WeakMap < ImageCropElement , { startX : number , startY : number } > = new WeakMap ( )
20+ const dragStartPositions : WeakMap < ImageCropElement , { dragStartX : number , dragStartY : number } > = new WeakMap ( )
21+ const constructedElements : WeakMap < ImageCropElement , { image : HTMLImageElement , box : HTMLElement } > = new WeakMap ( )
2222
2323function moveCropArea ( event : MouseEvent | KeyboardEvent ) {
2424 const el = event . currentTarget
2525 if ( ! ( el instanceof ImageCropElement ) ) return
26+ const { box, image} = constructedElements . get ( el ) || { }
2627
2728 let deltaX = 0
2829 let deltaY = 0
@@ -44,12 +45,12 @@ function moveCropArea(event: MouseEvent | KeyboardEvent) {
4445 }
4546
4647 if ( deltaX !== 0 || deltaY !== 0 ) {
47- const x = Math . min ( Math . max ( 0 , el . box . offsetLeft + deltaX ) , el . image . width - el . box . offsetWidth )
48- const y = Math . min ( Math . max ( 0 , el . box . offsetTop + deltaY ) , el . image . height - el . box . offsetHeight )
49- el . box . style . left = `${ x } px`
50- el . box . style . top = `${ y } px`
48+ const x = Math . min ( Math . max ( 0 , box . offsetLeft + deltaX ) , image . width - box . offsetWidth )
49+ const y = Math . min ( Math . max ( 0 , box . offsetTop + deltaY ) , image . height - box . offsetHeight )
50+ box . style . left = `${ x } px`
51+ box . style . top = `${ y } px`
5152
52- fireChangeEvent ( el , { x, y, width : el . box . offsetWidth , height : el . box . offsetHeight } )
53+ fireChangeEvent ( el , { x, y, width : box . offsetWidth , height : box . offsetHeight } )
5354 }
5455
5556 if ( event instanceof MouseEvent ) {
@@ -66,6 +67,7 @@ function updateCropArea(event: MouseEvent | KeyboardEvent) {
6667
6768 const el = target . closest ( 'image-crop' )
6869 if ( ! ( el instanceof ImageCropElement ) ) return
70+ const { box} = constructedElements . get ( el ) || { }
6971
7072 const rect = el . getBoundingClientRect ( )
7173 let deltaX , deltaY , delta
@@ -74,9 +76,9 @@ function updateCropArea(event: MouseEvent | KeyboardEvent) {
7476 if ( event . key === '-' ) delta = - 10
7577 if ( event . key === '=' ) delta = + 10
7678 if ( ! delta ) return
77- deltaX = el . box . offsetWidth + delta
78- deltaY = el . box . offsetHeight + delta
79- startPositions . set ( el , { startX : el . box . offsetLeft , startY : el . box . offsetTop } )
79+ deltaX = box . offsetWidth + delta
80+ deltaY = box . offsetHeight + delta
81+ startPositions . set ( el , { startX : box . offsetLeft , startY : box . offsetTop } )
8082 } else if ( event instanceof MouseEvent ) {
8183 const pos = startPositions . get ( el )
8284 if ( ! pos ) return
@@ -93,6 +95,7 @@ function startUpdate(event: MouseEvent) {
9395
9496 const el = currentTarget . closest ( 'image-crop' )
9597 if ( ! ( el instanceof ImageCropElement ) ) return
98+ const { box} = constructedElements . get ( el ) || { }
9699
97100 const target = event . target
98101 if ( ! ( target instanceof HTMLElement ) ) return
@@ -104,8 +107,8 @@ function startUpdate(event: MouseEvent) {
104107 if ( [ 'nw' , 'se' ] . indexOf ( direction ) >= 0 ) el . classList . add ( 'nwse' )
105108 if ( [ 'ne' , 'sw' ] . indexOf ( direction ) >= 0 ) el . classList . add ( 'nesw' )
106109 startPositions . set ( el , {
107- startX : el . box . offsetLeft + ( [ 'se' , 'ne' ] . indexOf ( direction ) >= 0 ? 0 : el . box . offsetWidth ) ,
108- startY : el . box . offsetTop + ( [ 'se' , 'sw' ] . indexOf ( direction ) >= 0 ? 0 : el . box . offsetHeight )
110+ startX : box . offsetLeft + ( [ 'se' , 'ne' ] . indexOf ( direction ) >= 0 ? 0 : box . offsetWidth ) ,
111+ startY : box . offsetTop + ( [ 'se' , 'sw' ] . indexOf ( direction ) >= 0 ? 0 : box . offsetHeight )
109112 } )
110113 updateCropArea ( event )
111114 } else {
@@ -118,20 +121,21 @@ function updateDimensions(target, deltaX, deltaY, reposition = true) {
118121 let newSide = Math . max ( Math . abs ( deltaX ) , Math . abs ( deltaY ) , 10 )
119122 const pos = startPositions . get ( target )
120123 if ( ! pos ) return
124+ const { box, image} = constructedElements . get ( target ) || { }
121125 newSide = Math . min (
122126 newSide ,
123- deltaY > 0 ? target . image . height - pos . startY : pos . startY ,
124- deltaX > 0 ? target . image . width - pos . startX : pos . startX
127+ deltaY > 0 ? image . height - pos . startY : pos . startY ,
128+ deltaX > 0 ? image . width - pos . startX : pos . startX
125129 )
126130
127- const x = reposition ? Math . round ( Math . max ( 0 , deltaX > 0 ? pos . startX : pos . startX - newSide ) ) : target . box . offsetLeft
128- const y = reposition ? Math . round ( Math . max ( 0 , deltaY > 0 ? pos . startY : pos . startY - newSide ) ) : target . box . offsetTop
131+ const x = reposition ? Math . round ( Math . max ( 0 , deltaX > 0 ? pos . startX : pos . startX - newSide ) ) : box . offsetLeft
132+ const y = reposition ? Math . round ( Math . max ( 0 , deltaY > 0 ? pos . startY : pos . startY - newSide ) ) : box . offsetTop
129133
130- target . box . style . left = `${ x } px`
131- target . box . style . top = `${ y } px`
134+ box . style . left = `${ x } px`
135+ box . style . top = `${ y } px`
132136
133- target . box . style . width = `${ newSide } px`
134- target . box . style . height = `${ newSide } px`
137+ box . style . width = `${ newSide } px`
138+ box . style . height = `${ newSide } px`
135139 fireChangeEvent ( target , { x, y, width : newSide , height : newSide } )
136140}
137141
@@ -147,7 +151,7 @@ function imageReady(event: Event) {
147151}
148152
149153function setInitialPosition ( el ) {
150- const image = el . image
154+ const { image} = constructedElements . get ( el ) || { }
151155 const side = Math . round ( image . clientWidth > image . clientHeight ? image . clientHeight : image . clientWidth )
152156 startPositions . set ( el , {
153157 startX : ( image . clientWidth - side ) / 2 ,
@@ -167,7 +171,8 @@ function stopUpdate(event: MouseEvent) {
167171}
168172
169173function fireChangeEvent ( target : ImageCropElement , result : { x : number , y : number , width : number , height : number } ) {
170- const ratio = target . image . naturalWidth / target . image . width
174+ const { image} = constructedElements . get ( target ) || { }
175+ const ratio = image . naturalWidth / image . width
171176 for ( const key in result ) {
172177 const value = Math . round ( result [ key ] * ratio )
173178 result [ key ] = value
@@ -179,31 +184,23 @@ function fireChangeEvent(target: ImageCropElement, result: {x: number, y: number
179184}
180185
181186class ImageCropElement extends HTMLElement {
182- image : HTMLImageElement
183- box : HTMLElement
184-
185187 connectedCallback ( ) {
186188 if ( constructedElements . has ( this ) ) return
187- constructedElements . set ( this , true )
188-
189189 this . appendChild ( document . importNode ( tmpl . content , true ) )
190-
191- const image = this . querySelector ( 'img' )
192- if ( ! ( image instanceof HTMLImageElement ) ) return
193- this . image = image
194-
195190 const box = this . querySelector ( '[data-crop-box]' )
196191 if ( ! ( box instanceof HTMLElement ) ) return
197- this . box = box
192+ const image = this . querySelector ( 'img' )
193+ if ( ! ( image instanceof HTMLImageElement ) ) return
194+ constructedElements . set ( this , { box, image} )
198195
199- this . image . addEventListener ( 'load' , imageReady )
196+ image . addEventListener ( 'load' , imageReady )
200197 this . addEventListener ( 'mouseleave' , stopUpdate )
201198 this . addEventListener ( 'mouseup' , stopUpdate )
202- this . box . addEventListener ( 'mousedown' , startUpdate )
199+ box . addEventListener ( 'mousedown' , startUpdate )
203200 this . addEventListener ( 'keydown' , moveCropArea )
204201 this . addEventListener ( 'keydown' , updateCropArea )
205202
206- if ( this . src ) this . image . src = this . src
203+ if ( this . src ) image . src = this . src
207204 }
208205
209206 static get observedAttributes ( ) {
@@ -235,9 +232,10 @@ class ImageCropElement extends HTMLElement {
235232 }
236233
237234 attributeChangedCallback ( attribute : string , oldValue : string , newValue : string ) {
235+ const { image} = constructedElements . get ( this ) || { }
238236 if ( attribute === 'src' ) {
239237 this . loaded = false
240- if ( this . image ) this . image . src = newValue
238+ if ( image ) image . src = newValue
241239 }
242240 }
243241}
0 commit comments