├── .gitignore ├── README.md ├── css ├── base.css ├── demo1.css ├── demo2.css ├── demo3.css ├── demo4.css ├── demo5.css ├── demo6.css ├── demo7.css └── demo8.css ├── favicon.ico ├── img ├── 1.jpg ├── 10.jpg ├── 11.jpg ├── 12.jpg ├── 13.jpg ├── 14.jpg ├── 15.jpg ├── 16.jpg ├── 17.jpg ├── 18.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── index.html ├── index2.html ├── index3.html ├── index4.html ├── index5.html ├── index6.html ├── index7.html ├── index8.html ├── js ├── MathUtils.js ├── demo1 │ ├── draggableImage.js │ └── index.js ├── demo2 │ ├── draggableImage.js │ └── index.js ├── demo3 │ ├── draggableImage.js │ └── index.js ├── demo4 │ ├── draggableImage.js │ └── index.js ├── demo5 │ ├── draggableImage.js │ └── index.js ├── demo6 │ ├── draggableImage.js │ └── index.js ├── demo7 │ ├── draggableImage.js │ └── index.js └── demo8 │ ├── draggableImage.js │ └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | dist/ 3 | node_modules/ 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Image Dragging Effects 2 | 3 | A set of playful effects for dragging images. 4 | 5 | ![Image Dragging Effects](https://tympanus.net/codrops/wp-content/uploads/2020/02/ImageDragging_featured.jpg) 6 | 7 | [Article on Codrops](https://tympanus.net/codrops/?p=47024) 8 | 9 | [Demo](http://tympanus.net/Development/ImageDraggingEffects/) 10 | 11 | 12 | ## Installation 13 | 14 | Install dependencies: 15 | 16 | ``` 17 | npm install 18 | ``` 19 | 20 | Compile the code for development and start a local server: 21 | 22 | ``` 23 | npm start 24 | ``` 25 | 26 | Create the build: 27 | 28 | ``` 29 | npm run build 30 | ``` 31 | 32 | ## Credits 33 | 34 | - [Draggabilly](https://draggabilly.desandro.com/) by Dave DeSandro 35 | - [imagesLoaded](https://imagesloaded.desandro.com/) by Dave DeSandro 36 | - [GSAP](https://greensock.com/) by Greensock 37 | - Images from [Unsplash.com](https://unsplash.com/) 38 | 39 | 40 | ## License 41 | 42 | This resource can be used freely if integrated or build upon in personal or commercial projects such as websites, web apps and web templates intended for sale. It is not allowed to take the resource "as-is" and sell it, redistribute, re-publish it, or sell "pluginized" versions of it. Free plugins built using this resource should have a visible mention and link to the original work. Always consider the licenses of all included libraries, scripts and images used. 43 | 44 | ## Misc 45 | 46 | Follow Codrops: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [Google+](https://plus.google.com/101095823814290637419), [GitHub](https://github.com/codrops), [Pinterest](http://www.pinterest.com/codrops/), [Instagram](https://www.instagram.com/codropsss/) 47 | 48 | [© Codrops 2020](http://www.codrops.com) 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 14px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #000; 14 | --color-bg: #85827a; 15 | --color-link: #594343; 16 | --color-link-hover: #000; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | --font-main: Geneva, Tahoma, Verdana, sans-serif; 20 | --font-alt: bigmoore, serif; 21 | --font-weight-alt: 400; 22 | --color-title: inherit; 23 | font-family: var(--font-main); 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | line-height: 1; 27 | } 28 | 29 | .demo-1 { 30 | --color-title: #fff; 31 | } 32 | 33 | .demo-2 { 34 | --color-link: #fff; 35 | --color-bg: #a1e0e7; 36 | --font-alt: meno-banner, serif; 37 | } 38 | 39 | .demo-3 { 40 | --color-text: #000; 41 | --color-link: #fff; 42 | --color-bg: #d0c6ad; 43 | --font-alt: freight-big-pro, serif; 44 | } 45 | 46 | .demo-4 { 47 | --color-link: #eaeaef; 48 | --color-bg: #0859ca; 49 | --font-alt: bely-display, sans-serif; 50 | --color-title: #eaeaef; 51 | } 52 | 53 | .demo-5 { 54 | --color-link: #dc4823; 55 | --color-bg: #eceae9; 56 | --font-alt: louvette-display, serif; 57 | font-family: 'Barlow', sans-serif; 58 | text-transform: uppercase; 59 | } 60 | 61 | .demo-6 { 62 | --color-text: #fff; 63 | --color-link: #a17d66; 64 | --color-bg: #dacca9; 65 | --font-alt: bigmoore, serif; 66 | } 67 | 68 | .demo-7 { 69 | --color-link: #343129; 70 | --color-bg: #77705e; 71 | --font-alt: meno-banner, serif; 72 | --color-text: #e6ae4d; 73 | } 74 | 75 | .demo-8 { 76 | --color-text: #000; 77 | --color-link: #7e0c0c; 78 | --color-bg: #bc3d3d; 79 | --font-alt: freight-big-pro, serif; 80 | --color-title: #fff; 81 | } 82 | 83 | /* Page Loader */ 84 | .js .loading::before { 85 | content: ''; 86 | position: fixed; 87 | z-index: 100000; 88 | top: 0; 89 | left: 0; 90 | width: 100%; 91 | height: 100%; 92 | background: var(--color-bg); 93 | } 94 | 95 | .js .loading::after { 96 | content: ''; 97 | position: fixed; 98 | z-index: 100000; 99 | top: 50%; 100 | left: 50%; 101 | width: 60px; 102 | height: 60px; 103 | margin: -30px 0 0 -30px; 104 | pointer-events: none; 105 | border-radius: 50%; 106 | opacity: 0.4; 107 | background: var(--color-link); 108 | animation: loaderAnim 0.7s linear infinite alternate forwards; 109 | } 110 | 111 | @keyframes loaderAnim { 112 | to { 113 | opacity: 1; 114 | transform: scale3d(0.5,0.5,1); 115 | } 116 | } 117 | 118 | a { 119 | text-decoration: none; 120 | color: var(--color-link); 121 | outline: none; 122 | } 123 | 124 | a:hover, 125 | a:focus { 126 | color: var(--color-link-hover); 127 | outline: none; 128 | } 129 | 130 | .frame { 131 | padding: 3rem 5vw; 132 | text-align: center; 133 | position: relative; 134 | z-index: 1000; 135 | } 136 | 137 | .frame__title { 138 | font-size: 1rem; 139 | margin: 0 0 1rem; 140 | font-weight: inherit; 141 | } 142 | 143 | .frame__links { 144 | display: block; 145 | } 146 | 147 | .frame__links a:not(:last-child), 148 | .frame__demos a:not(:last-child) { 149 | margin: 0 1rem 0.35rem 0; 150 | } 151 | 152 | .frame__demos { 153 | margin: 1rem 0; 154 | } 155 | 156 | .frame__demo--current, 157 | .frame__demo--current:hover { 158 | color: var(--color-text); 159 | } 160 | 161 | .frame__initials { 162 | font-family: var(--font-alt); 163 | font-weight: var(--font-weight-alt); 164 | font-size: 2rem; 165 | pointer-events: none; 166 | line-height: 14px; 167 | } 168 | 169 | .content { 170 | display: flex; 171 | position: relative; 172 | flex-direction: column; 173 | width: 100vw; 174 | height: calc(100vh - 13rem); 175 | position: relative; 176 | justify-content: flex-start; 177 | align-items: center; 178 | } 179 | 180 | .content__title { 181 | font-size: 10vw; 182 | font-family: var(--font-alt); 183 | font-weight: var(--font-weight-alt); 184 | margin: 0; 185 | position: relative; 186 | pointer-events: none; 187 | z-index: 1000; 188 | color: var(--color-title); 189 | text-align: center; 190 | } 191 | 192 | .content__title--multiline { 193 | font-size: 8.5vw; 194 | line-height: 1.3; 195 | text-transform: none; 196 | } 197 | 198 | .content__title-row { 199 | display: block; 200 | } 201 | 202 | .content__title-row:first-child { 203 | margin-right: 22vw; 204 | } 205 | 206 | .content__title--up { 207 | text-transform: uppercase; 208 | } 209 | 210 | .month { 211 | font-weight: 700; 212 | font-size: 4vw; 213 | } 214 | 215 | .year { 216 | font-size: 10vw; 217 | } 218 | 219 | .content__drag-area { 220 | position: absolute; 221 | width: 100%; 222 | height: 100%; 223 | display: flex; 224 | align-items: center; 225 | justify-content: center; 226 | } 227 | 228 | .img-drag, 229 | .img-wrap { 230 | flex: none; 231 | } 232 | 233 | @media screen and (max-width: 42em) { 234 | .content .img-drag, 235 | .content .img-wrap { 236 | margin: 1rem; 237 | } 238 | } 239 | 240 | @media screen and (min-width: 53em) { 241 | .frame { 242 | position: fixed; 243 | text-align: left; 244 | z-index: 10000; 245 | top: 0; 246 | left: 0; 247 | display: grid; 248 | align-content: space-between; 249 | width: 100%; 250 | max-width: none; 251 | height: 100vh; 252 | padding: 2.5rem 4rem; 253 | pointer-events: none; 254 | grid-template-columns: 40% 20% 40%; 255 | grid-template-rows: auto auto auto; 256 | grid-template-areas: 'title initials demos' 257 | '... ... ...' 258 | '... ... info'; 259 | } 260 | .frame__title-wrap { 261 | grid-area: title; 262 | } 263 | .frame__title { 264 | margin: 0 0 3rem 0; 265 | } 266 | .frame__initials { 267 | grid-area: initials; 268 | margin: 0; 269 | justify-self: center; 270 | align-self: start; 271 | } 272 | .frame__demos { 273 | margin: 0; 274 | grid-area: demos; 275 | justify-self: end; 276 | align-self: start; 277 | } 278 | .frame__links { 279 | grid-area: links; 280 | padding: 0; 281 | justify-self: end; 282 | display: flex; 283 | flex-direction: column; 284 | align-items: flex-start; 285 | } 286 | .frame__info { 287 | grid-area: info; 288 | margin: 0; 289 | justify-self: end; 290 | } 291 | .frame a { 292 | pointer-events: auto; 293 | } 294 | .content { 295 | height: 100vh; 296 | justify-content: center; 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /css/demo1.css: -------------------------------------------------------------------------------- 1 | .img-drag { 2 | position: relative; 3 | overflow: hidden; 4 | width: 260px; 5 | height: 330px; 6 | max-width: 100%; 7 | cursor: grab; 8 | margin: 4rem; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | } 13 | 14 | .img-drag:nth-child(1) { 15 | margin-top: 20vh; 16 | } 17 | 18 | .img-drag:nth-child(2) { 19 | margin-top: 0; 20 | width: 210px; 21 | height: 290px; 22 | } 23 | 24 | .img-drag__inner { 25 | flex: none; 26 | --overflow: 70px; 27 | position: relative; 28 | background-size: cover; 29 | background-position: 50% 50%; 30 | width: calc(100% + var(--overflow)); 31 | height: calc(100% + var(--overflow)); 32 | } -------------------------------------------------------------------------------- /css/demo2.css: -------------------------------------------------------------------------------- 1 | .img-drag { 2 | position: relative; 3 | overflow: hidden; 4 | width: 290px; 5 | height: 400px; 6 | max-width: 100%; 7 | cursor: grab; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | } 12 | 13 | .img-drag__inner { 14 | flex: none; 15 | --overflow: 100px; 16 | position: relative; 17 | background-size: cover; 18 | background-position: 50% 50%; 19 | width: calc(100% + var(--overflow)); 20 | height: calc(100% + var(--overflow)); 21 | will-change: transform; 22 | } -------------------------------------------------------------------------------- /css/demo3.css: -------------------------------------------------------------------------------- 1 | .img-drag { 2 | position: relative; 3 | background-size: cover; 4 | width: 220px; 5 | height: 300px; 6 | max-width: 100%; 7 | cursor: grab; 8 | margin: 4rem; 9 | will-change: transform; 10 | } 11 | 12 | .img-drag:nth-child(1) { 13 | margin-top: 30vh; 14 | } 15 | 16 | .img-drag:nth-child(2) { 17 | margin-top: 0; 18 | } -------------------------------------------------------------------------------- /css/demo4.css: -------------------------------------------------------------------------------- 1 | .img-wrap { 2 | position: relative; 3 | pointer-events: none; 4 | width: 350px; 5 | height: 450px; 6 | max-width: 100%; 7 | } 8 | 9 | .img-drag, 10 | .img-trail { 11 | cursor: grab; 12 | background-size: cover; 13 | background-position: 50% 50%; 14 | position: relative; 15 | width: 100%; 16 | height: 100%; 17 | pointer-events: auto; 18 | } 19 | 20 | .img-trail { 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | opacity: 0.8; 25 | } 26 | 27 | .content__title { 28 | font-size: 8vw; 29 | mix-blend-mode: exclusion; 30 | } 31 | -------------------------------------------------------------------------------- /css/demo5.css: -------------------------------------------------------------------------------- 1 | .img-wrap { 2 | --img-width: 210px; 3 | --img-height: 300px; 4 | width: var(--img-width); 5 | height: var(--img-height); 6 | position: relative; 7 | pointer-events: none; 8 | 9 | } 10 | 11 | .img-drag { 12 | position: relative; 13 | width: 100%; 14 | height: 100%; 15 | overflow: hidden; 16 | pointer-events: auto; 17 | cursor: grab; 18 | will-change: transform; 19 | } 20 | 21 | .img-drag__inner { 22 | background-size: cover; 23 | background-position: 50% 50%; 24 | width: 100%; 25 | height: 100%; 26 | } 27 | 28 | .img-trail { 29 | width: 100%; 30 | height: 100%; 31 | position: absolute; 32 | top: 0; 33 | left: 0; 34 | opacity: 0; 35 | will-change: transform; 36 | } -------------------------------------------------------------------------------- /css/demo6.css: -------------------------------------------------------------------------------- 1 | .img-wrap { 2 | --img-width: 200px; 3 | --img-height: 270px; 4 | width: var(--img-width); 5 | height: var(--img-height); 6 | position: relative; 7 | pointer-events: none; 8 | margin: 4rem; 9 | } 10 | 11 | .img-wrap:nth-child(1) { 12 | margin-top: 30vh; 13 | } 14 | 15 | .img-wrap:nth-child(2) { 16 | margin-top: 0; 17 | } 18 | 19 | .img-drag { 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | overflow: hidden; 24 | opacity: 1; 25 | pointer-events: auto; 26 | cursor: grab; 27 | } 28 | 29 | .img-drag__inner { 30 | background-size: cover; 31 | background-position: 50% 50%; 32 | width: 100%; 33 | height: 100%; 34 | } 35 | 36 | .img-trail { 37 | width: var(--img-width); 38 | height: var(--img-height); 39 | position: absolute; 40 | top: 0; 41 | left: 0; 42 | opacity: 0; 43 | mix-blend-mode: color-dodge; 44 | } 45 | 46 | .content__title { 47 | mix-blend-mode: difference; 48 | } 49 | -------------------------------------------------------------------------------- /css/demo7.css: -------------------------------------------------------------------------------- 1 | .img-drag { 2 | position: relative; 3 | max-width: 100%; 4 | display: flex; 5 | flex-wrap: wrap; 6 | cursor: grab; 7 | margin: 3rem; 8 | } 9 | 10 | .img-drag:nth-child(1) { 11 | margin-top: 20vh; 12 | } 13 | 14 | .img-drag:nth-child(2) { 15 | margin-top: 0; 16 | } 17 | 18 | .img-drag svg { 19 | display: block; 20 | } 21 | -------------------------------------------------------------------------------- /css/demo8.css: -------------------------------------------------------------------------------- 1 | .img-wrap { 2 | width: 180px; 3 | height: 250px; 4 | max-width: 100%; 5 | position: relative; 6 | pointer-events: none; 7 | } 8 | 9 | .img-drag { 10 | cursor: grab; 11 | } 12 | 13 | .img-drag { 14 | background-size: cover; 15 | background-position: 50% 50%; 16 | position: relative; 17 | width: 100%; 18 | height: 100%; 19 | pointer-events: auto; 20 | will-change: transform; 21 | } 22 | 23 | .img-trail { 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | opacity: 0.8; 28 | will-change: transform; 29 | } 30 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/favicon.ico -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/1.jpg -------------------------------------------------------------------------------- /img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/10.jpg -------------------------------------------------------------------------------- /img/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/11.jpg -------------------------------------------------------------------------------- /img/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/12.jpg -------------------------------------------------------------------------------- /img/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/13.jpg -------------------------------------------------------------------------------- /img/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/14.jpg -------------------------------------------------------------------------------- /img/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/15.jpg -------------------------------------------------------------------------------- /img/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/16.jpg -------------------------------------------------------------------------------- /img/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/17.jpg -------------------------------------------------------------------------------- /img/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/18.jpg -------------------------------------------------------------------------------- /img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/2.jpg -------------------------------------------------------------------------------- /img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/3.jpg -------------------------------------------------------------------------------- /img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/4.jpg -------------------------------------------------------------------------------- /img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/5.jpg -------------------------------------------------------------------------------- /img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/6.jpg -------------------------------------------------------------------------------- /img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/7.jpg -------------------------------------------------------------------------------- /img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/8.jpg -------------------------------------------------------------------------------- /img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/ImageDraggingEffects/a1faf9fcb5975bf356501236ae987bf89486b412/img/9.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 1 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

KH

28 |

Drag the images

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |

Kai & Harper

50 |
51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 2 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

KA

28 |

Drag the images

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |

Katharina

47 |
48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /index3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 3 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |

Image Dragging Effects

22 | 27 |
28 |

MP

29 |

Drag the images (fast)

30 |
31 | 1 32 | 2 33 | 3 34 | 4 35 | 5 36 | 6 37 | 7 38 | 8 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |

Markopoulos

47 |
48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /index4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 4 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

TD

28 |

Drag the images (fast)

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |

Tyler Dice

47 |
48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /index5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 5 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Image Dragging Effects

22 | 27 |
28 |

2020

29 |

Drag the images (fast)

30 |
31 | 1 32 | 2 33 | 3 34 | 4 35 | 5 36 | 6 37 | 7 38 | 8 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |

50 | Italy 51 | Art Fair @ Savona 52 | Apr — 2020 53 |

54 |
55 |
56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /index6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 6 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

ML

28 |

Drag the images (fast)

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
Mayra & Louise
54 |
55 |
56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /index7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 7 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

KH

28 |

Drag the images (fast)

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 |
69 |

Genevieve

70 |
71 |
72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /index8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Image Dragging Effects | Demo 8 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |

Image Dragging Effects

21 | 26 |
27 |

AG

28 |

Drag the images

29 |
30 | 1 31 | 2 32 | 3 33 | 4 34 | 5 35 | 6 36 | 7 37 | 8 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |

Antonella Gallo

53 |
54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /js/MathUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MathUtils.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | 12 | // Map number x from range [a, b] to [c, d] 13 | const map = (x, a, b, c, d) => (x - a) * (d - c) / (b - a) + c; 14 | 15 | // Linear interpolation 16 | const lerp = (a, b, n) => (1 - n) * a + n * b; 17 | 18 | // Clamp val within min and max 19 | const clamp = (val, min, max) => Math.max(Math.min(val, max), min); 20 | 21 | // Random float 22 | const getRandomFloat = (min, max) => (Math.random() * (max - min) + min).toFixed(2); 23 | 24 | // distance between two points 25 | const distance = (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1); 26 | 27 | export { map, lerp, clamp, getRandomFloat, distance }; 28 | -------------------------------------------------------------------------------- /js/demo1/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | 14 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 15 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 16 | 17 | // Image that gets dragged gets this zIndex value which then gets incremented 18 | let zIndex = 1; 19 | 20 | class DraggableImage { 21 | constructor(el) { 22 | // image container (the draggable element) 23 | this.DOM = {el: el}; 24 | // image element 25 | this.DOM.innerEl = this.DOM.el.querySelector('.img-drag__inner'); 26 | // css --overflow value 27 | // this will define how much the innerEl can move inside the parent without getting cut off 28 | this.overflowVal = parseInt(getComputedStyle(this.DOM.innerEl).getPropertyValue('--overflow'),10); 29 | // Dragging position 30 | this.draggingPos = { 31 | previous: {x: 0, y: 0}, 32 | current: {x: 0, y: 0}, 33 | amt: 0.1 34 | }; 35 | // Inner Element scale 36 | this.innerScale = { 37 | previous: 1, 38 | current: 1, 39 | amt: 0.15 40 | }; 41 | // outer Element scale 42 | this.outerScale = { 43 | previous: 1, 44 | current: 1, 45 | amt: 0.15 46 | }; 47 | // Initialize Draggabilly 48 | this.draggie = new Draggabilly(this.DOM.el); 49 | // Init/Bind events 50 | this.initEvents(); 51 | // Loop 52 | requestAnimationFrame(() => this.render()); 53 | } 54 | initEvents() { 55 | this.onDragStart = () => { 56 | // Reset 57 | this.draggingPos.previous = {x: 0, y: 0}; 58 | }; 59 | 60 | this.onDragMove = (event, pointer, moveVector) => { 61 | this.draggingPos.current = moveVector; 62 | }; 63 | 64 | this.onPointerDown = () => { 65 | this.DOM.el.style.zIndex = zIndex++; 66 | this.innerScale.current = 1.3; 67 | this.outerScale.current = 0.8; 68 | document.body.style.cursor = 'grabbing'; 69 | this.DOM.el.style.cursor = 'grabbing'; 70 | }; 71 | 72 | this.onPointerUp = () => { 73 | // Reset 74 | this.innerScale.current = 1; 75 | this.outerScale.current = 1; 76 | document.body.style.cursor = 'default'; 77 | this.DOM.el.style.cursor = 'grab'; 78 | }; 79 | 80 | this.draggie.on('pointerDown', this.onPointerDown); 81 | this.draggie.on('dragStart', this.onDragStart); 82 | this.draggie.on('dragMove', this.onDragMove); 83 | this.draggie.on('pointerUp', this.onPointerUp); 84 | } 85 | render() { 86 | this.draggingPos.previous.x = lerp(this.draggingPos.previous.x, this.draggingPos.current.x, this.draggingPos.amt); 87 | this.draggingPos.previous.y = lerp(this.draggingPos.previous.y, this.draggingPos.current.y, this.draggingPos.amt); 88 | this.innerScale.previous = lerp(this.innerScale.previous, this.innerScale.current, this.innerScale.amt); 89 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 90 | 91 | this.layout(); 92 | // loop 93 | requestAnimationFrame(() => this.render()); 94 | } 95 | layout() { 96 | // The inner element transform 97 | this.DOM.innerEl.style.transform = `translate3d(${this.getInnerTranslation('x')}px,${this.getInnerTranslation('y')}px,0) scale3d(${this.innerScale.previous}, ${this.innerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 98 | // The draggable element transform 99 | this.DOM.el.style.transform = `translate3d(${(this.draggingPos.previous.x - this.draggingPos.current.x).toFixed(2)}px,${(this.draggingPos.previous.y - this.draggingPos.current.y).toFixed(2)}px,0) scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 100 | } 101 | // Calculate how much to translate the inner element 102 | getInnerTranslation(axis) { 103 | const distance = this.draggingPos.previous[axis] - this.draggingPos.current[axis]; 104 | const boundaries = { 105 | distance: {min: 0, max: 400}, 106 | translation: {min: 0, max: this.overflowVal/2*this.innerScale.previous/this.outerScale.previous} 107 | }; 108 | 109 | let translationVal = map(Math.abs(distance), boundaries.distance.min, boundaries.distance.max, boundaries.translation.min, boundaries.translation.max); 110 | translationVal = clamp(translationVal, boundaries.translation.min, boundaries.translation.max); 111 | 112 | return distance > 0 ? translationVal.toFixed(2) : -1*translationVal.toFixed(2); 113 | } 114 | } 115 | 116 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo1/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag__inner'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'hsm8jwd' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-drag')].forEach((draggableEl) => new DraggableImage(draggableEl)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | -------------------------------------------------------------------------------- /js/demo2/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | import { gsap, Power2 } from 'gsap'; 14 | 15 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 16 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 17 | 18 | // Image that gets dragged gets this zIndex value which then gets incremented 19 | let zIndex = 1; 20 | 21 | class DraggableImage { 22 | constructor(el) { 23 | // image container (the draggable element) 24 | this.DOM = {el: el}; 25 | // image element 26 | this.DOM.innerEl = this.DOM.el.querySelector('.img-drag__inner'); 27 | // css --overflow value 28 | // this will define how much the innerEl can move inside the parent without getting cut off 29 | this.overflowVal = parseInt(getComputedStyle(this.DOM.innerEl).getPropertyValue('--overflow'),10); 30 | // Dragging position 31 | this.draggingPos = { 32 | previous: {x: 0, y: 0}, 33 | current: {x: 0, y: 0}, 34 | amt: 0.1 35 | }; 36 | // Inner Element scale 37 | this.innerScale = { 38 | previous: 1, 39 | current: 1, 40 | amt: 0.15 41 | }; 42 | // outer Element scale 43 | this.outerScale = { 44 | previous: 1, 45 | current: 1, 46 | amt: 0.15 47 | }; 48 | // Initialize Draggabilly 49 | this.draggie = new Draggabilly(this.DOM.el); 50 | // Init/Bind events 51 | this.initEvents(); 52 | // Loop 53 | requestAnimationFrame(() => this.render()); 54 | } 55 | initEvents() { 56 | this.onDragStart = () => { 57 | // Reset 58 | this.draggingPos.previous = {x: 0, y: 0}; 59 | }; 60 | 61 | this.onDragMove = (event, pointer, moveVector) => { 62 | this.draggingPos.current = moveVector; 63 | }; 64 | 65 | this.onPointerDown = () => { 66 | this.DOM.el.style.zIndex = zIndex++; 67 | 68 | this.innerScale.current = 1; 69 | this.outerScale.current = 1.2; 70 | 71 | gsap.to(document.body, {duration: 0.5, ease: Power2.easeOut, backgroundColor: '#588186'}); 72 | 73 | document.body.style.cursor = 'grabbing'; 74 | this.DOM.el.style.cursor = 'grabbing'; 75 | }; 76 | 77 | this.onPointerUp = () => { 78 | // Reset 79 | this.innerScale.current = 1; 80 | this.outerScale.current = 1; 81 | 82 | gsap.to(document.body, {duration: 0.5, ease: Power2.easeOut, backgroundColor: '#a1e0e7'}); 83 | 84 | document.body.style.cursor = 'default'; 85 | this.DOM.el.style.cursor = 'grab'; 86 | }; 87 | 88 | this.onMouseEnter = () => { 89 | if ( this.DOM.el.classList.contains('is-dragging') ) return; 90 | this.innerScale.current = 1.2; 91 | this.outerScale.current = 1.1; 92 | }; 93 | 94 | this.onMouseLeave = () => { 95 | if ( this.DOM.el.classList.contains('is-dragging') ) return; 96 | // Reset 97 | this.innerScale.current = 1; 98 | this.outerScale.current = 1; 99 | }; 100 | 101 | this.draggie.on('pointerDown', this.onPointerDown); 102 | this.draggie.on('dragStart', this.onDragStart); 103 | this.draggie.on('dragMove', this.onDragMove); 104 | this.draggie.on('pointerUp', this.onPointerUp); 105 | this.DOM.el.addEventListener('mouseenter', this.onMouseEnter); 106 | this.DOM.el.addEventListener('mouseleave', this.onMouseLeave); 107 | } 108 | render() { 109 | this.draggingPos.previous.x = lerp(this.draggingPos.previous.x, this.draggingPos.current.x, this.draggingPos.amt); 110 | this.draggingPos.previous.y = lerp(this.draggingPos.previous.y, this.draggingPos.current.y, this.draggingPos.amt); 111 | this.innerScale.previous = lerp(this.innerScale.previous, this.innerScale.current, this.innerScale.amt); 112 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 113 | 114 | this.layout(); 115 | // loop 116 | requestAnimationFrame(() => this.render()); 117 | } 118 | layout() { 119 | // The inner element transform 120 | this.DOM.innerEl.style.transform = `translate3d(${this.getInnerTranslation('x')}px,${this.getInnerTranslation('y')}px,0) scale3d(${this.innerScale.previous}, ${this.innerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 121 | // The draggable element transform 122 | this.DOM.el.style.transform = `translate3d(${(this.draggingPos.previous.x - this.draggingPos.current.x).toFixed(2)}px,${(this.draggingPos.previous.y - this.draggingPos.current.y).toFixed(2)}px,0) scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 123 | } 124 | // Calculate how much to translate the inner element 125 | getInnerTranslation(axis) { 126 | const distance = this.draggingPos.previous[axis] - this.draggingPos.current[axis]; 127 | const boundaries = { 128 | distance: {min: 0, max: 400}, 129 | translation: {min: 0, max: this.overflowVal/2*this.innerScale.previous/this.outerScale.previous} 130 | }; 131 | 132 | let translationVal = map(Math.abs(distance), boundaries.distance.min, boundaries.distance.max, boundaries.translation.min, boundaries.translation.max); 133 | translationVal = clamp(translationVal, boundaries.translation.min, boundaries.translation.max); 134 | 135 | return distance > 0 ? translationVal : -1*translationVal; 136 | } 137 | } 138 | 139 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo2/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag__inner'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'mto6dlj' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-drag')].forEach((draggableEl) => new DraggableImage(draggableEl)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | -------------------------------------------------------------------------------- /js/demo3/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp, getRandomFloat, distance } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | 14 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 15 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 16 | 17 | // Image that gets dragged gets this zIndex value which then gets incremented 18 | let zIndex = 1; 19 | 20 | class DraggableImage { 21 | constructor(el) { 22 | // image container (the draggable element) 23 | this.DOM = {el: el}; 24 | this.boundingRect = this.DOM.el.getBoundingClientRect(); 25 | // Dragging position 26 | this.draggingPos = { 27 | previous: {x: 0, y: 0}, 28 | current: {x: 0, y: 0}, 29 | amt: 0.13 30 | }; 31 | this.pointerOffset = {x: 0,y: 0}; 32 | // Initialize Draggabilly 33 | this.draggie = new Draggabilly(this.DOM.el); 34 | // Init/Bind events 35 | this.initEvents(); 36 | // Loop 37 | requestAnimationFrame(() => this.render()); 38 | } 39 | initEvents() { 40 | this.onDragStart = () => { 41 | this.DOM.el.style.zIndex = zIndex++; 42 | // Reset 43 | this.draggingPos.previous = {x: 0, y: 0}; 44 | }; 45 | 46 | this.onDragMove = (event, pointer, moveVector) => { 47 | this.draggingPos.current = moveVector; 48 | }; 49 | 50 | this.onPointerDown = (event, pointer) => { 51 | this.pointerOffset = { 52 | x: pointer.offsetX, 53 | y: pointer.offsetY 54 | }; 55 | document.body.style.cursor = 'grabbing'; 56 | this.DOM.el.style.cursor = 'grabbing'; 57 | }; 58 | 59 | this.onPointerUp = () => { 60 | document.body.style.cursor = 'default'; 61 | this.DOM.el.style.cursor = 'grab'; 62 | }; 63 | 64 | this.onResize = () => { 65 | this.boundingRect = this.DOM.el.getBoundingClientRect(); 66 | }; 67 | 68 | this.draggie.on('dragStart', this.onDragStart); 69 | this.draggie.on('dragMove', this.onDragMove); 70 | this.draggie.on('pointerDown', this.onPointerDown); 71 | this.draggie.on('pointerUp', this.onPointerUp); 72 | window.addEventListener('resize', this.onResize); 73 | } 74 | render() { 75 | this.draggingPos.previous.x = lerp(this.draggingPos.previous.x, this.draggingPos.current.x, this.draggingPos.amt); 76 | this.draggingPos.previous.y = lerp(this.draggingPos.previous.y, this.draggingPos.current.y, this.draggingPos.amt); 77 | 78 | this.layout(); 79 | // loop 80 | requestAnimationFrame(() => this.render()); 81 | } 82 | layout() { 83 | const draggingDistance = { 84 | x: (this.draggingPos.previous.x - this.draggingPos.current.x).toFixed(2), 85 | y: (this.draggingPos.previous.y - this.draggingPos.current.y).toFixed(2), 86 | total: distance(this.draggingPos.previous.x, this.draggingPos.previous.y, this.draggingPos.current.x, this.draggingPos.current.y) 87 | }; 88 | const blurVal = clamp(map(draggingDistance.total, 0, 400, 0, 10), 0, 10); 89 | const brightnessVal = clamp(map(draggingDistance.total, 0, 400, 1, 1.5), 1, 1.5); 90 | 91 | // The draggable element transform 92 | const skewDirection = { 93 | vertical: this.pointerOffset.y > this.boundingRect.height/2 ? -1 : 1, 94 | horizontal: this.pointerOffset.x > this.boundingRect.width/2 ? -1 : 1 95 | }; 96 | this.DOM.el.style.transform = `translate3d(${draggingDistance.x}px,${draggingDistance.y}px,0) 97 | scale(${clamp(map(draggingDistance.total, 0, 800, 1, 0.6), 0.6, 1)}) 98 | skewX(${skewDirection.vertical*map(draggingDistance.x, 0, 500, 0, 10)}deg) skewY(${skewDirection.horizontal*map(draggingDistance.y, 0, 500, 0, 10)}deg)`; 99 | 100 | // Filters 101 | this.DOM.el.style.filter = `blur(${blurVal.toFixed(2)}px) brightness(${brightnessVal.toFixed(2)})`; 102 | } 103 | } 104 | 105 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo3/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'wwn4ioo' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-drag')].forEach((draggableEl) => new DraggableImage(draggableEl)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | -------------------------------------------------------------------------------- /js/demo4/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp, distance } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | 14 | // Image that gets dragged gets this zIndex value which then gets incremented 15 | let zIndex = 1; 16 | 17 | class DraggableImage { 18 | constructor(el) { 19 | // Image container 20 | this.DOM = {el: el}; 21 | // The draggable element 22 | this.DOM.draggable = this.DOM.el.querySelector('.img-drag'); 23 | // Image trails 24 | this.trailsTotal = 5; 25 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 26 | const el = document.createElement('div'); 27 | el.className = 'img-trail'; 28 | el.style.backgroundImage = this.DOM.draggable.style.backgroundImage; 29 | this.DOM.el.insertBefore(el, this.DOM.el.firstChild); 30 | } 31 | this.DOM.trails = [...this.DOM.el.querySelectorAll('.img-trail')]; 32 | 33 | // Dragging position 34 | this.draggingPos = { 35 | previous: {x: 0, y: 0}, 36 | current: {x: 0, y: 0}, 37 | amt: 0.1 38 | }; 39 | // Trails translations 40 | this.trailsTranslation = [...new Array(this.trailsTotal)].map(() => ({ 41 | previous: {x: 0, y: 0}, 42 | current: {x: 0, y: 0}, 43 | amt: position => 0.15 + 0.05*position 44 | })); 45 | // Initialize Draggabilly 46 | this.draggie = new Draggabilly(this.DOM.draggable); 47 | // Init/Bind events 48 | this.initEvents(); 49 | // Loop 50 | requestAnimationFrame(() => this.render()); 51 | } 52 | initEvents() { 53 | this.onDragStart = () => { 54 | // Reset 55 | this.draggingPos.previous = {x: 0, y: 0}; 56 | }; 57 | 58 | this.onDragMove = (event, pointer, moveVector) => { 59 | this.draggingPos.current = moveVector; 60 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 61 | this.trailsTranslation[i].current = this.draggie.position; 62 | } 63 | }; 64 | 65 | this.onPointerDown = () => { 66 | this.DOM.el.style.zIndex = zIndex++; 67 | this.DOM.draggable.style.opacity = 0.8; 68 | document.body.style.cursor = 'grabbing'; 69 | this.DOM.draggable.style.cursor = 'grabbing'; 70 | }; 71 | 72 | this.onPointerUp = () => { 73 | this.DOM.draggable.style.opacity = 1; 74 | document.body.style.cursor = 'default'; 75 | this.DOM.draggable.style.cursor = 'grab'; 76 | }; 77 | 78 | this.draggie.on('pointerDown', this.onPointerDown); 79 | this.draggie.on('dragStart', this.onDragStart); 80 | this.draggie.on('dragMove', this.onDragMove); 81 | this.draggie.on('pointerUp', this.onPointerUp); 82 | } 83 | render() { 84 | this.draggingPos.previous.x = lerp(this.draggingPos.previous.x, this.draggingPos.current.x, this.draggingPos.amt); 85 | this.draggingPos.previous.y = lerp(this.draggingPos.previous.y, this.draggingPos.current.y, this.draggingPos.amt); 86 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 87 | this.trailsTranslation[i].previous.x = lerp(this.trailsTranslation[i].previous.x, this.trailsTranslation[i].current.x, this.trailsTranslation[i].amt(i)); 88 | this.trailsTranslation[i].previous.y = lerp(this.trailsTranslation[i].previous.y, this.trailsTranslation[i].current.y, this.trailsTranslation[i].amt(i)); 89 | } 90 | this.layout(); 91 | // loop 92 | requestAnimationFrame(() => this.render()); 93 | } 94 | layout() { 95 | const draggingDistance = distance(this.draggingPos.previous.x, this.draggingPos.previous.y, this.draggingPos.current.x, this.draggingPos.current.y); 96 | 97 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 98 | const brightnessVal = clamp(map(draggingDistance, 0, 400, 100, 100+(this.trailsTotal - 1 - i)*40), 100, 100+(this.trailsTotal - 1 - i)*40); 99 | this.DOM.trails[i].style.filter = `brightness(${brightnessVal}%)`; 100 | this.DOM.trails[i].style.transform = `translate3d(${this.trailsTranslation[i].previous.x}px,${this.trailsTranslation[i].previous.y}px,0)`; 101 | } 102 | } 103 | } 104 | 105 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo4/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag, img'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'ngs8vzi' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-wrap')].forEach((element) => new DraggableImage(element)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | 41 | 42 | -------------------------------------------------------------------------------- /js/demo5/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { lerp, clamp, distance } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | import { gsap, Power1 } from 'gsap'; 14 | 15 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 16 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 17 | 18 | // Image that gets dragged gets this zIndex value which then gets incremented 19 | let zIndex = 1; 20 | 21 | class DraggableImage { 22 | constructor(el) { 23 | // Image container 24 | this.DOM = {el: el}; 25 | // The draggable element 26 | this.DOM.draggable = this.DOM.el.querySelector('.img-drag'); 27 | // image element 28 | this.DOM.innerEl = this.DOM.el.querySelector('.img-drag__inner'); 29 | // Image trails 30 | this.trailsTotal = 10; 31 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 32 | const el = document.createElement('img'); 33 | el.className = 'img-trail'; 34 | el.alt = 'A decorative image'; 35 | el.src = this.DOM.innerEl.style.backgroundImage.match(/url\(["']?([^"']*)["']?\)/)[1]; 36 | this.DOM.el.insertBefore(el, this.DOM.el.firstChild); 37 | } 38 | this.DOM.trails = [...this.DOM.el.querySelectorAll('.img-trail')]; 39 | 40 | // Dragging position 41 | this.draggingPos = { 42 | previous: {x: 0, y: 0}, 43 | current: {x: 0, y: 0} 44 | }; 45 | // Inner Element scale 46 | this.innerScale = { 47 | previous: 1, 48 | current: 1, 49 | amt: 0.2 50 | }; 51 | // outer Element scale 52 | this.outerScale = { 53 | previous: 1, 54 | current: 1, 55 | amt: 0.2 56 | }; 57 | 58 | // mouse distance required to show the first trail image 59 | this.threshold = 30; 60 | this.trailPosition = 0; 61 | 62 | // Initialize Draggabilly 63 | this.draggie = new Draggabilly(this.DOM.draggable); 64 | // Init/Bind events 65 | this.initEvents(); 66 | // Loop 67 | requestAnimationFrame(() => this.render()); 68 | } 69 | initEvents() { 70 | this.onDragStart = () => { 71 | // Reset 72 | this.draggingPos.previous = {x: 0, y: 0}; 73 | }; 74 | 75 | this.onDragMove = (event, pointer, moveVector) => { 76 | this.draggingPos.current = moveVector; 77 | }; 78 | 79 | this.onPointerDown = () => { 80 | this.DOM.el.style.zIndex = zIndex++; 81 | this.innerScale.current = 1.5; 82 | this.outerScale.current = 0.8; 83 | document.body.style.cursor = 'grabbing'; 84 | this.DOM.draggable.style.cursor = 'grabbing'; 85 | }; 86 | 87 | this.onPointerUp = () => { 88 | // Reset 89 | this.innerScale.current = 1; 90 | this.outerScale.current = 1; 91 | document.body.style.cursor = 'default'; 92 | this.DOM.draggable.style.cursor = 'grab'; 93 | }; 94 | 95 | this.draggie.on('pointerDown', this.onPointerDown); 96 | this.draggie.on('dragStart', this.onDragStart); 97 | this.draggie.on('dragMove', this.onDragMove); 98 | this.draggie.on('pointerUp', this.onPointerUp); 99 | } 100 | render() { 101 | this.innerScale.previous = lerp(this.innerScale.previous, this.innerScale.current, this.innerScale.amt); 102 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 103 | 104 | this.layout(); 105 | // loop 106 | requestAnimationFrame(() => this.render()); 107 | } 108 | layout() { 109 | const draggingDistance = distance(this.draggingPos.previous.x, this.draggingPos.previous.y, this.draggingPos.current.x, this.draggingPos.current.y); 110 | 111 | // The inner element transform 112 | this.DOM.innerEl.style.transform = `scale3d(${this.innerScale.previous}, ${this.innerScale.previous}, 1)`; 113 | // The draggable element transform 114 | this.DOM.draggable.style.transform = `scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1)`; 115 | 116 | // If the mouse moved more than [this.threshold] then show the next image 117 | if ( draggingDistance > this.threshold ) { 118 | this.showNextTrailImage(); 119 | this.trailPosition = this.trailPosition < this.trailsTotal-1 ? this.trailPosition+1 : 0; 120 | this.draggingPos.previous = this.draggingPos.current; 121 | } 122 | } 123 | showNextTrailImage() { 124 | const trailEl = this.DOM.trails[this.trailPosition]; 125 | // Kill any tween on the trail 126 | gsap.killTweensOf(trailEl); 127 | gsap.timeline({onComplete: () => this.resetTrail(trailEl)}) 128 | // show the image 129 | .set(trailEl, { 130 | startAt: {opacity: 0}, 131 | opacity: 1, 132 | scale: this.outerScale.previous, 133 | x: this.draggie.position.x, 134 | y: this.draggie.position.y 135 | }, 0) 136 | // then make it disappear 137 | .to(trailEl, 0.3, { 138 | ease: Power1.easeOut, 139 | opacity: 0, 140 | scale: () => this.outerScale.previous 141 | }, 0.1); 142 | } 143 | resetTrail(trailEl) { 144 | gsap.set(trailEl, { 145 | opacity: 0, 146 | scale: 1, 147 | x: this.draggie.position.x, 148 | y: this.draggie.position.y 149 | }); 150 | } 151 | } 152 | 153 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo5/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag__inner, img'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'sth6zmv' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-wrap')].forEach((element) => new DraggableImage(element)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | 41 | 42 | -------------------------------------------------------------------------------- /js/demo6/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { lerp, clamp, distance, getRandomFloat } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | import { gsap, Power1 } from 'gsap'; 14 | 15 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 16 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 17 | 18 | // Image that gets dragged gets this zIndex value which then gets incremented 19 | let zIndex = 1; 20 | 21 | class DraggableImage { 22 | constructor(el) { 23 | // Image container 24 | this.DOM = {el: el}; 25 | // The draggable element 26 | this.DOM.draggable = this.DOM.el.querySelector('.img-drag'); 27 | // image element 28 | this.DOM.innerEl = this.DOM.el.querySelector('.img-drag__inner'); 29 | // Image trails 30 | this.trailsTotal = 20; 31 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 32 | const el = document.createElement('img'); 33 | el.className = 'img-trail'; 34 | el.alt = 'A decorative image'; 35 | el.src = this.DOM.innerEl.style.backgroundImage.match(/url\(["']?([^"']*)["']?\)/)[1]; 36 | this.DOM.el.insertBefore(el, this.DOM.el.firstChild); 37 | } 38 | this.DOM.trails = [...this.DOM.el.querySelectorAll('.img-trail')]; 39 | 40 | // Dragging position 41 | this.draggingPos = { 42 | previous: {x: 0, y: 0}, 43 | current: {x: 0, y: 0} 44 | }; 45 | // Inner Element scale 46 | this.innerScale = { 47 | previous: 1, 48 | current: 1, 49 | amt: 0.2 50 | }; 51 | // outer Element scale 52 | this.outerScale = { 53 | previous: 1, 54 | current: 1, 55 | amt: 0.2 56 | }; 57 | 58 | // mouse distance required to show the first trail image 59 | this.threshold = 10; 60 | this.trailPosition = 0; 61 | 62 | // Initialize Draggabilly 63 | this.draggie = new Draggabilly(this.DOM.draggable); 64 | // Init/Bind events 65 | this.initEvents(); 66 | // Loop 67 | requestAnimationFrame(() => this.render()); 68 | } 69 | initEvents() { 70 | this.onDragStart = () => { 71 | // Reset 72 | this.draggingPos.previous = {x: 0, y: 0}; 73 | }; 74 | 75 | this.onDragMove = (event, pointer, moveVector) => { 76 | this.draggingPos.current = moveVector; 77 | }; 78 | 79 | this.onPointerDown = () => { 80 | this.DOM.el.style.zIndex = zIndex++; 81 | this.innerScale.current = 1.2; 82 | this.outerScale.current = 0.8; 83 | document.body.style.cursor = 'grabbing'; 84 | this.DOM.draggable.style.cursor = 'grabbing'; 85 | }; 86 | 87 | this.onPointerUp = () => { 88 | // Reset 89 | this.innerScale.current = 1; 90 | this.outerScale.current = 1; 91 | document.body.style.cursor = 'default'; 92 | this.DOM.draggable.style.cursor = 'grab'; 93 | }; 94 | 95 | this.draggie.on('pointerDown', this.onPointerDown); 96 | this.draggie.on('dragStart', this.onDragStart); 97 | this.draggie.on('dragMove', this.onDragMove); 98 | this.draggie.on('pointerUp', this.onPointerUp); 99 | } 100 | render() { 101 | this.innerScale.previous = lerp(this.innerScale.previous, this.innerScale.current, this.innerScale.amt); 102 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 103 | 104 | this.layout(); 105 | // loop 106 | requestAnimationFrame(() => this.render()); 107 | } 108 | layout() { 109 | const draggingDistance = distance(this.draggingPos.previous.x, this.draggingPos.previous.y, this.draggingPos.current.x, this.draggingPos.current.y); 110 | 111 | // If the mouse moved more than [this.threshold] then show the next image 112 | if ( draggingDistance > this.threshold ) { 113 | this.showNextTrailImage(); 114 | this.trailPosition = this.trailPosition < this.trailsTotal-1 ? this.trailPosition+1 : 0; 115 | this.draggingPos.previous = this.draggingPos.current; 116 | } 117 | 118 | // The inner element transform 119 | this.DOM.innerEl.style.transform = `scale3d(${this.innerScale.previous}, ${this.innerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 120 | // The draggable element transform 121 | this.DOM.draggable.style.transform = `scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1) rotate3d(1,1,1,0.1deg)`; 122 | } 123 | showNextTrailImage() { 124 | const trailEl = this.DOM.trails[this.trailPosition]; 125 | // Kill any tween on the trail 126 | gsap.killTweensOf(trailEl); 127 | gsap.timeline({onComplete: () => this.resetTrail(trailEl)}) 128 | // show the image 129 | .set(trailEl, { 130 | startAt: {opacity: 0}, 131 | opacity: 1, 132 | scale: this.outerScale.previous, 133 | x: this.draggie.position.x, 134 | y: this.draggie.position.y, 135 | rotation: () => getRandomFloat(-10,10) 136 | }, 0) 137 | // then make it disappear 138 | .to(trailEl, 0.3, { 139 | ease: Power1.easeOut, 140 | opacity: 0, 141 | scale: () => this.outerScale.previous 142 | }, 0.1); 143 | } 144 | resetTrail(trailEl) { 145 | gsap.set(trailEl, { 146 | opacity: 0, 147 | scale: 1, 148 | x: this.draggie.position.x, 149 | y: this.draggie.position.y, 150 | rotation: 0 151 | }); 152 | } 153 | } 154 | 155 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo6/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag__inner, img'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'hsm8jwd' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-wrap')].forEach((element) => new DraggableImage(element)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | 41 | -------------------------------------------------------------------------------- /js/demo7/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp, distance } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | 14 | // Image that gets dragged gets this zIndex value which then gets incremented 15 | let zIndex = 1; 16 | 17 | class DraggableImage { 18 | constructor(el) { 19 | // image container (the draggable element) 20 | this.DOM = {el: el}; 21 | this.DOM.svg = this.DOM.el.querySelector('svg'); 22 | this.DOM.img = this.DOM.svg.querySelector('g > image'); 23 | // The feDisplacementMap element 24 | this.DOM.feDisplacementMapEl = this.DOM.svg.querySelector('feDisplacementMap'); 25 | 26 | // Dragging position 27 | this.draggingPos = { 28 | translation: { 29 | previous: {x: 0, y: 0}, 30 | current: {x: 0, y: 0}, 31 | amt: 0.15 32 | }, 33 | displacement: { 34 | previous: {x: 0, y: 0}, 35 | current: {x: 0, y: 0}, 36 | amt: 0.08 37 | } 38 | }; 39 | // outer Element scale 40 | this.outerScale = { 41 | previous: 1, 42 | current: 1, 43 | amt: 0.1 44 | }; 45 | 46 | // Initialize Draggabilly 47 | this.draggie = new Draggabilly(this.DOM.el); 48 | // Init/Bind events 49 | this.initEvents(); 50 | // Loop 51 | requestAnimationFrame(() => this.render()); 52 | } 53 | initEvents() { 54 | this.onDragStart = () => { 55 | // Reset 56 | this.draggingPos.translation.previous = {x: 0, y: 0}; 57 | this.draggingPos.displacement.previous = {x: 0, y: 0}; 58 | }; 59 | 60 | this.onDragMove = (event, pointer, moveVector) => { 61 | this.draggingPos.translation.current = moveVector; 62 | this.draggingPos.displacement.current = moveVector; 63 | }; 64 | 65 | this.onPointerDown = () => { 66 | this.DOM.el.style.zIndex = zIndex++; 67 | this.outerScale.current = 0.75; 68 | document.body.style.cursor = 'grabbing'; 69 | this.DOM.el.style.cursor = 'grabbing'; 70 | }; 71 | 72 | this.onPointerUp = () => { 73 | // Reset 74 | this.outerScale.current = 1; 75 | document.body.style.cursor = 'default'; 76 | this.DOM.el.style.cursor = 'grab'; 77 | }; 78 | 79 | this.draggie.on('pointerDown', this.onPointerDown); 80 | this.draggie.on('dragStart', this.onDragStart); 81 | this.draggie.on('dragMove', this.onDragMove); 82 | this.draggie.on('pointerUp', this.onPointerUp); 83 | } 84 | render() { 85 | this.draggingPos.translation.previous.x = lerp(this.draggingPos.translation.previous.x, this.draggingPos.translation.current.x, this.draggingPos.translation.amt); 86 | this.draggingPos.translation.previous.y = lerp(this.draggingPos.translation.previous.y, this.draggingPos.translation.current.y, this.draggingPos.translation.amt); 87 | this.draggingPos.displacement.previous.x = lerp(this.draggingPos.displacement.previous.x, this.draggingPos.displacement.current.x, this.draggingPos.displacement.amt); 88 | this.draggingPos.displacement.previous.y = lerp(this.draggingPos.displacement.previous.y, this.draggingPos.displacement.current.y, this.draggingPos.displacement.amt); 89 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 90 | 91 | this.layout(); 92 | // loop 93 | requestAnimationFrame(() => this.render()); 94 | } 95 | layout() { 96 | // The svg element transform 97 | this.DOM.svg.style.transform = `scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1) translate3d(${(this.draggingPos.translation.previous.x - this.draggingPos.translation.current.x).toFixed(2)}px,${(this.draggingPos.translation.previous.y - this.draggingPos.translation.current.y).toFixed(2)}px,0)`; 98 | 99 | const draggingDistance = distance(this.draggingPos.displacement.previous.x, this.draggingPos.displacement.previous.y, this.draggingPos.displacement.current.x, this.draggingPos.displacement.current.y); 100 | // The displacement value 101 | this.DOM.feDisplacementMapEl.scale.baseVal = clamp(map(draggingDistance, 0, 400, 0, 150), 0, 150); 102 | } 103 | } 104 | 105 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo7/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | 13 | // Preload fonts 14 | const preloadFonts = () => { 15 | return new Promise((resolve, reject) => { 16 | WebFont.load({ 17 | typekit: { 18 | id: 'mto6dlj' 19 | }, 20 | active: resolve 21 | }); 22 | }); 23 | }; 24 | 25 | Promise.all([ 26 | preloadFonts() 27 | ]).then(() => { 28 | [...document.querySelectorAll('.img-drag')].forEach((draggableEl) => new DraggableImage(draggableEl)); 29 | document.body.classList.remove('loading'); 30 | }); 31 | -------------------------------------------------------------------------------- /js/demo8/draggableImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * draggableImage.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import { map, lerp, clamp, distance, getRandomFloat } from './../MathUtils'; 12 | const Draggabilly = require('draggabilly'); 13 | 14 | // Draggabilly: Preserve transforms by using left and top rather than transform values (see https://codepen.io/desandro/pen/dEyIg) 15 | Draggabilly.prototype.positionDrag = Draggabilly.prototype.setLeftTop; 16 | 17 | // Image that gets dragged gets this zIndex value which then gets incremented 18 | let zIndex = 1; 19 | 20 | class DraggableImage { 21 | constructor(el) { 22 | // Image container 23 | this.DOM = {el: el}; 24 | // The draggable element 25 | this.DOM.draggable = this.DOM.el.querySelector('.img-drag'); 26 | this.boundingRect = this.DOM.draggable.getBoundingClientRect(); 27 | // Image trails 28 | this.DOM.trails = [...this.DOM.el.querySelectorAll('.img-trail')]; 29 | this.trailsTotal = this.DOM.trails.length; 30 | 31 | // Dragging position 32 | this.draggingPos = { 33 | previous: {x: 0, y: 0}, 34 | current: {x: 0, y: 0}, 35 | amt: 0.13 36 | }; 37 | // outer Element scale 38 | this.outerScale = { 39 | previous: 1, 40 | current: 1, 41 | amt: 0.1 42 | }; 43 | // Trails translations 44 | this.trailsTranslation = [...new Array(this.trailsTotal)].map(() => ({ 45 | previous: {x: 0, y: 0}, 46 | current: {x: 0, y: 0}, 47 | random: {x: 0, y: 0}, 48 | amt: getRandomFloat(0.07,0.11) 49 | })); 50 | // Trails scales 51 | this.trailsScale = [...new Array(this.trailsTotal)].map(() => ({ 52 | previous: 0, 53 | current: 0, 54 | amt: 0.1 55 | })); 56 | // Trails rotations 57 | this.trailsRotation = [...new Array(this.trailsTotal)].map(() => ({ 58 | previous: 0, 59 | current: 0, 60 | amt: 0.1 61 | })); 62 | // Initialize Draggabilly 63 | this.draggie = new Draggabilly(this.DOM.draggable); 64 | // Init/Bind events 65 | this.initEvents(); 66 | // Loop 67 | requestAnimationFrame(() => this.render()); 68 | } 69 | initEvents() { 70 | this.onDragStart = () => { 71 | // Reset 72 | this.draggingPos.previous = {x: 0, y: 0}; 73 | }; 74 | 75 | this.onDragMove = (event, pointer, moveVector) => { 76 | this.draggingPos.current = moveVector; 77 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 78 | this.trailsTranslation[i].current.x = this.draggie.position.x - parseFloat(this.trailsTranslation[i].random.x); 79 | this.trailsTranslation[i].current.y = this.draggie.position.y - parseFloat(this.trailsTranslation[i].random.y); 80 | } 81 | }; 82 | 83 | this.onPointerDown = () => { 84 | this.DOM.el.style.zIndex = zIndex++; 85 | this.outerScale.current = 0.8; 86 | const radius = (this.boundingRect.width + this.boundingRect.height)/2.5; 87 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 88 | this.trailsTranslation[i].random = { 89 | //x: getRandomFloat(-this.boundingRect.width*.85,this.boundingRect.width*.85), 90 | x: Math.round(radius * Math.cos(2*(i+1)*Math.PI/this.trailsTotal)), 91 | //y: getRandomFloat(-this.boundingRect.height*.85,this.boundingRect.height*.85) 92 | y: Math.round(radius * Math.sin(2*(i+1)*Math.PI/this.trailsTotal)) 93 | }; 94 | this.trailsTranslation[i].current.x = this.draggie.position.x - parseFloat(this.trailsTranslation[i].random.x); 95 | this.trailsTranslation[i].current.y = this.draggie.position.y - parseFloat(this.trailsTranslation[i].random.y); 96 | this.trailsScale[i].current = 0.5; 97 | this.trailsRotation[i].current = getRandomFloat(-10,10); 98 | } 99 | document.body.style.cursor = 'grabbing'; 100 | this.DOM.draggable.style.cursor = 'grabbing'; 101 | }; 102 | 103 | this.onPointerUp = () => { 104 | this.outerScale.current = 1; 105 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 106 | this.trailsTranslation[i].current = {x: this.draggie.position.x, y: this.draggie.position.y}; 107 | this.trailsScale[i].current = 0; 108 | this.trailsRotation[i].current = 0; 109 | } 110 | document.body.style.cursor = 'default'; 111 | this.DOM.draggable.style.cursor = 'grab'; 112 | }; 113 | 114 | this.onResize = () => { 115 | this.boundingRect = this.DOM.el.getBoundingClientRect(); 116 | }; 117 | 118 | this.draggie.on('pointerDown', this.onPointerDown); 119 | this.draggie.on('dragStart', this.onDragStart); 120 | this.draggie.on('dragMove', this.onDragMove); 121 | this.draggie.on('pointerUp', this.onPointerUp); 122 | window.addEventListener('resize', this.onResize); 123 | } 124 | render() { 125 | this.draggingPos.previous.x = lerp(this.draggingPos.previous.x, this.draggingPos.current.x, this.draggingPos.amt); 126 | this.draggingPos.previous.y = lerp(this.draggingPos.previous.y, this.draggingPos.current.y, this.draggingPos.amt); 127 | this.outerScale.previous = lerp(this.outerScale.previous, this.outerScale.current, this.outerScale.amt); 128 | 129 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 130 | this.trailsTranslation[i].previous.x = lerp(this.trailsTranslation[i].previous.x, this.trailsTranslation[i].current.x, this.trailsTranslation[i].amt); 131 | this.trailsTranslation[i].previous.y = lerp(this.trailsTranslation[i].previous.y, this.trailsTranslation[i].current.y, this.trailsTranslation[i].amt); 132 | this.trailsScale[i].previous = lerp(this.trailsScale[i].previous, this.trailsScale[i].current, this.trailsScale[i].amt); 133 | this.trailsRotation[i].previous = lerp(this.trailsRotation[i].previous, this.trailsRotation[i].current, this.trailsRotation[i].amt); 134 | } 135 | this.layout(); 136 | // loop 137 | requestAnimationFrame(() => this.render()); 138 | } 139 | layout() { 140 | const draggingDistance = distance(this.draggingPos.previous.x, this.draggingPos.previous.y, this.draggingPos.current.x, this.draggingPos.current.y); 141 | 142 | for (let i = 0; i <= this.trailsTotal - 1; ++i) { 143 | const blurVal = clamp(map(draggingDistance, 0, 400, 0, 20), 0, 20); 144 | this.DOM.trails[i].style.filter = `blur(${blurVal}px`; 145 | this.DOM.trails[i].style.transform = `translate3d(${this.trailsTranslation[i].previous.x}px,${this.trailsTranslation[i].previous.y}px,0) scale3d(${this.trailsScale[i].previous},${this.trailsScale[i].previous},1) rotate3d(0,0,1,${this.trailsRotation[i].previous}deg)`; 146 | } 147 | 148 | this.DOM.draggable.style.transform = `translate3d(${(this.draggingPos.previous.x - this.draggingPos.current.x).toFixed(2)}px,${(this.draggingPos.previous.y - this.draggingPos.current.y).toFixed(2)}px,0) scale3d(${this.outerScale.previous}, ${this.outerScale.previous}, 1)`; 149 | } 150 | } 151 | 152 | export default DraggableImage; -------------------------------------------------------------------------------- /js/demo8/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * index.js 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2020, Codrops 9 | * http://www.codrops.com 10 | */ 11 | import DraggableImage from "./draggableImage"; 12 | const imagesLoaded = require('imagesloaded'); 13 | 14 | // Preload images 15 | const preloadImages = () => { 16 | return new Promise((resolve, reject) => { 17 | imagesLoaded(document.querySelectorAll('.img-drag, .img-trail'), {background: true}, resolve); 18 | }); 19 | }; 20 | 21 | // Preload fonts 22 | const preloadFonts = () => { 23 | return new Promise((resolve, reject) => { 24 | WebFont.load({ 25 | typekit: { 26 | id: 'wwn4ioo' 27 | }, 28 | active: resolve 29 | }); 30 | }); 31 | }; 32 | 33 | Promise.all([ 34 | preloadImages(), 35 | preloadFonts() 36 | ]).then(() => { 37 | [...document.querySelectorAll('.img-wrap')].forEach((element) => new DraggableImage(element)); 38 | document.body.classList.remove('loading'); 39 | }); 40 | 41 | 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ImageDraggingEffects", 3 | "version": "1.0.0", 4 | "description": "A set of playful dragging effects for images using various techniques.", 5 | "main": "index.js", 6 | "scripts": { 7 | "copyimages": "copyfiles --f img/10.jpg img/11.jpg dist", 8 | "start": "npm run copyimages && parcel *.html --open", 9 | "clean": "rm -rf dist/*", 10 | "build:parcel": "parcel build index.html --no-minify --no-source-maps --public-url ./ && npm run copyimages", 11 | "build": "npm run clean && npm run build:parcel" 12 | }, 13 | "keywords": [], 14 | "author": "Codrops", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "@babel/core": "^7.8.3", 18 | "babel-preset-env": "^1.7.0" 19 | }, 20 | "dependencies": { 21 | "copyfiles": "^2.2.0", 22 | "draggabilly": "^2.2.0", 23 | "gsap": "^3.0.5", 24 | "imagesloaded": "^4.1.4", 25 | "parcel-bundler": "^1.12.4" 26 | } 27 | } 28 | --------------------------------------------------------------------------------