1// https://codepen.io/WillyW/pen/wZebow 2 3 4class DraggingEvent { 5 constructor(target = undefined) { 6 this.target = target; 7 } 8 9 event(callback) { 10 let handler; 11 12 this.target.addEventListener("mousedown", e => { 13 e.preventDefault() 14 15 handler = callback(e) 16 17 window.addEventListener("mousemove", handler) 18 19 document.addEventListener("mouseleave", clearDraggingEvent) 20 21 window.addEventListener("mouseup", clearDraggingEvent) 22 23 function clearDraggingEvent() { 24 window.removeEventListener("mousemove", handler) 25 window.removeEventListener("mouseup", clearDraggingEvent) 26 27 document.removeEventListener("mouseleave", clearDraggingEvent) 28 29 handler(null) 30 } 31 }) 32 33 this.target.addEventListener("touchstart", e => { 34 handler = callback(e) 35 36 window.addEventListener("touchmove", handler) 37 38 window.addEventListener("touchend", clearDraggingEvent) 39 40 document.body.addEventListener("mouseleave", clearDraggingEvent) 41 42 function clearDraggingEvent() { 43 window.removeEventListener("touchmove", handler) 44 window.removeEventListener("touchend", clearDraggingEvent) 45 46 handler(null) 47 } 48 }) 49 } 50 51 // Get the distance that the user has dragged 52 getDistance(callback) { 53 function distanceInit(e1) { 54 let startingX, startingY; 55 56 if ("touches" in e1) { 57 startingX = e1.touches[0].clientX 58 startingY = e1.touches[0].clientY 59 } else { 60 startingX = e1.clientX 61 startingY = e1.clientY 62 } 63 64 65 return function(e2) { 66 if (e2 === null) { 67 return callback(null) 68 } else { 69 70 if ("touches" in e2) { 71 return callback({ 72 x: e2.touches[0].clientX - startingX, 73 y: e2.touches[0].clientY - startingY 74 }) 75 } else { 76 return callback({ 77 x: e2.clientX - startingX, 78 y: e2.clientY - startingY 79 }) 80 } 81 } 82 } 83 } 84 85 this.event(distanceInit) 86 } 87} 88 89 90class CardCarousel extends DraggingEvent { 91 constructor(container, controller = undefined) { 92 super(container) 93 94 // DOM elements 95 this.container = container 96 this.controllerElement = controller 97 this.cards = container.querySelectorAll(".card") 98 99 // Carousel data 100 this.centerIndex = (this.cards.length - 1) / 2; 101 this.cardWidth = this.cards[0].offsetWidth / this.container.offsetWidth * 100 102 this.xScale = {}; 103 104 // Resizing 105 window.addEventListener("resize", this.updateCardWidth.bind(this)) 106 107 if (this.controllerElement) { 108 this.controllerElement.addEventListener("keydown", this.controller.bind(this)) 109 } 110 111 112 // Initializers 113 this.build() 114 115 // Bind dragging event 116 super.getDistance(this.moveCards.bind(this)) 117 } 118 119 updateCardWidth() { 120 this.cardWidth = this.cards[0].offsetWidth / this.container.offsetWidth * 100 121 122 this.build() 123 } 124 125 build(fix = 0) { 126 for (let i = 0; i < this.cards.length; i++) { 127 const x = i - this.centerIndex; 128 const scale = this.calcScale(x) 129 const scale2 = this.calcScale2(x) 130 const zIndex = -(Math.abs(i - this.centerIndex)) 131 132 const leftPos = this.calcPos(x, scale2) 133 134 135 this.xScale[x] = this.cards[i] 136 137 this.updateCards(this.cards[i], { 138 x: x, 139 scale: scale, 140 leftPos: leftPos, 141 zIndex: zIndex 142 }) 143 } 144 } 145 146 147 controller(e) { 148 const temp = {...this.xScale}; 149 150 if (e.keyCode === 39) { 151 // Left arrow 152 for (let x in this.xScale) { 153 const newX = (parseInt(x) - 1 < -this.centerIndex) ? this.centerIndex : parseInt(x) - 1; 154 155 temp[newX] = this.xScale[x] 156 } 157 } 158 159 if (e.keyCode == 37) { 160 // Right arrow 161 for (let x in this.xScale) { 162 const newX = (parseInt(x) + 1 > this.centerIndex) ? -this.centerIndex : parseInt(x) + 1; 163 164 temp[newX] = this.xScale[x] 165 } 166 } 167 168 this.xScale = temp; 169 170 for (let x in temp) { 171 const scale = this.calcScale(x), 172 scale2 = this.calcScale2(x), 173 leftPos = this.calcPos(x, scale2), 174 zIndex = -Math.abs(x) 175 176 this.updateCards(this.xScale[x], { 177 x: x, 178 scale: scale, 179 leftPos: leftPos, 180 zIndex: zIndex 181 }) 182 } 183 } 184 185 calcPos(x, scale) { 186 let formula; 187 188 if (x < 0) { 189 formula = (scale * 100 - this.cardWidth) / 2 190 191 return formula 192 193 } else if (x > 0) { 194 formula = 100 - (scale * 100 + this.cardWidth) / 2 195 196 return formula 197 } else { 198 formula = 100 - (scale * 100 + this.cardWidth) / 2 199 200 return formula 201 } 202 } 203 204 updateCards(card, data) { 205 if (data.x || data.x == 0) { 206 card.setAttribute("data-x", data.x) 207 } 208 209 if (data.scale || data.scale == 0) { 210 card.style.transform = `scale(${data.scale})` 211 212 if (data.scale == 0) { 213 card.style.opacity = data.scale 214 } else { 215 card.style.opacity = 1; 216 } 217 } 218 219 if (data.leftPos) { 220 card.style.left = `${data.leftPos}%` 221 } 222 223 if (data.zIndex || data.zIndex == 0) { 224 if (data.zIndex == 0) { 225 card.classList.add("highlight") 226 } else { 227 card.classList.remove("highlight") 228 } 229 230 card.style.zIndex = data.zIndex 231 } 232 } 233 234 calcScale2(x) { 235 let formula; 236 237 if (x <= 0) { 238 formula = 1 - -1 / 5 * x 239 240 return formula 241 } else if (x > 0) { 242 formula = 1 - 1 / 5 * x 243 244 return formula 245 } 246 } 247 248 calcScale(x) { 249 const formula = 1 - 1 / 5 * Math.pow(x, 2) 250 251 if (formula <= 0) { 252 return 0 253 } else { 254 return formula 255 } 256 } 257 258 checkOrdering(card, x, xDist) { 259 const original = parseInt(card.dataset.x) 260 const rounded = Math.round(xDist) 261 let newX = x 262 263 if (x !== x + rounded) { 264 if (x + rounded > original) { 265 if (x + rounded > this.centerIndex) { 266 267 newX = ((x + rounded - 1) - this.centerIndex) - rounded + -this.centerIndex 268 } 269 } else if (x + rounded < original) { 270 if (x + rounded < -this.centerIndex) { 271 272 newX = ((x + rounded + 1) + this.centerIndex) - rounded + this.centerIndex 273 } 274 } 275 276 this.xScale[newX + rounded] = card; 277 } 278 279 const temp = -Math.abs(newX + rounded) 280 281 this.updateCards(card, {zIndex: temp}) 282 283 return newX; 284 } 285 286 moveCards(data) { 287 let xDist; 288 289 if (data != null) { 290 this.container.classList.remove("smooth-return") 291 xDist = data.x / 250; 292 } else { 293 294 295 this.container.classList.add("smooth-return") 296 xDist = 0; 297 298 for (let x in this.xScale) { 299 this.updateCards(this.xScale[x], { 300 x: x, 301 zIndex: Math.abs(Math.abs(x) - this.centerIndex) 302 }) 303 } 304 } 305 306 for (let i = 0; i < this.cards.length; i++) { 307 const x = this.checkOrdering(this.cards[i], parseInt(this.cards[i].dataset.x), xDist), 308 scale = this.calcScale(x + xDist), 309 scale2 = this.calcScale2(x + xDist), 310 leftPos = this.calcPos(x + xDist, scale2) 311 312 313 this.updateCards(this.cards[i], { 314 scale: scale, 315 leftPos: leftPos 316 }) 317 } 318 } 319}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.