276 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { CardLoader, DOMFlip } from '../flippable.js'
 | 
						|
import { Capabilities } from '../capabilities.js'
 | 
						|
import { DeepZoomImage } from './deepzoom/image.js'
 | 
						|
 | 
						|
let globalScatterLoaderCanvas = null
 | 
						|
 | 
						|
export class ScatterLoader extends CardLoader {
 | 
						|
    get scatter() {
 | 
						|
        return this.src
 | 
						|
    }
 | 
						|
 | 
						|
    unscaledSize() {
 | 
						|
        let displayObject = this.scatter.displayObject
 | 
						|
        let w = displayObject.width
 | 
						|
        let h = displayObject.height
 | 
						|
        return [w / displayObject.scale.x, h / displayObject.scale.y]
 | 
						|
    }
 | 
						|
 | 
						|
    scaledSize() {
 | 
						|
        let displayObject = this.scatter.displayObject
 | 
						|
        let w = displayObject.width
 | 
						|
        let h = displayObject.height
 | 
						|
        return [w, h]
 | 
						|
    }
 | 
						|
 | 
						|
    cloneScatterImage() {
 | 
						|
        let w = this.scatter.width
 | 
						|
        let h = this.scatter.height
 | 
						|
        let isSprite = this.scatter.displayObject instanceof PIXI.Sprite
 | 
						|
        let isDeepZoom = this.scatter.displayObject instanceof DeepZoomImage
 | 
						|
        let resolution = app.renderer.resolution
 | 
						|
        if (isSprite) {
 | 
						|
            w = this.scatter.displayObject.texture.width
 | 
						|
            h = this.scatter.displayObject.texture.height
 | 
						|
        } else if (isDeepZoom) {
 | 
						|
            let [ww, hh] = this.scatter.displayObject.baseSize
 | 
						|
            w = ww
 | 
						|
            h = hh
 | 
						|
        }
 | 
						|
        if (globalScatterLoaderCanvas === null) {
 | 
						|
            globalScatterLoaderCanvas = document.createElement('canvas')
 | 
						|
        }
 | 
						|
        let canvas = globalScatterLoaderCanvas
 | 
						|
        canvas.width = w
 | 
						|
        canvas.height = h
 | 
						|
        let renderer = new PIXI.Renderer({
 | 
						|
            width: w,
 | 
						|
            height: h,
 | 
						|
            view: canvas,
 | 
						|
            resolution: resolution,
 | 
						|
        })
 | 
						|
 | 
						|
        let displayObject = this.scatter.displayObject
 | 
						|
        let x = displayObject.x
 | 
						|
        let y = displayObject.y
 | 
						|
        let rot = displayObject.rotation
 | 
						|
        let sx = displayObject.scale.x
 | 
						|
        let sy = displayObject.scale.y
 | 
						|
        displayObject.rotation = 0
 | 
						|
        // The Safari WebGLRenderer wants everything flipped
 | 
						|
        // See https://github.com/pixijs/pixi.js/issues/2283
 | 
						|
        displayObject.x = 0
 | 
						|
        if (Capabilities.isSafari) {
 | 
						|
            displayObject.y = h
 | 
						|
            displayObject.scale.set(1, -1) // sx, -sy)
 | 
						|
        } else {
 | 
						|
            displayObject.y = 0
 | 
						|
            displayObject.scale.set(1, 1)
 | 
						|
        }
 | 
						|
        if (isSprite) {
 | 
						|
            displayObject.width = w
 | 
						|
            displayObject.height = h
 | 
						|
        }
 | 
						|
        renderer.render(displayObject)
 | 
						|
        displayObject.rotation = rot
 | 
						|
        displayObject.x = x
 | 
						|
        displayObject.y = y
 | 
						|
        displayObject.scale.set(sx, sy)
 | 
						|
 | 
						|
        let url = canvas.toDataURL()
 | 
						|
        return [x, y, w, h, url]
 | 
						|
    }
 | 
						|
 | 
						|
    load(domNode) {
 | 
						|
        return new Promise((resolve, reject) => {
 | 
						|
            let isImage = domNode instanceof HTMLImageElement
 | 
						|
            let isSprite = this.scatter.displayObject instanceof PIXI.Sprite
 | 
						|
            let image = isImage ? domNode : document.createElement('img')
 | 
						|
            let [x, y, w, h, cloneURL] = this.cloneScatterImage()
 | 
						|
            let [ww, hh] = this.unscaledSize()
 | 
						|
            image.onload = (e) => {
 | 
						|
                if (!isImage) domNode.appendChild(image)
 | 
						|
                this.x = x
 | 
						|
                this.y = y
 | 
						|
                this.wantedWidth = ww
 | 
						|
                this.wantedHeight = hh
 | 
						|
                this.scale = 1
 | 
						|
                this.rotation = this.scatter.rotation
 | 
						|
                resolve(this)
 | 
						|
            }
 | 
						|
            image.onerror = (e) => {
 | 
						|
                reject(this)
 | 
						|
            }
 | 
						|
            image.src = cloneURL
 | 
						|
        })
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
export default class FlipEffect {
 | 
						|
    constructor(scatter, domScatterContainer, flipTemplate, backLoader) {
 | 
						|
        this.flipped = false
 | 
						|
        this.scatter = scatter
 | 
						|
        this.backLoader = backLoader
 | 
						|
        this.scatterLoader = new ScatterLoader(scatter)
 | 
						|
        this.domFlip = new DOMFlip(domScatterContainer, flipTemplate, this.scatterLoader, backLoader, {
 | 
						|
            onBack: this.backCardClosed.bind(this),
 | 
						|
        })
 | 
						|
        this.setupInfoButton()
 | 
						|
    }
 | 
						|
 | 
						|
    startFlip() {
 | 
						|
        let center = this.flipCenter()
 | 
						|
        let loader = this.backLoader
 | 
						|
        this.domFlip.load().then((domFlip) => {
 | 
						|
            this.scatter.displayObject.visible = false
 | 
						|
            domFlip.centerAt(center)
 | 
						|
            domFlip.zoom(this.scatter.scale)
 | 
						|
            let target = this.constraintFlipCenter(center, loader)
 | 
						|
            domFlip.start({ targetCenter: target })
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    unscaledSize() {
 | 
						|
        return this.scatterLoader.unscaledSize()
 | 
						|
    }
 | 
						|
 | 
						|
    flipCenter() {
 | 
						|
        let isSprite = this.scatter.displayObject instanceof PIXI.Sprite
 | 
						|
        let resolution = isSprite ? app.renderer.resolution : 1
 | 
						|
        let center = this.scatter.center
 | 
						|
        let canvas = app.renderer.view
 | 
						|
        let domNode = this.domFlip.domScatterContainer.element
 | 
						|
        let page = window.convertPointFromNodeToPage(canvas, center.x * resolution, center.y * resolution)
 | 
						|
        let local = window.convertPointFromPageToNode(domNode, page.x, page.y)
 | 
						|
        return local
 | 
						|
    }
 | 
						|
 | 
						|
    constraintFlipCenter(center, loader) {
 | 
						|
        let w = loader.wantedWidth
 | 
						|
        let h = loader.wantedHeight
 | 
						|
        let canvas = app.renderer.view
 | 
						|
        let x = center.x
 | 
						|
        let y = center.y
 | 
						|
        if (x < w / 2) x = w / 2
 | 
						|
        if (y < h / 2) y = h / 2
 | 
						|
        if (x > canvas.width) x = canvas.width - w / 2
 | 
						|
        if (y > canvas.height) y = canvas.height - h / 2
 | 
						|
        return { x, y }
 | 
						|
    }
 | 
						|
 | 
						|
    setupInfoButton() {
 | 
						|
        let iscale = 1.0 / this.scatter.scale
 | 
						|
        this.infoBtn = new PIXI.Graphics()
 | 
						|
        this.infoBtn.beginFill(0x333333)
 | 
						|
        this.infoBtn.lineStyle(4, 0xffffff)
 | 
						|
        this.infoBtn.drawCircle(0, 0, 22)
 | 
						|
        this.infoBtn.endFill()
 | 
						|
 | 
						|
        this.infoBtn.beginFill(0xffffff)
 | 
						|
        this.infoBtn.lineStyle(0)
 | 
						|
        this.infoBtn.drawCircle(0, -8, 4)
 | 
						|
        this.infoBtn.endFill()
 | 
						|
 | 
						|
        this.infoBtn.lineStyle(6, 0xffffff)
 | 
						|
        this.infoBtn.moveTo(0, -2)
 | 
						|
        this.infoBtn.lineTo(0, 14)
 | 
						|
        this.infoBtn.endFill()
 | 
						|
 | 
						|
        this.infoBtn.on('click', (e) => {
 | 
						|
            this.infoSelected()
 | 
						|
        })
 | 
						|
        this.infoBtn.on('tap', (e) => {
 | 
						|
            this.infoSelected()
 | 
						|
        })
 | 
						|
 | 
						|
        this.infoBtn.interactive = true
 | 
						|
        this.infoBtn.width = 44
 | 
						|
        this.infoBtn.height = 44
 | 
						|
        this.infoBtn.pivot.x = 30
 | 
						|
        this.infoBtn.pivot.y = 30
 | 
						|
 | 
						|
        let displayObject = this.scatter.displayObject
 | 
						|
        let [w, h] = this.unscaledSize()
 | 
						|
        this.infoBtn.position = new PIXI.Point(w, h)
 | 
						|
        if (displayObject.foreground) {
 | 
						|
            this.infoBtn.scale.x = iscale
 | 
						|
            this.infoBtn.scale.y = iscale
 | 
						|
            displayObject.foreground.addChild(this.infoBtn)
 | 
						|
        } else {
 | 
						|
            displayObject.addChild(this.infoBtn)
 | 
						|
        }
 | 
						|
 | 
						|
        this.scatter.addTransformEventCallback((e) => {
 | 
						|
            let displayObject = this.scatter.displayObject
 | 
						|
            if (displayObject.foreground) {
 | 
						|
                if (e.scale) {
 | 
						|
                    let iscale = 1.0 / e.scale
 | 
						|
                    this.infoBtn.scale.x = iscale
 | 
						|
                    this.infoBtn.scale.y = iscale
 | 
						|
                }
 | 
						|
            }
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    setupButton(url) {
 | 
						|
        let svgImage = new Image()
 | 
						|
        let canvas = document.createElement('canvas')
 | 
						|
        canvas.width = 88 * 4
 | 
						|
        canvas.height = 44 * 4
 | 
						|
        svgImage.onload = (e) => {
 | 
						|
            let displayObject = this.scatter.displayObject
 | 
						|
            canvas.getContext('2d').drawImage(svgImage, 0, 0, canvas.width, canvas.height)
 | 
						|
            let texure = new PIXI.Texture(new PIXI.BaseTexture(canvas))
 | 
						|
            this.infoBtn = new PIXI.Sprite(texure)
 | 
						|
            this.infoBtn.anchor.set(0.5, 0.5)
 | 
						|
            if (displayObject.foreground) {
 | 
						|
                displayObject.foreground.addChild(this.infoBtn)
 | 
						|
            } else {
 | 
						|
                displayObject.addChild(this.infoBtn)
 | 
						|
            }
 | 
						|
            this.infoBtn.scale.set(0.5, 0.5)
 | 
						|
 | 
						|
            let [w, h] = this.unscaledSize()
 | 
						|
            this.infoBtn.position = new PIXI.Point(w, h)
 | 
						|
            this.infoBtn.interactive = true
 | 
						|
            this.infoBtn.updateTransform()
 | 
						|
            this.infoBtn.on('click', (e) => {
 | 
						|
                this.infoSelected()
 | 
						|
            })
 | 
						|
            this.infoBtn.on('tap', (e) => {
 | 
						|
                this.infoSelected()
 | 
						|
            })
 | 
						|
        }
 | 
						|
        svgImage.src = url
 | 
						|
    }
 | 
						|
 | 
						|
    infoSelected() {
 | 
						|
        this.startFlip()
 | 
						|
    }
 | 
						|
 | 
						|
    backSelected() {
 | 
						|
        this.domFlip.start()
 | 
						|
    }
 | 
						|
 | 
						|
    backCardClosed() {
 | 
						|
        /*** The flip effect should now be in it's initial state again. All
 | 
						|
        memory should be freed. ***/
 | 
						|
        let displayObject = this.scatter.displayObject
 | 
						|
        displayObject.visible = true
 | 
						|
        this.domFlip.fadeOutAndRemove()
 | 
						|
        this.flipped = false
 | 
						|
    }
 | 
						|
 | 
						|
    targetRotation(alpha) {
 | 
						|
        let ortho = 90
 | 
						|
        let rest = alpha % ortho
 | 
						|
        let delta = 0.0
 | 
						|
        if (rest > ortho / 2.0) {
 | 
						|
            delta = ortho - rest
 | 
						|
        } else {
 | 
						|
            delta = -rest
 | 
						|
        }
 | 
						|
        return delta
 | 
						|
    }
 | 
						|
}
 |