1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="UTF-8 ">
5+ <!-- UIkit CSS -->
6+ < link rel ="stylesheet " href ="https://cdn.jsdelivr.net/npm/uikit@3.2.1/dist/css/uikit.min.css " />
7+
8+ <!-- UIkit JS -->
9+ < script src ="https://cdn.jsdelivr.net/npm/uikit@3.2.1/dist/js/uikit.min.js "> </ script >
10+ < script src ="https://cdn.jsdelivr.net/npm/uikit@3.2.1/dist/js/uikit-icons.min.js "> </ script >
11+ < link href ='https://fonts.googleapis.com/css?family=Lato:300,900 ' rel ='stylesheet ' type ='text/css '>
12+ < title > Title</ title >
13+ < style >
14+ # svgWrapper {
15+ font-family : 'Lato' ;
16+ margin : 0 ;
17+ overflow : hidden;
18+ }
19+ .handle {
20+ fill : grey;
21+ fill-opacity : 0.1 ;
22+ cursor : move;
23+ stroke-dasharray : 5 ;
24+ stroke : grey;
25+ r : 10 ;
26+ }
27+
28+ .bottomright {
29+ cursor : move;
30+ }
31+ .topleft {
32+ cursor : move;
33+ }
34+ .topright {
35+ fill : # fff ;
36+ fill-opacity : 1 ;
37+ stroke-dasharray : 0 ;
38+ stroke : # E8336D ;
39+ r : 10 ;
40+ }
41+ .resizing {
42+ fill : blue;
43+ }
44+
45+ .moving {
46+ fill : transparent;
47+ }
48+
49+ # controls {
50+ position : absolute;
51+ top : 0 ;
52+ }
53+
54+ # controls input {
55+ width : 3em ;
56+ }
57+
58+ : root {
59+ --accent-color : # E8336D ;
60+ }
61+
62+ svg {
63+ font-family : 'Lato' ;
64+ width : 100% ;
65+ height : 100% ;
66+ }
67+
68+ .annotation path {
69+ stroke : var (--accent-color );
70+ fill : none;
71+ }
72+
73+ text .title {
74+ font-size : 1.2em ;
75+ font-weight : bold;
76+ }
77+
78+ .img-overlay-wrap {
79+ position : relative;
80+ display : inline-block; /* <= shrinks container to image size */
81+ transition : transform 150ms ease-in-out;
82+ }
83+
84+ .img-overlay-wrap img { /* <= optional, for responsiveness */
85+ display : block;
86+ max-width : 75% ;
87+ height : auto;
88+ }
89+
90+ .img-overlay-wrap svg {
91+ position : absolute;
92+ top : 0 ;
93+ left : 0 ;
94+ }
95+ </ style >
96+ </ head >
97+ < body >
98+ < div class ="img-overlay-wrap ">
99+ < image id ="documentPicture " src ="./example.jpg "> </ image >
100+ < div id ="svgWrapper ">
101+ < svg > </ svg >
102+ </ div >
103+ </ div >
104+ < fieldset id ="controls ">
105+ < label > x:< input type ="text " id ="x "> </ label >
106+ < label > y:< input type ="text " id ="y "> </ label >
107+ < label > width:< input type ="text " id ="width "> </ label >
108+ < label > height:< input type ="text " id ="height "> </ label >
109+ </ fieldset >
110+
111+ < script src ="https://d3js.org/d3.v4.js "> </ script >
112+ < script >
113+
114+ data = [
115+ { id : 1 , x : - 75 , y : - 75 , width : 150 , height : 150 }
116+ ] ;
117+
118+ var MAP_HEIGHT = 2500 ;
119+ var MAP_WIDTH = MAP_HEIGHT * Math . sqrt ( 2 ) ;
120+
121+ var MAX_TRANSLATE_X = MAP_WIDTH / 2 ;
122+ var MIN_TRANSLATE_X = - MAX_TRANSLATE_X ;
123+
124+ var MAX_TRANSLATE_Y = MAP_HEIGHT / 2 ;
125+ var MIN_TRANSLATE_Y = - MAX_TRANSLATE_Y ;
126+
127+ var MIN_RECT_WIDTH = 5 ;
128+ var MIN_RECT_HEIGHT = 5 ;
129+
130+ var HANDLE_R = 5 ;
131+ var HANDLE_R_ACTIVE = 12 ;
132+
133+ var wrapper = document . getElementById ( "svgWrapper" ) ;
134+
135+ var height = wrapper . offsetHeight ;
136+ var width = wrapper . offsetWidth ;
137+
138+ var
139+ inpX = document . getElementById ( "x" ) ,
140+ inpY = document . getElementById ( "y" ) ,
141+ inpWidth = document . getElementById ( "width" ) ,
142+ inpHeight = document . getElementById ( "height" ) ;
143+
144+ var svg = d3 . select ( "svg" ) ;
145+
146+ // for the background
147+ svg . append ( "rect" )
148+ . style ( "fill" , "transparent" )
149+ . attr ( "width" , "100%" )
150+ . attr ( "height" , "100%" ) ;
151+
152+ var g = svg . append ( "g" ) ;
153+
154+ g . append ( "rect" )
155+ . style ( "fill" , "transparent" )
156+ . attr ( "x" , MIN_TRANSLATE_X )
157+ . attr ( "y" , MIN_TRANSLATE_Y )
158+ . attr ( "width" , MAP_WIDTH )
159+ . attr ( "height" , MAP_HEIGHT ) ;
160+
161+ function resizerHover ( ) {
162+ var el = d3 . select ( this ) , isEntering = d3 . event . type === "mouseenter" ;
163+ el
164+ . classed ( "hovering" , isEntering )
165+ . attr (
166+ "r" ,
167+ isEntering || el . classed ( "resizing" ) ?
168+ HANDLE_R_ACTIVE : HANDLE_R
169+ ) ;
170+ }
171+
172+ function rectResizeStartEnd ( ) {
173+ var el = d3 . select ( this ) , isStarting = d3 . event . type === "start" ;
174+ d3 . select ( this )
175+ . classed ( "resizing" , isStarting )
176+ . attr (
177+ "r" ,
178+ isStarting || el . classed ( "hovering" ) ?
179+ HANDLE_R_ACTIVE : HANDLE_R
180+ ) ;
181+ }
182+
183+ function rectResizing ( d ) {
184+
185+ //document.querySelector("#deleteIcon").setAttribute("cx",d.width)
186+ var dragX = Math . max (
187+ Math . min ( d3 . event . x , MAX_TRANSLATE_X ) ,
188+ MIN_TRANSLATE_X
189+ ) ;
190+
191+ var dragY = Math . max (
192+ Math . min ( d3 . event . y , MAX_TRANSLATE_Y ) ,
193+ MIN_TRANSLATE_Y
194+ ) ;
195+
196+ if ( d3 . select ( this ) . classed ( "topleft" ) ) {
197+
198+ var newWidth = Math . max ( d . width + d . x - dragX , MIN_RECT_WIDTH ) ;
199+
200+ d . x += d . width - newWidth ;
201+ d . width = newWidth ;
202+
203+ var newHeight = Math . max ( d . height + d . y - dragY , MIN_RECT_HEIGHT ) ;
204+
205+ d . y += d . height - newHeight ;
206+ d . height = newHeight ;
207+
208+ } else {
209+
210+ d . width = Math . max ( dragX - d . x , MIN_RECT_WIDTH ) ;
211+ d . height = Math . max ( dragY - d . y , MIN_RECT_HEIGHT ) ;
212+
213+ }
214+
215+ update ( ) ;
216+ }
217+
218+ function rectMoveStartEnd ( d ) {
219+ d3 . select ( this ) . classed ( "moving" , d3 . event . type === "start" ) ;
220+ }
221+
222+ function rectMoving ( d ) {
223+
224+ var dragX = Math . max (
225+ Math . min ( d3 . event . x , MAX_TRANSLATE_X - d . width ) ,
226+ MIN_TRANSLATE_X
227+ ) ;
228+
229+ var dragY = Math . max (
230+ Math . min ( d3 . event . y , MAX_TRANSLATE_Y - d . height ) ,
231+ MIN_TRANSLATE_Y
232+ ) ;
233+
234+ d . x = dragX ;
235+ d . y = dragY ;
236+
237+ update ( ) ;
238+ }
239+
240+ function update ( ) {
241+
242+ var rects = g . selectAll ( "g.rectangle" ) . data ( data , function ( d ) {
243+ return d ;
244+ } ) ;
245+
246+ rects . exit ( ) . remove ( ) ;
247+
248+ var newRects = rects . enter ( ) . append ( "g" ) . classed ( "rectangle" , true ) ;
249+
250+ newRects . append ( "rect" )
251+ . classed ( "bg" , true )
252+ . attr ( "fill" , "transparent" )
253+ . attr ( "stroke" , "#E8336D" )
254+ . attr ( "stroke-width" , 1 )
255+ . call ( d3 . drag ( )
256+ . container ( g . node ( ) )
257+ . on ( "start end" , rectMoveStartEnd )
258+ . on ( "drag" , rectMoving )
259+ ) ;
260+
261+ newRects . append ( "g" ) . classed ( "circles" , true ) . each ( function ( d ) {
262+ var circleG = d3 . select ( this ) ;
263+ var editCircle = circleG . append ( "circle" )
264+ . classed ( "topright" , true )
265+ . attr ( "id" , "deleteIcon" )
266+ . attr ( "cx" , d . width )
267+ . attr ( "cy" , 0 )
268+ . attr ( "r" , HANDLE_R )
269+ . on ( "mouseenter" , function ( d ) {
270+ g . select ( "circle.topright" ) . style ( 'fill' , '#E8336D' )
271+ g . selectAll ( "path" ) . each ( function ( d , i ) {
272+ d3 . select ( this ) . attr ( "stroke" , "white" ) ;
273+ } ) ;
274+ } )
275+ . on ( "mouseleave" , function ( d ) {
276+ g . select ( "circle.topright" ) . style ( 'fill' , '#fff' )
277+ g . selectAll ( "path" ) . each ( function ( d , i ) {
278+ d3 . select ( this ) . attr ( "stroke" , "#E8336D" ) ;
279+ } ) ;
280+ } )
281+ . on ( "click" , function ( d ) {
282+ alert ( "on click" + d . className ) ;
283+ } ) ;
284+
285+ circleG . append ( "circle" )
286+ . classed ( "topleft" , true )
287+ . style ( 'fill' , "grey" )
288+ . style ( 'fill-opacity' , '0.1' )
289+ . style ( 'cursor' , 'move' )
290+ . style ( 'stroke-dasharray' , '5' )
291+ . style ( 'stroke' , 'grey' )
292+ . style ( 'r' , 10 )
293+ . attr ( "r" , HANDLE_R )
294+ . on ( "mouseenter mouseleave" , resizerHover )
295+ . call ( d3 . drag ( )
296+ . container ( g . node ( ) )
297+ . subject ( function ( ) {
298+ return { x : d3 . event . x , y : d3 . event . y } ;
299+ } )
300+ . on ( "start end" , rectResizeStartEnd )
301+ . on ( "drag" , rectResizing )
302+ ) ;
303+
304+ circleG
305+ . append ( "circle" )
306+ . classed ( "bottomright" , true )
307+ . style ( 'fill' , "grey" )
308+ . style ( 'fill-opacity' , '0.1' )
309+ . style ( 'cursor' , 'move' )
310+ . style ( 'stroke-dasharray' , '5' )
311+ . style ( 'stroke' , 'grey' )
312+ . style ( 'r' , 10 )
313+ . attr ( "r" , HANDLE_R )
314+ . on ( "mouseenter mouseleave" , resizerHover )
315+ . call ( d3 . drag ( )
316+ . container ( g . node ( ) )
317+ . subject ( function ( ) {
318+ return { x : d3 . event . x , y : d3 . event . y } ;
319+ } )
320+ . on ( "start end" , rectResizeStartEnd )
321+ . on ( "drag" , rectResizing )
322+ ) ;
323+
324+ var editIcon = circleG . append ( "svg" ) . attr ( "x" , d . width ) . attr ( "y" , - 8 ) . classed ( "toprightsvg" , true ) ;
325+ editIcon . append ( "path" ) . attr ( "stroke" , "#E8336D" ) . attr ( "stroke-width" , "1.06" ) . attr ( "d" , "M16,16 L4,4" ) . attr ( "transform" , "scale(0.8)" ) ;
326+ editIcon . append ( "path" ) . attr ( "stroke" , "#E8336D" ) . attr ( "stroke-width" , "1.06" ) . attr ( "d" , "M16,4 L4,16" ) . attr ( "transform" , "scale(0.8)" ) ;
327+
328+ } ) ;
329+ var allRects = newRects . merge ( rects ) ;
330+
331+ allRects
332+ . attr ( "transform" , function ( d ) {
333+ return "translate(" + d . x + "," + d . y + ")" ;
334+ } ) ;
335+
336+ allRects
337+ . select ( "rect.bg" )
338+ . attr ( "height" , function ( d ) {
339+ return d . height ;
340+ } )
341+ . attr ( "width" , function ( d ) {
342+ return d . width ;
343+ } ) ;
344+
345+ allRects
346+ . select ( "circle.bottomright" )
347+ . attr ( "cx" , function ( d ) {
348+ return d . width ;
349+ } )
350+ . attr ( "cy" , function ( d ) {
351+ return d . height ;
352+ } ) ;
353+ allRects
354+ . select ( "circle.topright" )
355+ . attr ( "cx" , function ( d ) {
356+ return d . width ;
357+ } ) ;
358+ allRects
359+ . select ( "svg.toprightsvg" )
360+ . attr ( "x" , function ( d ) {
361+ return d . width - 8.1 ;
362+ } )
363+
364+ inpX . value = data [ 0 ] . x ;
365+ inpY . value = data [ 0 ] . y ;
366+ inpWidth . value = data [ 0 ] . width ;
367+ inpHeight . value = data [ 0 ] . height ;
368+ }
369+
370+ function controlChange ( ) {
371+ data [ 0 ] [ this . id ] = + this . value ;
372+ update ( ) ;
373+ }
374+
375+ [ inpX , inpY , inpWidth , inpHeight ] . forEach ( function ( e ) {
376+ e . addEventListener ( "change" , controlChange ) ;
377+ } ) ;
378+ update ( ) ;
379+
380+ </ script >
381+ </ body >
382+ </ html >
0 commit comments