uix-kit
Version:
A free web kits for fast web design and development, compatible with Bootstrap v5.
482 lines (317 loc) • 12.6 kB
JavaScript
/*
*************************************
* <!-- Simulate HTML Layout with threejs -->
*************************************
*/
import {
UixModuleInstance,
UixDebounce,
UixThrottle
} from '@uixkit/core/_global/js';
export const THREE_SIMULATE_HTML_LAYOUT = ( ( module, $, window, document ) => {
if ( window.THREE_SIMULATE_HTML_LAYOUT === null ) return false;
module.THREE_SIMULATE_HTML_LAYOUT = module.THREE_SIMULATE_HTML_LAYOUT || {};
module.THREE_SIMULATE_HTML_LAYOUT.version = '0.0.4';
module.THREE_SIMULATE_HTML_LAYOUT.documentReady = function( $ ) {
//Prevent this module from loading in other pages
if ( $( '#app-3D-page-container' ).length == 0 || ! Modernizr.webgl ) return false;
//=====================================================================================
//=====================================================================================
//==============================THREE.js===============================================
//=====================================================================================
//=====================================================================================
//=====================================================================================
//scroll spy
let scrollY = 0;
let touchStartY = 0;
const _event = {
y: 0,
deltaY: 0
};
const scrollTrigger = document.getElementById( 'app-3D-page-container' );
const maxHeight = (scrollTrigger.clientHeight || scrollTrigger.offsetHeight) - window.innerHeight;
// THREE PARAMS
//-------------------------------------
let camera = null,
scene = null,
renderer;
let clock = new THREE.Clock(), time = 0;
const dataBGSources = [];
// Loader manager
const loadingManager = new THREE.LoadingManager();
loadingManager.onLoad = function() {
//console.log( '▶▶▶▶▶ Loading complete! ◀◀◀◀◀◀' );
};
loadingManager.onProgress = function ( item, loaded, total ) {
//console.log( '▶▶▶▶▶ LoadingManager ◀◀◀◀◀◀ ( item: '+item+', loaded: '+loaded+', total: '+total+')' );
};
loadingManager.onError = function(url) {
console.log( '▶▶▶▶▶ There was an error loading ◀◀◀◀◀◀ ' + url );
};
const loaderImage = new THREE.TextureLoader(loadingManager);
loaderImage.crossOrigin = 'anonymous';
function SubStageInit( $rendererInnerCanvas, wrapperHeight, wrapperWidth, offsetLeft ) {
console.log( 'wrapperHeight: ' + wrapperHeight );
//=================
//camera
camera = new THREE.OrthographicCamera( - wrapperWidth / wrapperHeight / 2, wrapperWidth / wrapperHeight / 2, 1 / 2, -1 / 2, -0.1, 0.1);
camera.position.set( 0, 0, 0 );
camera.lookAt(new THREE.Vector3(0, 0, 0));
//=================
//Scene
scene = new THREE.Scene();
//=================
//WebGL Renderer
renderer = new THREE.WebGLRenderer( {
alpha : true,
antialias: true
} );
renderer.setSize( wrapperWidth, wrapperHeight );
renderer.shadowMap = true;
renderer.shadowMapSoft = true;
$rendererInnerCanvas[0].appendChild( renderer.domElement );
//=================
// Immediately use the texture for material creation
let i = 0;
//update image data
document.querySelectorAll('.app-coverWebgl ~ img').forEach(function( thisImg ) {
dataBGSources.forEach(function (item, i) {
if ( item.url.indexOf( thisImg.src ) >= 0 || thisImg.src == item.url ) {
item.visibleWidth = thisImg.width;
item.visibleHeight = thisImg.height;
item.top = thisImg.getBoundingClientRect().top;
item.left = thisImg.getBoundingClientRect().left;
}
});
});
console.log( dataBGSources );
document.querySelectorAll('.app-coverWebgl').forEach(function( thisImg ) {
const _curURL = thisImg.getAttribute('data-url');
let ratio;
//
(function(index) {
window['tex' + i] = loaderImage.load( _curURL );
window['tex' + i].anisotropy = renderer.capabilities.getMaxAnisotropy();
})(i);
//
dataBGSources.forEach(function (item, i) {
if ( item.url.indexOf( _curURL ) >= 0 || _curURL == item.url ) {
ratio = wrapperWidth/wrapperHeight;
const _offsetLeft = offsetLeft/wrapperWidth * ratio;
window['geometry' + i] = new THREE.BoxGeometry(item.visibleWidth / wrapperHeight, item.visibleHeight / wrapperHeight, 40 / wrapperHeight);
window['tex' + i].wrapS = window['tex' + i].wrapT = THREE.RepeatWrapping;
window['materiel' + i] = new THREE.MeshBasicMaterial({
map: window['tex' + i]
});
window['materiel' + i].map.minFilter = THREE.LinearFilter;
window['mesh' + i] = new THREE.Mesh(window['geometry' + i], window['materiel' + i]);
window['mesh' + i].material.transparent = true;
window['mesh' + i].position.y = -(item.top + item.visibleHeight / 2) / wrapperHeight + 0.5; // car origine repere est au centre du view
window['mesh' + i].position.x = (item.left * ratio + item.visibleWidth * ratio / 2) / wrapperWidth - 0.5 * ratio - _offsetLeft; // car origine repere est au centre du view
//
scene.add(window['mesh' + i]);
//console.log( window['mesh' + i] );
}
});
i++;
});
//=================
// Add function to the window that should be resized
const debounceFuncWindow = UixDebounce(function(){
windowUpdate(wrapperWidth,wrapperHeight);
}, 50);
window.removeEventListener('resize', debounceFuncWindow);
window.addEventListener('resize', debounceFuncWindow);
//=================
// Add function to the element that should be used as the scrollable area.
const throttleFunc = UixThrottle(scrollUpdate, 5);
scrollTrigger.removeEventListener('scroll', throttleFunc);
scrollTrigger.removeEventListener('touchmove', throttleFunc);
scrollTrigger.addEventListener('scroll', throttleFunc);
scrollTrigger.addEventListener('touchmove', throttleFunc);
throttleFunc();
/*
mobile example:
scrollTrigger.addEventListener('touchstart', onTouchStart);
scrollTrigger.addEventListener('touchmove', onTouchMove);
*/
}
function SubStageRender() {
requestAnimationFrame( SubStageRender );
//To set a background color.
//renderer.setClearColor( 0x000000 );
var delta = clock.getDelta();
//objects animation
dataBGSources.forEach(function (item, i) {
window['mesh' + i].rotation.y = 0.01 * scrollY;
window['mesh' + i].rotation.x = 0.004 * scrollY;
});
//render the scene to display our scene through the camera's eye.
renderer.render( scene, camera );
}
function windowUpdate(w,h) {
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
}
//Destroy the 3D rendering process
function destroy3DScene() {
console.log( 'Destroy the 3D rendering process!' );
//Clear the animations and scenes
//------
cancelAnimationFrame( SubStageRender );
scene.remove();
//Clear the renderer cache, no need to use in this demo
//------
renderer.dispose();
renderer.forceContextLoss();
renderer.content = null;
renderer.domElement = null;
//Clear the cache of the current obj object
//------
const cleanMaterial = function( material ) {
//console.log('dispose material!')
material.dispose();
// dispose textures
for (const key of Object.keys(material)) {
const value = material[key];
if (value && typeof value === 'object' && 'minFilter' in value) {
//console.log('dispose texture!')
value.dispose();
}
}
};
scene.traverse(object => {
if (!object.isMesh) return;
//console.log('dispose geometry!');
object.geometry.dispose();
if (object.material.isMaterial) {
cleanMaterial(object.material);
} else {
// an array of materials
for (const material of object.material) cleanMaterial(material);
}
});
}
//=====================================================================================
//=====================================================================================
//===================================SCROLL ANIMATION==================================
//=====================================================================================
//=====================================================================================
//=====================================================================================
function scrollUpdate(e) {
scrollY = scrollTrigger.scrollTop;
console.log(scrollTrigger.scrollTop);
};
/*
mobile example
function onTouchStart (e) {
var t = (e.targetTouches) ? e.targetTouches[0] : e;
touchStartY = t.pageY;
};
function onTouchMove (e) {
var evt = _event;
var t = (e.targetTouches) ? e.targetTouches[0] : e;
evt.deltaY = (t.pageY - touchStartY) * 5;
touchStartY = t.pageY;
};*/
//=====================================================================================
//=====================================================================================
//===================================IMAGES LOADER====================================
//=====================================================================================
//=====================================================================================
//=====================================================================================
const sources = [];
//Push all images from page
$( 'section' ).find( 'img' ).each(function() {
sources.push(
{
"url": this.src,
"type": 'img'
}
);
//
dataBGSources.push( {w: 0, h: 0,visibleWidth: 0, visibleHeight: 0, top: 0, left: 0, url: this.src } );
});
//===========
const loadImages = function() {
const promises = [];
for (let i = 0; i < sources.length; i++) {
if ( sources[i].type == 'img' ) {
///////////
// IMAGE //
///////////
promises.push(
new Promise(function(resolve, reject) {
const img = new Image();
img.src = sources[i].url;
img.onload = function(image) {
//Compatible with safari and firefox
if ( typeof image.path === typeof undefined ) {
return resolve( {
w: 0,
h: 0,
url: image.target.currentSrc
} );
} else {
return resolve( {
w: image.path[0].naturalWidth,
h: image.path[0].naturalHeight,
url: image.path[0].currentSrc
} );
}
};
}).then( textureLoaded )
);
}
}
return Promise.all(promises);
};
let k = 0;
const textureLoaded = function( data ) {
//console.log( data );
const _curURL = data.url;
const _curW = data.w;
const _curH = data.h;
//update image data
dataBGSources.forEach(function (item, i) {
if ( _curURL.indexOf( item.url ) >= 0 || _curURL == item.url ) {
item.w = _curW;
item.h = _curH;
}
});
k++;
return k;
};
//============
//images loaded
//Must be placed behind the loadImages()
loadImages().then( function( images ) {
console.log( '------images loaded!------' );
//in order to calculate a correct height for all images
setTimeout( function() {
//Run 3D rendering process
const $innerCanvas = $( '#app-3D-page-container' ).find( '.app-innerCanvas' );
const canvasPosOffsetX = 15;
const canvasPosOffsetY = -$( '#app-3D-page-container' )[0].getBoundingClientRect().top;
$innerCanvas.css({
'position': 'absolute',
'z-index': '-1',
'left': 0,
'top': canvasPosOffsetY
});
if ( $innerCanvas.length > 0 ) {
SubStageInit( $innerCanvas, $( '#app-3D-page-container' ).find( '.app-work-detail__wrapper' ).outerHeight( true ), $( '#app-3D-page-container' ).find( '.app-work-detail__wrapper' ).outerWidth( true ), $( '#app-3D-page-container' ).find( '.app-work-detail__wrapper' ).offset().left - canvasPosOffsetX );
SubStageRender();
}
$( '#app-3D-page-container' ).css( 'overflow-y', 'auto' );
}, 500 );
});
};
module.components.documentReady.push( module.THREE_SIMULATE_HTML_LAYOUT.documentReady );
return class THREE_SIMULATE_HTML_LAYOUT {
constructor() {
this.module = module;
}
};
})( UixModuleInstance, jQuery, window, document );