Skip to content

Instantly share code, notes, and snippets.

@scorredoira
Created October 2, 2020 20:33
Show Gist options
  • Save scorredoira/b9a12db70a9c311b868ac87599632973 to your computer and use it in GitHub Desktop.
Save scorredoira/b9a12db70a9c311b868ac87599632973 to your computer and use it in GitHub Desktop.
namespace UI {
const subtitle = T("@@or drop a file to upload")
interface Position {
x: number
y: number
}
interface Bounds {
left: number
top: number
right: number
bottom: number
}
export class Imagedrop extends S.Control {
private subtitleRow: HTMLElement
private input: HTMLInputElement
private overlay: HTMLElement
private draggingElement: string
private mouseStart: Position
private startBounds: Bounds
private cropLayer: HTMLElement
private cropperBounds: Bounds
data: string
constructor() {
super(S.create("div", "ui-imagedrop"))
// this.data = DATA
// this.startCrop()
}
private addDropEvents(element: HTMLElement) {
element.addEventListener("dragover", e => this.onDragover(e))
element.addEventListener("dragenter", e => this.onDragenter(e))
element.addEventListener("dragleave", e => this.onDragleave(e))
element.addEventListener("drop", e => this.onDrop(e))
}
private _url: string;
public get url(): string {
return this._url;
}
public set url(v: string) {
this._url = v;
this.render()
}
render() {
if (this.building) {
return
}
if (!this.data && !this._url) {
this.renderEmpty()
return
}
// this.overlay = S.create("div", "overlay", this.element)
// this.overlay.style.backgroundImage = "url(" + this.data || this.url + ")"
}
private renderEmpty() {
this.clear()
this.element.classList.remove("crop")
this.element.classList.add("empty")
this.input = S.createInput("file", "inputFile", this.element)
this.input.accept = ".gif,.jpg,.jpeg,.png"
this.input.addEventListener("input", e => this.onFilePicked())
this.addDropEvents(this.element)
let icon = getIcon("photo", 50, 50)
let row = S.create("div", "row", this.element, icon)
this.addDropEvents(row)
let button = new Button(T("@@Add file"))
button.click = () => this.input.click()
this.appendChild(button)
row = S.create("div", "row", this.element, button.element)
this.addDropEvents(row)
this.subtitleRow = S.create("div", "row subtitle", this.element, subtitle)
this.addDropEvents(this.subtitleRow)
}
private onDragover(e: DragEvent) {
e.preventDefault()
e.stopPropagation()
}
private onDragenter(e: DragEvent) {
e.preventDefault()
e.stopPropagation()
this.element.classList.add("dragover")
}
private onDragleave(e: DragEvent) {
e.preventDefault()
e.stopPropagation()
this.element.classList.remove("dragover")
}
private onDrop(e: DragEvent) {
// Prevent default behavior (Prevent file from being opened)
e.preventDefault()
e.stopPropagation()
this.element.classList.remove("dragover")
this.onFileSelected(e.dataTransfer.files[0])
e.dataTransfer.clearData()
}
private onFilePicked() {
this.onFileSelected(this.input.files[0])
this.input.files = null
}
private onFileSelected(f: File) {
const reader = new FileReader();
reader.readAsDataURL(f)
reader.onload = () => {
this.data = reader.result.toString()
this.dispatchEvent(new CustomEvent("input", { detail: f }))
this.startCrop()
}
}
private startCrop() {
this.clear()
this.element.classList.add("crop")
this.element.classList.remove("empty")
let img = S.create("img", null, this.element)
img.addEventListener("load", () => this.showCropper())
img.src = this.data
}
private showCropper() {
this.cropLayer = S.create("div", "cropLayer", this.element)
this.cropLayer.addEventListener("mouseup", () => this.stopDragging())
//this.cropLayer.addEventListener("mouseleave", () => this.stopDragging())
this.cropLayer.addEventListener("mousemove", e => this.onMouseMove(e))
this.cropperBounds = {
left: 20,
right: 20,
top: 20,
bottom: 20
}
this.adjustGrid()
let top = S.create("div", "cover", this.cropLayer)
top.style.gridColumn = "span 3"
S.create("div", "cover", this.cropLayer)
let cropper = S.create("div", "cropper", this.cropLayer)
S.create("div", "cover", this.cropLayer)
let bottom = S.create("div", "cover", this.cropLayer)
bottom.style.gridColumn = "span 3"
let leftTop = S.create("div", "handle leftTop", cropper)
let rightTop = S.create("div", "handle rightTop", cropper)
let leftBottom = S.create("div", "handle leftBottom", cropper)
let rightBottom = S.create("div", "handle rightBottom", cropper)
cropper.addEventListener("mousedown", e => this.startDragging(e, "cropper"))
leftTop.addEventListener("mousedown", e => this.startDragging(e, "leftTop"))
rightTop.addEventListener("mousedown", e => this.startDragging(e, "rightTop"))
leftBottom.addEventListener("mousedown", e => this.startDragging(e, "leftBottom"))
rightBottom.addEventListener("mousedown", e => this.startDragging(e, "rightBottom"))
}
private startDragging(e: MouseEvent, source: string) {
if (e.button != 0) {
return
}
e.stopPropagation()
this.draggingElement = source
this.mouseStart = { x: e.x, y: e.y }
this.startBounds = {
left: this.cropperBounds.left,
right: this.cropperBounds.right,
top: this.cropperBounds.top,
bottom: this.cropperBounds.bottom,
}
}
private stopDragging() {
this.mouseStart = null
this.startBounds = null
console.log(this.getCropBounds())
}
private onMouseMove(e: MouseEvent) {
if (e.buttons != 1) {
// not clicked
return
}
let x = e.x - this.mouseStart.x
let y = e.y - this.mouseStart.y
let isCropper
switch (this.draggingElement) {
case "cropper":
isCropper = true
this.cropperBounds.left = this.startBounds.left + x
this.cropperBounds.right = this.startBounds.right - x
this.cropperBounds.top = this.startBounds.top + y
this.cropperBounds.bottom = this.startBounds.bottom - y
break
case "leftTop":
this.cropperBounds.left = this.startBounds.left + x
this.cropperBounds.top = this.startBounds.top + y
break
case "leftBottom":
this.cropperBounds.left = this.startBounds.left + x
this.cropperBounds.bottom = this.startBounds.bottom - y
break
case "rightTop":
this.cropperBounds.right = this.startBounds.right - x
this.cropperBounds.top = this.startBounds.top + y
break
case "rightBottom":
this.cropperBounds.right = this.startBounds.right - x
this.cropperBounds.bottom = this.startBounds.bottom - y
break
}
if (x < 0) {
if (this.cropperBounds.left < 0) {
this.cropperBounds.left = 0
if (isCropper) {
this.cropperBounds.right = this.startBounds.left + this.startBounds.right
}
}
} else if (x > 0) {
if (this.cropperBounds.right < 0) {
this.cropperBounds.right = 0
if (isCropper) {
this.cropperBounds.left = this.startBounds.left + this.startBounds.right
}
}
}
if (y < 0) {
if (this.cropperBounds.top < 0) {
this.cropperBounds.top = 0
if (isCropper) {
this.cropperBounds.bottom = this.startBounds.top + this.startBounds.bottom
}
}
}
if (y > 0) {
if (this.cropperBounds.bottom < 0) {
this.cropperBounds.bottom = 0
if (isCropper) {
this.cropperBounds.top = this.startBounds.top + this.startBounds.bottom
}
}
}
this.adjustGrid()
}
private adjustGrid() {
let b = this.cropperBounds
this.cropLayer.style.gridTemplateColumns = b.left + "px auto " + b.right + "px"
this.cropLayer.style.gridTemplateRows = b.top + "px auto " + b.bottom + "px"
}
private getCropBounds() {
let width = this.element.offsetWidth
let height = this.element.offsetHeight
let b = this.cropperBounds
return {
left: b.left,
top: b.top,
right: width - b.right,
bottom: height - b.bottom
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment