PageSourceSearch

https://www.perseusfans.com/static/web/style/js/plugs/three/three.js

js perseusfans.com collected 2026-10-09 21:20:04 UTC 5,625 bytes, 204 lines download raw bytes

1
2import {
3  AmbientLight,
4  DirectionalLight,
5  PerspectiveCamera,
6  PointLight,
7  Scene,
8  WebGLRenderer
9} from './build/three.module.min.js'
10import { OrbitControls } from './jsm/controls/OrbitControls.js'
11
12import pointer from './pointer.js'
13export default function (params) {
14  const options = {
15    el: null,
16    canvas: null,
17    eventsEl: null,
18    width: null,
19    height: null,
20    resize: true,
21    alpha: false,
22    antialias: false,
23    orbitControls: false,
24    init () {},
25    initCamera () {},
26    initScene () {},
27    afterResize () {},
28    beforeRender () {},
29    afterRender () {},
30    beforeunload(){},
31    ...params
32  }
33
34  const three = {
35    renderer: null,
36    camera: null,
37    scene: null,
38    pointer: null,
39    width: 0,
40    height: 0,
41    wWidth: 0,
42    wHeight: 0,
43    clock: {
44      startTime: 0,
45      time: 0,
46      elapsed: 0
47    },
48    options
49  }
50
51  let render
52
53  let cameraCtrl
54
55  init()
56  return three
57
58  function init () {
59    let canvas
60    if (options.el) {
61      canvas = document.createElement('canvas')
62      options.el.appendChild(canvas)
63    } else if (options.canvas) {
64      canvas = options.canvas
65    } else {
66      throw new Error('Missing parameter : el or canvas is required')
67    }
68
69    options.init?.(three);
70    three.renderer = new WebGLRenderer({ canvas, alpha: options.alpha, antialias: options.antialias })
71    options.initRenderer?.(three)
72
73    three.camera = new PerspectiveCamera()
74    three.camera.position.z = 50;
75    options.initCamera?.(three)
76    if (options.orbitControls) {
77      cameraCtrl = new OrbitControls(three.camera, options.eventsEl ?? three.renderer.domElement)
78      cameraCtrl.enableDamping = true
79      cameraCtrl.dampingFactor = 0.1
80      if (typeof options.orbitControls === 'object') {
81        Object.keys(options.orbitControls).forEach(key => {
82          cameraCtrl[key] = options.orbitControls[key]
83        })
84      }
85    }
86
87    resize()
88    if (options.resize && !options.width && !options.height) {
89      window.addEventListener('resize', resize)
90    }
91
92    three.scene = new Scene()
93    options.initScene?.(three)
94
95    initPointer()
96
97    render = options.render ? options.render : () => { three.renderer.render(three.scene, three.camera) }
98
99    options.beforeunload?.(three)
100    // requestAnimationFrame(timestamp => {
101    //   three.clock.startTime = three.clock.time = timestamp
102    //   requestAnimationFrame(animate)
103    // })
104    animate();
105    options.afterRender?.(three)
106  }
107  function initPointer () {
108    const pointerOptions = {}
109    if (options.onPointerEnter) { pointerOptions.onEnter = options.onPointerEnter }
110    if (options.onPointerMove) { pointerOptions.onMove = options.onPointerMove }
111    if (options.onPointerMove) { pointerOptions.onLeave = options.onPointerLeave }
112    if (Object.keys(pointerOptions).length > 0) {
113      three.pointer = pointer({ domElement: options.eventsEl ?? (options.el ?? options.canvas), ...pointerOptions })
114    }
115  }
116
117  function animate (timestamp) {
118    const { clock } = three
119    clock.elapsed = timestamp - clock.time
120    clock.time = timestamp
121
122    options.beforeRender(three)
123
124    if (cameraCtrl) cameraCtrl.update()
125
126    render(three)
127    three.animationId = requestAnimationFrame(animate);
128  }
129
130  function resize () {
131    if (options.width && options.height) {
132      three.width = options.width
133      three.height = options.height
134    } else if (options.resize === 'window') {
135      three.width = window.innerWidth
136      three.height = window.innerHeight
137    } else {
138      const parent = three.renderer.domElement.parentElement
139      three.width = parent.clientWidth
140      three.height = parent.clientHeight
141    }
142
143    three.renderer.setSize(three.width, three.height)
144    three.camera.aspect = three.width / three.height
145    three.camera.updateProjectionMatrix()
146    if (three.camera instanceof PerspectiveCamera) {
147      const wsize = getCameraViewSize()
148      three.wWidth = wsize[0]; three.wHeight = wsize[1]
149    } else {
150      three.wWidth = three.camera.top - three.camera.bottom
151      three.wHeight = three.camera.right - three.camera.left
152    }
153    options.afterResize?.(three)
154  }
155
156  function getCameraViewSize () {
157    const vFOV = (three.camera.fov * Math.PI) / 180
158    const h = 2 * Math.tan(vFOV / 2) * Math.abs(three.camera.position.z)
159    const w = h * three.camera.aspect
160    return [w, h]
161  }
162}
163export function commonConfig (params) {
164  const config = {}
165  const keys = ['el', 'canvas', 'eventsEl', 'width', 'height', 'resize', 'orbitControls']
166  keys.forEach(key => {
167    if (params[key] !== undefined) config[key] = params[key]
168  })
169  return config
170}
171
172export function initLights (scene, lightsConfig) {
173  const lights = []
174  if (Array.isArray(lightsConfig) && lightsConfig.length > 0) {
175    let light
176    lightsConfig.forEach(lightConfig => {
177      switch (lightConfig.type) {
178        case 'ambient':
179          light = new AmbientLight(...lightConfig.params)
180          break
181        case 'directional':
182          light = new DirectionalLight(...lightConfig.params)
183          break
184        case 'point':
185          light = new PointLight(...lightConfig.params)
186          break
187        default:
188          console.error(`Unknown light type ${lightConfig.type}`)
189      }
190      if (light) {
191        if (typeof lightConfig.props === 'object') {
192          Object.keys(lightConfig.props).forEach(key => {
193            if (key === 'position') {
194              light.position.set(...lightConfig.props[key])
195            } else light[key] = lightConfig.props[key]
196          })
197        }
198        scene.add(light)
199        lights.push(light)
200      }
201    })
202  }
203  return lights
204}

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.