avansel
Version:
Free OpenSource ThreeJS Javascript Virtual Tours viewer
169 lines (146 loc) • 5.35 kB
text/typescript
import { BoxGeometry, CanvasTexture, Mesh, MeshBasicMaterial, BackSide, ImageLoader } from 'three';
import { pano } from '../../../config.json'
enum ImageType { Sphere, Cylinder, Cubestrip }
enum StripType { Type1x6, Type2x3, Type3x2, Type6x1 }
interface PreviewSettings {
type?: ImageType,
stripType?: StripType
url?: string,
striporder?: string,
size: number
}
const striporderDefault = 'rludfb'
let preview: Mesh
let settings: PreviewSettings
let contexts: Array<CanvasRenderingContext2D> = []
let materials: Array<MeshBasicMaterial> = []
/*
let size, sides = {}
let positions
const format = 'udlrfb'
*/
const colorSide = (side: string) => {
return {
u: '#8888aa',
d: '#88aa88',
l: '#aa8888',
r: '#88aaaa',
f: '#aaaa88',
b: '#aaaaaa',
}[side]
}
const getSides = () => {
const striporder = settings.striporder ?? striporderDefault
return Array.from(striporder)
}
const getCanvas = (side: string) => {
const canvas = document.createElement( 'canvas' )
const size = settings.size ?? 1024
canvas.width = size
canvas.height = size
const context = canvas.getContext("2d")
context.fillStyle = colorSide(side)
context.fillRect(0, 0, size, size)
context.rect(20, 20, size - 40, size - 40)
context.strokeStyle = "#ffffff";
context.stroke();
context.fillStyle = "#ffffff"
context.font = "48px Arial";
context.textAlign = "center"
context.fillText('side: ' + side, size / 2, size / 2)
return canvas
}
const getMaterial = (canvas: HTMLCanvasElement) => {
const texture = new CanvasTexture(canvas)
const material = new MeshBasicMaterial( { map: texture, depthWrite: true } )
material.side = BackSide
material.opacity = 1
material.transparent = true
return material
}
const materialsEmpty = () => {
const materials = []
const sides = getSides()
for(var i = 0; i < sides.length; i ++){
const side = sides[i]
const canvas = getCanvas(side)
contexts.push(canvas.getContext('2d'))
materials.push(getMaterial(canvas))
}
return materials
}
const settingsBy = (img: HTMLImageElement): PreviewSettings => {
const width = img.width
const height = img.height
if(height / width == 6){
if(!settings.type) settings.type = ImageType.Cubestrip
if(!settings.stripType) settings.stripType = StripType.Type1x6
if(!settings.size) settings.size = width
}else if(height / width == 1.5){
if(!settings.type) settings.type = ImageType.Cubestrip
if(!settings.stripType) settings.stripType = StripType.Type2x3
if(!settings.size) settings.size = width / 2
}else if(width / height == 1.5){
if(!settings.type) settings.type = ImageType.Cubestrip
if(!settings.stripType) settings.stripType = StripType.Type3x2
if(!settings.size) settings.size = height / 2
}else if(width / height == 6){
if(!settings.type) settings.type = ImageType.Cubestrip
if(!settings.stripType) settings.stripType = StripType.Type6x1
if(!settings.size) settings.size = height
}else if(width / height == 2){
if(!settings.type) settings.type = ImageType.Sphere
}
if(!settings.type) settings.type = ImageType.Cylinder
if(!settings.size) settings.size = pano.tileBase
return settings
}
const onImageLoad = (img: HTMLImageElement) => {
const sides = Array.from(striporderDefault)
const materials = []
const size = settings.size
settings = settingsBy(img)
for(var i = 0; i < sides.length; i ++){
const side = sides[i]
const index = settings.striporder.indexOf(sides[i])
const canvas = getCanvas(side)
const context = canvas.getContext('2d')
context.drawImage( img, 0, size * index, size, size, 0, 0, size, size )
materials.push(getMaterial(canvas))
}
return materials
}
const onError = (e: ErrorEvent) => {
console.log(e)
}
const load = async (src: string): Promise<HTMLImageElement> => {
const loader = new ImageLoader()
return new Promise<HTMLImageElement>((resolve, reject) => {
loader.load(src, img => resolve(img), undefined, e => reject(e))
})
}
async function createPreview(data: PreviewSettings): Promise<Mesh> {
settings = data
return new Promise<Mesh>((resolve, reject) => {
const boxSize = pano.tileBase + pano.maxLevels + 1
const geometry = new BoxGeometry(boxSize, boxSize, boxSize)
if(settings.url || settings.type){
if(!settings.type){
load('/tiles/preview.jpg').then(img => {
materials = onImageLoad(img)
preview = new Mesh(geometry, materials);
preview.scale.x = -1
preview.renderOrder = 1
resolve(preview)
})
}
}else{
materials = materialsEmpty()
preview = new Mesh(geometry, materials);
preview.scale.x = -1
preview.renderOrder = 1
resolve(preview)
}
})
}
export { createPreview };