iwmlib/lib/pixi/flipeffect.js

276 lines
8.8 KiB
JavaScript
Raw Normal View History

2019-10-02 11:51:23 +02:00
import { CardLoader, DOMFlip } from '../flippable.js'
2019-07-18 12:26:39 +02:00
import { Capabilities } from '../capabilities.js'
import { DeepZoomImage } from './deepzoom/image.js'
2019-03-21 09:57:27 +01:00
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
2019-07-18 12:26:39 +02:00
} else if (isDeepZoom) {
2019-03-21 09:57:27 +01:00
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
2019-10-02 15:00:08 +02:00
let renderer = new PIXI.Renderer({
width: w,
height: h,
2019-07-18 12:26:39 +02:00
view: canvas,
2022-10-04 10:51:35 +02:00
resolution: resolution,
2019-07-18 12:26:39 +02:00
})
2019-03-21 09:57:27 +01:00
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)
2019-07-18 12:26:39 +02:00
} else {
2019-03-21 09:57:27 +01:00
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
2019-07-18 12:26:39 +02:00
let image = isImage ? domNode : document.createElement('img')
2019-03-21 09:57:27 +01:00
let [x, y, w, h, cloneURL] = this.cloneScatterImage()
let [ww, hh] = this.unscaledSize()
2022-10-04 10:51:35 +02:00
image.onload = (e) => {
2019-07-18 12:26:39 +02:00
if (!isImage) domNode.appendChild(image)
2019-03-21 09:57:27 +01:00
this.x = x
this.y = y
this.wantedWidth = ww
this.wantedHeight = hh
this.scale = 1
this.rotation = this.scatter.rotation
resolve(this)
}
2022-10-04 10:51:35 +02:00
image.onerror = (e) => {
2019-03-21 09:57:27 +01:00
reject(this)
}
image.src = cloneURL
2019-07-18 12:26:39 +02:00
})
2019-03-21 09:57:27 +01:00
}
}
export default class FlipEffect {
constructor(scatter, domScatterContainer, flipTemplate, backLoader) {
this.flipped = false
this.scatter = scatter
this.backLoader = backLoader
this.scatterLoader = new ScatterLoader(scatter)
2019-07-30 16:56:29 +02:00
this.domFlip = new DOMFlip(domScatterContainer, flipTemplate, this.scatterLoader, backLoader, {
2022-10-04 10:51:35 +02:00
onBack: this.backCardClosed.bind(this),
2019-07-30 16:56:29 +02:00
})
2019-03-21 09:57:27 +01:00
this.setupInfoButton()
}
startFlip() {
let center = this.flipCenter()
let loader = this.backLoader
2022-10-04 10:51:35 +02:00
this.domFlip.load().then((domFlip) => {
2019-03-21 09:57:27 +01:00
this.scatter.displayObject.visible = false
domFlip.centerAt(center)
domFlip.zoom(this.scatter.scale)
let target = this.constraintFlipCenter(center, loader)
2019-07-18 12:26:39 +02:00
domFlip.start({ targetCenter: target })
2019-03-21 09:57:27 +01:00
})
}
unscaledSize() {
return this.scatterLoader.unscaledSize()
}
flipCenter() {
let isSprite = this.scatter.displayObject instanceof PIXI.Sprite
2019-07-18 12:26:39 +02:00
let resolution = isSprite ? app.renderer.resolution : 1
2019-03-21 09:57:27 +01:00
let center = this.scatter.center
let canvas = app.renderer.view
let domNode = this.domFlip.domScatterContainer.element
2019-07-30 16:56:29 +02:00
let page = window.convertPointFromNodeToPage(canvas, center.x * resolution, center.y * resolution)
2019-03-21 09:57:27 +01:00
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
2019-07-18 12:26:39 +02:00
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
2019-03-21 09:57:27 +01:00
return { x, y }
}
setupInfoButton() {
let iscale = 1.0 / this.scatter.scale
this.infoBtn = new PIXI.Graphics()
this.infoBtn.beginFill(0x333333)
2019-07-18 12:26:39 +02:00
this.infoBtn.lineStyle(4, 0xffffff)
2019-03-21 09:57:27 +01:00
this.infoBtn.drawCircle(0, 0, 22)
this.infoBtn.endFill()
2019-07-18 12:26:39 +02:00
this.infoBtn.beginFill(0xffffff)
2019-03-21 09:57:27 +01:00
this.infoBtn.lineStyle(0)
this.infoBtn.drawCircle(0, -8, 4)
this.infoBtn.endFill()
2019-07-18 12:26:39 +02:00
this.infoBtn.lineStyle(6, 0xffffff)
2019-03-21 09:57:27 +01:00
this.infoBtn.moveTo(0, -2)
this.infoBtn.lineTo(0, 14)
this.infoBtn.endFill()
2022-10-04 10:51:35 +02:00
this.infoBtn.on('click', (e) => {
2019-07-18 12:26:39 +02:00
this.infoSelected()
})
2022-10-04 10:51:35 +02:00
this.infoBtn.on('tap', (e) => {
2019-07-18 12:26:39 +02:00
this.infoSelected()
})
2019-03-21 09:57:27 +01:00
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)
2019-07-18 12:26:39 +02:00
} else {
2019-03-21 09:57:27 +01:00
displayObject.addChild(this.infoBtn)
}
2022-10-04 10:51:35 +02:00
this.scatter.addTransformEventCallback((e) => {
2019-03-21 09:57:27 +01:00
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
2022-10-04 10:51:35 +02:00
svgImage.onload = (e) => {
2019-03-21 09:57:27 +01:00
let displayObject = this.scatter.displayObject
2019-07-30 16:56:29 +02:00
canvas.getContext('2d').drawImage(svgImage, 0, 0, canvas.width, canvas.height)
2019-03-21 09:57:27 +01:00
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)
2019-07-18 12:26:39 +02:00
} else {
2019-03-21 09:57:27 +01:00
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()
2022-10-04 10:51:35 +02:00
this.infoBtn.on('click', (e) => {
2019-07-18 12:26:39 +02:00
this.infoSelected()
})
2022-10-04 10:51:35 +02:00
this.infoBtn.on('tap', (e) => {
2019-07-18 12:26:39 +02:00
this.infoSelected()
})
2019-03-21 09:57:27 +01:00
}
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
2019-07-18 12:26:39 +02:00
if (rest > ortho / 2.0) {
2019-03-21 09:57:27 +01:00
delta = ortho - rest
2019-07-18 12:26:39 +02:00
} else {
2019-03-21 09:57:27 +01:00
delta = -rest
}
return delta
}
}