versione 0.8
This commit is contained in:
+563
@@ -0,0 +1,563 @@
|
||||
import { gsap } from 'gsap';
|
||||
|
||||
var APP = {
|
||||
|
||||
Player: function (canvas_container) {
|
||||
|
||||
var renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
|
||||
var loader = new THREE.ObjectLoader();
|
||||
var camera, scene;
|
||||
|
||||
var events = {};
|
||||
const markers = [];
|
||||
|
||||
var controls = null;
|
||||
|
||||
var dom = document.getElementById(canvas_container);
|
||||
|
||||
//var dom = document.createElement( 'div' );
|
||||
dom.appendChild(renderer.domElement);
|
||||
|
||||
this.dom = dom;
|
||||
this.canvas = renderer.domElement;
|
||||
|
||||
this.width = dom.innerWidth;
|
||||
this.height = dom.innerHeight;
|
||||
|
||||
this.load = function (json) {
|
||||
|
||||
var project = json.project;
|
||||
|
||||
if (project.shadows !== undefined) renderer.shadowMap.enabled = project.shadows;
|
||||
if (project.shadowType !== undefined) renderer.shadowMap.type = project.shadowType;
|
||||
if (project.toneMapping !== undefined) renderer.toneMapping = project.toneMapping;
|
||||
if (project.toneMappingExposure !== undefined) renderer.toneMappingExposure = project.toneMappingExposure;
|
||||
|
||||
this.setScene(loader.parse(json.scene));
|
||||
this.setCamera(loader.parse(json.camera));
|
||||
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
controls.minPolarAngle = THREE.MathUtils.degToRad(90);
|
||||
controls.maxPolarAngle = THREE.MathUtils.degToRad(90);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.1;
|
||||
|
||||
controls.minDistance = 1.2;
|
||||
controls.maxDistance = 20;
|
||||
|
||||
|
||||
controls.addEventListener('change', function () {
|
||||
renderer.render(scene, camera);
|
||||
|
||||
});
|
||||
|
||||
events = {
|
||||
init: [],
|
||||
start: [],
|
||||
stop: [],
|
||||
keydown: [],
|
||||
keyup: [],
|
||||
pointerdown: [],
|
||||
pointerup: [],
|
||||
pointermove: [],
|
||||
update: []
|
||||
};
|
||||
|
||||
var scriptWrapParams = 'player,renderer,scene,camera';
|
||||
var scriptWrapResultObj = {};
|
||||
|
||||
for (var eventKey in events) {
|
||||
|
||||
scriptWrapParams += ',' + eventKey;
|
||||
scriptWrapResultObj[eventKey] = eventKey;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
var scriptWrapResult = JSON.stringify(scriptWrapResultObj).replace(/\"/g, '');
|
||||
|
||||
for (var uuid in json.scripts) {
|
||||
|
||||
var object = scene.getObjectByProperty('uuid', uuid, true);
|
||||
|
||||
if (object === undefined) {
|
||||
|
||||
console.warn('APP.Player: Script without object.', uuid);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
var scripts = json.scripts[uuid];
|
||||
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
|
||||
var script = scripts[i];
|
||||
|
||||
var functions = (new Function(scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';').bind(object))(this, renderer, scene, camera);
|
||||
|
||||
for (var name in functions) {
|
||||
|
||||
if (functions[name] === undefined) continue;
|
||||
|
||||
if (events[name] === undefined) {
|
||||
|
||||
console.warn('APP.Player: Event type not supported (', name, ')');
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
events[name].push(functions[name].bind(object));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispatch(events.init, arguments);
|
||||
|
||||
};
|
||||
|
||||
this.addToScene = function (object) {
|
||||
scene.add(object);
|
||||
}
|
||||
|
||||
this.swapModel = function (model_name) {
|
||||
|
||||
let found = false;
|
||||
|
||||
scene.traverse((mod) => {
|
||||
if (mod.userData.name == model_name) {
|
||||
mod.visible = true;
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
if (mod.name == 'infisso')
|
||||
mod.visible = false;
|
||||
}
|
||||
});
|
||||
|
||||
renderer.render(scene, camera);
|
||||
return found;
|
||||
}
|
||||
|
||||
this.hideModel = function (model_name) {
|
||||
let modello = scene.getObjectByName(model_name);
|
||||
modello.visible = false;
|
||||
}
|
||||
|
||||
this.viewFrontSide = function () {
|
||||
camera.position.set(0, 0, 0.7);
|
||||
const box = new THREE.Box3().setFromObject(scene);
|
||||
|
||||
const size = box.getSize(new THREE.Vector3());
|
||||
const center = box.getCenter(new THREE.Vector3());
|
||||
|
||||
const maxDim = Math.max(size.x, size.y, size.z);
|
||||
|
||||
const fov = camera.fov * (Math.PI / 180);
|
||||
const cameraZ = Math.abs(maxDim / (2 * Math.tan(fov / 2))) / 0.4;
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(camera.position, center).normalize();
|
||||
camera.position.copy(center).add(direction.multiplyScalar(cameraZ));
|
||||
|
||||
camera.lookAt(center);
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
this.flipView = function () {
|
||||
if (!scene || !camera) return;
|
||||
|
||||
const box = new THREE.Box3().setFromObject(scene);
|
||||
const center = box.getCenter(new THREE.Vector3());
|
||||
const size = box.getSize(new THREE.Vector3());
|
||||
|
||||
const maxDim = Math.max(size.x, size.y, size.z);
|
||||
const fov = camera.fov * (Math.PI / 180);
|
||||
const cameraZ = Math.abs(maxDim / (2 * Math.tan(fov / 2))) / 0.4;
|
||||
|
||||
const radius = cameraZ;
|
||||
const duration = 1;
|
||||
|
||||
|
||||
const startAngle = scene.rotation.y
|
||||
|
||||
const endAngle = startAngle + Math.PI; // Angolo finale (180 gradi in radianti)
|
||||
|
||||
|
||||
gsap.to(camera.position, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: cameraZ,
|
||||
duration: duration,
|
||||
ease: "power1.inOut",
|
||||
onUpdate: () => {
|
||||
//camera.lookAt(center); // Mantieni la camera puntata verso il centro
|
||||
},
|
||||
onComplete: () => {
|
||||
//controls.update(); // Aggiorna i controlli al termine dell'animazione
|
||||
}
|
||||
});
|
||||
|
||||
gsap.to(scene.rotation, {
|
||||
y: scene.rotation.y + Math.PI,
|
||||
duration: duration,
|
||||
ease: "power1.inOut",
|
||||
onUpdate: () => {
|
||||
renderer.render(scene, camera); // Render the scene during the animation
|
||||
},
|
||||
onComplete: () => {
|
||||
//controls.update(); // Update controls after the animation
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.moveCameraToFront = function (objectName) {
|
||||
if (!scene || !camera) return;
|
||||
|
||||
// Trova l'oggetto nella scena
|
||||
const object = scene.getObjectByName(objectName);
|
||||
if (!object) {
|
||||
console.warn(`Oggetto con nome "${objectName}" non trovato.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ottieni la posizione dell'oggetto
|
||||
const targetPosition = object.getWorldPosition(new THREE.Vector3());
|
||||
|
||||
// Calcola la nuova posizione della telecamera (davanti all'oggetto)
|
||||
const offset = new THREE.Vector3(0, 0, -2); // Offset per posizionare la telecamera davanti
|
||||
const newCameraPosition = targetPosition.clone().add(offset);
|
||||
|
||||
// Anima la posizione della telecamera con GSAP
|
||||
gsap.to(camera.position, {
|
||||
x: newCameraPosition.x,
|
||||
y: newCameraPosition.y,
|
||||
z: newCameraPosition.z,
|
||||
duration: 1.5, // Durata dell'animazione in secondi
|
||||
ease: "power1.inOut",
|
||||
onUpdate: () => {
|
||||
camera.lookAt(targetPosition); // Mantieni la telecamera puntata verso l'oggetto
|
||||
},
|
||||
onComplete: () => {
|
||||
controls.update(); // Aggiorna i controlli al termine dell'animazione
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.setCamera = function (value) {
|
||||
|
||||
camera = value;
|
||||
camera.aspect = this.width / this.height;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
};
|
||||
|
||||
this.setScene = function (value) {
|
||||
scene = value;
|
||||
};
|
||||
|
||||
this.rotateBackground = function (radians) {
|
||||
scene.backgroundRotation.y = radians;
|
||||
scene.environmentRotation.y = radians;
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
this.setPixelRatio = function (pixelRatio) {
|
||||
|
||||
renderer.setPixelRatio(pixelRatio);
|
||||
|
||||
};
|
||||
|
||||
this.setSize = function (width, height) {
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
if (camera) {
|
||||
|
||||
camera.aspect = this.width / this.height;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
}
|
||||
|
||||
renderer.setSize(width, height);
|
||||
|
||||
};
|
||||
|
||||
function dispatch(array, event) {
|
||||
|
||||
for (var i = 0, l = array.length; i < l; i++) {
|
||||
|
||||
array[i](event);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var time, startTime, prevTime;
|
||||
|
||||
function animate() {
|
||||
|
||||
time = performance.now();
|
||||
|
||||
try {
|
||||
|
||||
dispatch(events.update, { time: time - startTime, delta: time - prevTime });
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.error((e.message || e), (e.stack || ''));
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (controls.update()) {
|
||||
renderer.render(scene, camera);
|
||||
updateMarkers();
|
||||
prevTime = time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.play = function () {
|
||||
|
||||
startTime = prevTime = performance.now();
|
||||
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
document.addEventListener('keyup', onKeyUp);
|
||||
document.addEventListener('pointerdown', onPointerDown);
|
||||
document.addEventListener('pointerup', onPointerUp);
|
||||
document.addEventListener('pointermove', onPointerMove);
|
||||
|
||||
dispatch(events.start, arguments);
|
||||
|
||||
renderer.setAnimationLoop(animate);
|
||||
|
||||
};
|
||||
|
||||
this.stop = function () {
|
||||
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
document.removeEventListener('keyup', onKeyUp);
|
||||
document.removeEventListener('pointerdown', onPointerDown);
|
||||
document.removeEventListener('pointerup', onPointerUp);
|
||||
document.removeEventListener('pointermove', onPointerMove);
|
||||
|
||||
dispatch(events.stop, arguments);
|
||||
|
||||
renderer.setAnimationLoop(null);
|
||||
|
||||
};
|
||||
|
||||
this.render = function (time) {
|
||||
|
||||
dispatch(events.update, { time: time * 1000, delta: 0 /* TODO */ });
|
||||
|
||||
renderer.render(scene, camera);
|
||||
|
||||
};
|
||||
|
||||
this.dispose = function () {
|
||||
|
||||
renderer.dispose();
|
||||
|
||||
camera = undefined;
|
||||
scene = undefined;
|
||||
|
||||
};
|
||||
|
||||
this.showObject = (name) => {
|
||||
scene.traverse((object) => {
|
||||
if (object.isMesh) {
|
||||
if (object.userData.categoria == name) {
|
||||
object.visible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.hideObject = (name) => {
|
||||
scene.traverse((object) => {
|
||||
if (object.isMesh) {
|
||||
if (object.userData.categoria == name) {
|
||||
object.visible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.addMarker = (name, popup_position, video_url) => {
|
||||
const object = scene.getObjectByName(name);
|
||||
const position = object.getWorldPosition(new THREE.Vector3());
|
||||
|
||||
const markerContainer = document.getElementById('markerContainer');
|
||||
const marker = document.createElement('div');
|
||||
marker.className = 'marker';
|
||||
markerContainer.appendChild(marker);
|
||||
|
||||
const popup = document.createElement('div');
|
||||
popup.className = 'popup';
|
||||
popup.style.display = 'none';
|
||||
popup.innerHTML = `
|
||||
<iframe width="100%" height="100%" src="${video_url}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>`;
|
||||
|
||||
popup.classList.add(popup_position);
|
||||
popup.dataset.position = popup_position;
|
||||
|
||||
marker.appendChild(popup);
|
||||
object.visible = false;
|
||||
|
||||
marker.onclick = () => {
|
||||
if (popup.style.display == 'none') {
|
||||
popup.style.display = 'block';
|
||||
} else {
|
||||
popup.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
markers.push({ element: marker, position: position });
|
||||
}
|
||||
|
||||
this.changeXscale = (name, scale) => {
|
||||
let infisso = scene.getObjectByName(name);
|
||||
scene.traverse((object) => {
|
||||
if (object.name == name) {
|
||||
object.scale.x = scale;
|
||||
}
|
||||
});
|
||||
//infisso.scale.x = scale;
|
||||
}
|
||||
|
||||
this.changeTexture = async (data) => {
|
||||
|
||||
let texture = null;
|
||||
let bump = null;
|
||||
|
||||
texture = data.texture_map ? await new THREE.TextureLoader().loadAsync(`./assets/data/immagini/${window.sistema}/${data.folder}/${data.texture_folder}/${data.id}/${data.texture_map}`) : null;
|
||||
bump = data.texture_bump ? await new THREE.TextureLoader().loadAsync(`./assets/data/immagini/${window.sistema}/${data.folder}/${data.texture_folder}/${data.id}/${data.texture_bump}`) : null;
|
||||
|
||||
// A newer selection for this same group may have been made while the texture above was loading.
|
||||
// Discard this stale result so the last user/init action always wins, regardless of load order.
|
||||
if (data.isStale && data.isStale()) return;
|
||||
|
||||
scene.traverse((object) => {
|
||||
if (object.isMesh) {
|
||||
if (data.categories.includes(object.userData.categoria)) {
|
||||
|
||||
object.material.map = null;
|
||||
object.material.bumpMap = null;
|
||||
if (texture != null) {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
object.material.map = texture;
|
||||
}
|
||||
|
||||
if (bump != null) {
|
||||
bump.colorSpace = THREE.NoColorSpace;
|
||||
object.material.bumpMap = bump;
|
||||
}
|
||||
|
||||
object.material.needsUpdate = true;
|
||||
if (data.roughness_valore != "") object.material.roughness = data.roughness_valore;
|
||||
if (data.metalness_valore != "") object.material.metalness = data.metalness_valore;
|
||||
if (data.opacity_valore != "") object.material.opacity = data.opacity_valore;
|
||||
if (data.bump_valore != "") object.material.bumpScale = data.bump_valore;
|
||||
//if(data.color_valore != "") object.material.color.setHex(parseInt(data.color_valore.replace("#", "0x")));
|
||||
if (data.color_valore != "") object.material.color = new THREE.Color(data.color_valore);
|
||||
|
||||
object.material.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
this.changeColor = async (data) => {
|
||||
if (data.color_valore_corpo_base != "") {
|
||||
scene.traverse((object) => {
|
||||
if (object.isMesh) {
|
||||
if (data.categories.includes(object.userData.categoria)) {
|
||||
|
||||
object.material.color = new THREE.Color(data.color_valore_corpo_base);
|
||||
|
||||
object.material.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const updateMarkers = () => {
|
||||
markers.forEach(marker => {
|
||||
const vector = new THREE.Vector3(marker.position.x, marker.position.y, marker.position.z);
|
||||
vector.project(camera);
|
||||
const popup = marker.element.querySelector('.popup');
|
||||
if (camera.rotation.y < 0) {
|
||||
if (popup.dataset.position == 'right') {
|
||||
popup.classList.add('left');
|
||||
popup.classList.remove('right');
|
||||
} else {
|
||||
popup.classList.add('right');
|
||||
popup.classList.remove('left');
|
||||
}
|
||||
|
||||
} else {
|
||||
if (popup.dataset.position == 'right') {
|
||||
|
||||
popup.classList.add('right');
|
||||
popup.classList.remove('left');
|
||||
} else {
|
||||
popup.classList.add('left');
|
||||
popup.classList.remove('right');
|
||||
}
|
||||
}
|
||||
const x = (vector.x * 0.5 + 0.5) * dom.clientWidth;
|
||||
const y = (vector.y * -0.5 + 0.5) * dom.clientHeight;
|
||||
|
||||
marker.element.style.left = `${x}px`;
|
||||
marker.element.style.top = `${y}px`;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function onKeyDown(event) {
|
||||
|
||||
dispatch(events.keydown, event);
|
||||
|
||||
}
|
||||
|
||||
function onKeyUp(event) {
|
||||
|
||||
dispatch(events.keyup, event);
|
||||
|
||||
}
|
||||
|
||||
function onPointerDown(event) {
|
||||
dispatch(events.pointerdown, event);
|
||||
|
||||
}
|
||||
|
||||
function onPointerUp(event) {
|
||||
|
||||
dispatch(events.pointerup, event);
|
||||
|
||||
}
|
||||
|
||||
function onPointerMove(event) {
|
||||
|
||||
dispatch(events.pointermove, event);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export { APP };
|
||||
@@ -0,0 +1,187 @@
|
||||
let shared_data = null;
|
||||
|
||||
const Configurator = {
|
||||
init: (priceCalculator, config_data) => {
|
||||
Configurator.priceCalculator = priceCalculator;
|
||||
shared_data = config_data;
|
||||
},
|
||||
enable: () => {
|
||||
$(("#larghezza, #altezza, select, input[name=vetro], input[type=radio]")).on('input', (e) => {
|
||||
|
||||
|
||||
Configurator.checkTextures()
|
||||
|
||||
let res = Configurator.generatePrice();
|
||||
|
||||
if(res == null) return;
|
||||
|
||||
res = Configurator.generateConfigData(res);
|
||||
|
||||
$(".prezzo").html(`€ ${res.prezzo.toFixed(2)}<span>IVA Inclusa</span>`);
|
||||
window.configurazione = res;
|
||||
|
||||
if($(e.target).data('model')){
|
||||
caricaModello($(e.target).data('model'));
|
||||
}
|
||||
});
|
||||
},
|
||||
generatePrice: () => {
|
||||
|
||||
const config_data = {};
|
||||
config_data.height = $('#altezza').val();
|
||||
config_data.width = $('#larghezza').val();
|
||||
config_data.finitura = $('#prezzi_finiture').val();
|
||||
config_data.percentuale_accessori = 0;
|
||||
|
||||
$('input.percentuale:checked').each((i, el) => {
|
||||
let perc = $(el).data('percentuale');
|
||||
|
||||
perc = perc == undefined ? 0 : parseFloat(perc);
|
||||
perc = isNaN(perc) ? 0 : perc;
|
||||
config_data.percentuale_accessori += (perc / 100);
|
||||
if($(el).hasClass('check_finitura')){
|
||||
|
||||
config_data.override_supplemento_finitura = true;
|
||||
}
|
||||
});
|
||||
//config_data.finitura_interna = $('input[name=finitura_interna]:checked').val();
|
||||
//config_data.finitura_esterna = $('input[name=finitura_esterna]:checked').val();
|
||||
config_data.maniglia = $('input[name=maniglia]:checked').val();
|
||||
|
||||
//config_data.finitura_cassonetto = $('input[name=cassonetto]:checked').val();
|
||||
config_data.finitura_avvolgibile = $('input[name=avvolgibile]:checked').val();
|
||||
|
||||
config_data.vetro = $('input[name=vetro]:checked').val();
|
||||
config_data.cerniere_scomparsa = $('.cerniere_a_scomparsa').val();
|
||||
config_data.altezza_maniglia = $('.altezza_maniglia').val();
|
||||
config_data.azionamento = $('.azionamento').val();
|
||||
config_data.tipo_ispezione = $('.tipo_ispezione').val();
|
||||
config_data.apertura_portoncino = $('.apertura_portoncino option:selected').text();
|
||||
config_data.tipo_ispezione = $('.tipo_ispezione option:selected').text();
|
||||
|
||||
let price = Configurator.priceCalculator.getGridPrice(config_data.width, config_data.height);
|
||||
|
||||
if(price < 0){
|
||||
$(".errore-misure-cnt").removeClass('d-none');
|
||||
$(".prezzo").addClass('invisible');
|
||||
$(".cart-button").addClass('disabled');
|
||||
}else{
|
||||
$(".errore-misure-cnt").addClass('d-none');
|
||||
$(".prezzo").removeClass('invisible');
|
||||
$(".cart-button").removeClass('disabled');
|
||||
}
|
||||
|
||||
config_data.prezzo_base = price;
|
||||
|
||||
const config = Configurator.priceCalculator.getConfigurationPrice(config_data);
|
||||
config.configurazione.height = config_data.height;
|
||||
config.configurazione.width = config_data.width;
|
||||
config.configurazione.nome = shared_data.nome_esteso;
|
||||
|
||||
if(config_data.apertura_portoncino != "")
|
||||
config.configurazione.apertura_portoncino = config_data.apertura_portoncino;
|
||||
|
||||
if(config_data.tipo_ispezione != "")
|
||||
config.configurazione.tipo_ispezione = config_data.tipo_ispezione;
|
||||
|
||||
return config;
|
||||
},
|
||||
generateConfigData: (config) =>{
|
||||
let input_finiture = $(`.finitura input[type=radio]:checked`);
|
||||
|
||||
//console.log(input_finiture);
|
||||
input_finiture.each((i, el) => {
|
||||
let id_finitura = $(el).val();
|
||||
let nome_finitura = $(el).attr('name');
|
||||
let finitura = shared_data.data_finiture.find(f => f.id == id_finitura);
|
||||
config.configurazione[nome_finitura] = finitura.descrizione;
|
||||
});
|
||||
|
||||
//se è un cassonetto
|
||||
if(shared_data.data_avvolgibile != null && shared_data.data_avvolgibile.length > 0){
|
||||
|
||||
let id_avvolgibile = $(`input[name=avvolgibile]:checked`).val();
|
||||
let avvolgibile = shared_data.data_avvolgibile.find(a => a.id == id_avvolgibile);
|
||||
config.configurazione.avvolgibile = avvolgibile.descrizione;
|
||||
|
||||
let id_cassonetto = $(`input[name=avvolgibile]:checked`).val();
|
||||
let cassonetto = shared_data.data_finiture.find(a => a.id == id_cassonetto);
|
||||
config.configurazione.cassonetto = cassonetto.descrizione;
|
||||
|
||||
}
|
||||
|
||||
let val_maniglia = $(`input[name=maniglia]:checked`).val();
|
||||
let finitura_maniglia = shared_data.data_maniglie.find(m => m.id == val_maniglia);
|
||||
let altezza = parseFloat(config.configurazione.height);
|
||||
let mod_altezza = altezza % 10;
|
||||
|
||||
if(mod_altezza > 0) altezza = (altezza - mod_altezza) + 10;
|
||||
|
||||
let altezza_maniglia = shared_data.altezza_maniglia.find((m) => m.altezza == altezza);
|
||||
|
||||
if(altezza_maniglia != null){
|
||||
config.configurazione.altezza_maniglia = altezza_maniglia.altezza_maniglia;
|
||||
}
|
||||
|
||||
if(altezza_maniglia == null && shared_data.altezza_maniglia.length > 0){
|
||||
config.configurazione.altezza_maniglia = shared_data.altezza_maniglia[0];
|
||||
}
|
||||
|
||||
if(finitura_maniglia != null)
|
||||
config.configurazione.maniglia = finitura_maniglia.descrizione;
|
||||
|
||||
$('input.auto-radio:checked').each((i, el) => {
|
||||
|
||||
let nome = $(el).attr('name');
|
||||
if($(`.${nome}`).hasClass('d-none')) return;
|
||||
config.configurazione[nome] = $(el).val();
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
checkTextures: () =>{
|
||||
|
||||
let $interna = $("input[name=finitura_interna]:checked");
|
||||
let $esterna = $("input[name=finitura_esterna]:checked");
|
||||
|
||||
let interna = $interna.val();
|
||||
// modelli senza rivestimento esterno separato (tipo 'uniforme'): segue l'interno
|
||||
let esterna = $esterna.length ? $esterna.val() : interna;
|
||||
let internaPredefinita = $interna.data('predefinito') === true;
|
||||
let tipo = $interna.data('tipo');
|
||||
let percentuale = $interna.data('percentuale');
|
||||
|
||||
// bianco: stesso colore predefinito su interno ed esterno -> nessun sovrapprezzo
|
||||
// uniforme: stesso colore (non predefinito) su interno ed esterno -> sovrapprezzo "uniforme"
|
||||
// bicolore: colori interno ed esterno diversi tra loro -> sovrapprezzo "bicolore"
|
||||
if(interna === esterna){
|
||||
$("#prezzi_finiture").val(internaPredefinita ? 'bianco' : 'uniforme');
|
||||
}else{
|
||||
$("#prezzi_finiture").val('bicolore');
|
||||
}
|
||||
|
||||
if(percentuale != undefined && percentuale.length > 0){
|
||||
$("#prezzi_finiture").val('');
|
||||
}
|
||||
|
||||
if(tipo == 'uniforme' && internaPredefinita){
|
||||
$("#prezzi_finiture").val('bianco');
|
||||
return;
|
||||
}
|
||||
|
||||
if(tipo == 'uniforme' && !internaPredefinita){
|
||||
$("#prezzi_finiture").val('uniforme');
|
||||
return;
|
||||
}
|
||||
|
||||
if(shared_data.data_avvolgibile != null && shared_data.data_avvolgibile.length > 0){
|
||||
$("#prezzi_finiture").val('bicolore');
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
priceCalculator: null
|
||||
|
||||
}
|
||||
|
||||
export default Configurator;
|
||||
@@ -0,0 +1,443 @@
|
||||
import Configurator from './configurator.js';
|
||||
import PriceCalculator from './price_calculator.js';
|
||||
|
||||
|
||||
let container = null;
|
||||
let textureRequestVersion = {};
|
||||
let data_finiture = null;
|
||||
let data_maniglie = null;
|
||||
let data_avvolgibile = null;
|
||||
let data_vetri = null;
|
||||
let listino = null;
|
||||
|
||||
const MenuBuilder = {
|
||||
build: async (params, parent_element_id, model, data) => {
|
||||
|
||||
data_finiture = data.data_finiture;
|
||||
data_maniglie = data.data_maniglie;
|
||||
data_avvolgibile = data.data_avvolgibile;
|
||||
data_vetri = data.data_vetri;
|
||||
listino = data.listino;
|
||||
|
||||
const price_data = {
|
||||
misure: listino,
|
||||
finiture: params.prezzi_finiture,
|
||||
cerniere: params.select.cerniere_a_scomparsa,
|
||||
//altezza_maniglia: params.select.altezza_maniglia,
|
||||
azionamento: params.select.azionamento,
|
||||
vetri: data_vetri
|
||||
}
|
||||
|
||||
window.addEventListener('orientationchange', () => {
|
||||
location.reload();
|
||||
});
|
||||
PriceCalculator.init(price_data);
|
||||
let template_file = params.template != null ? params.template : 'menu.html';
|
||||
let template = await fetch(`./assets/_${template_file}?rnd=${Math.random()}`);
|
||||
|
||||
|
||||
template = await template.text();
|
||||
|
||||
|
||||
container = document.getElementById(parent_element_id);
|
||||
container.innerHTML = template;
|
||||
|
||||
let isMobile = window.innerWidth <= 1108;
|
||||
console.log("is mobile", isMobile);
|
||||
if (isMobile && window.innerWidth < window.innerHeight) {
|
||||
console.log('Mobile portrait mode setup');
|
||||
const menuHeader = $('.menu-categorie').html();
|
||||
const opzioniMenu = $('.opzioni-mobile-menu').html();
|
||||
$('#menu-mobile').append(menuHeader);
|
||||
$('#menu-mobile').append(opzioniMenu);
|
||||
$('.opzioni-mobile-menu').remove();
|
||||
$('.menu-categorie').remove();
|
||||
|
||||
//console.log($("#menu-mobile").height());
|
||||
$("#canvas-container").height(window.innerHeight - ($('#menu-mobile').height() + 90));
|
||||
|
||||
const menuScroll = $(".menu-scroll").html();
|
||||
$(".mobile-popup .popup-content").html(menuScroll);
|
||||
$(".mobile-popup").addClass("d-none");
|
||||
$(".opzioni-menu").removeClass("d-none");
|
||||
$(".menu-scroll").remove();
|
||||
|
||||
$(".mobile-popup .popup-content").css('max-height', window.innerHeight * 0.6);
|
||||
$(".mobile-popup .popup-content").css('overflow-y', 'auto');
|
||||
|
||||
const canvas_height = $('#canvas-container').height();
|
||||
$('.button-180').css('bottom', canvas_height / 2);
|
||||
|
||||
$(".btn-opzioni").on('click', function () {
|
||||
const opzione = $(this).data('opzione');
|
||||
$('.mob-menu-item').addClass('d-none');
|
||||
|
||||
$(`.mobile-popup-backdrop, .${opzione}-menu`).removeClass('d-none');
|
||||
|
||||
$(".mobile-popup").removeClass("d-none");
|
||||
// porta lo scrolling del popup mobile all'inizio quando si apre
|
||||
const popupContent = document.querySelector('.mobile-popup .popup-content');
|
||||
if (popupContent) {
|
||||
popupContent.scrollTop = 0;
|
||||
// assicurati che il primo elemento sia visibile / focusabile
|
||||
const firstChild = popupContent.querySelector('*');
|
||||
if (firstChild && typeof firstChild.focus === 'function') firstChild.focus();
|
||||
}
|
||||
});
|
||||
|
||||
$(".btn-popup").removeClass("d-none");
|
||||
$(".btn-popup, .mobile-popup-backdrop, .mobile-popup .btn-container").on('click', function () {
|
||||
$(".mobile-popup-backdrop, .mobile-popup").addClass("d-none");
|
||||
});
|
||||
|
||||
//console.log('Mobile portrait mode detected');
|
||||
} else if (isMobile && window.innerWidth >= window.innerHeight) {
|
||||
$("#left-container").addClass('overflow-auto');
|
||||
//console.log('Mobile landscape mode detected');
|
||||
}
|
||||
|
||||
let listino_min = listino[0];
|
||||
let listino_max = listino[listino.length - 1];
|
||||
const maxLarghezza = Math.max(...listino.map(item => item.larghezza));
|
||||
const maxAltezza = Math.max(...listino.map(item => item.altezza));
|
||||
const minLarghezza = Math.min(...listino.map(item => item.larghezza));
|
||||
const minAltezza = Math.min(...listino.map(item => item.altezza));
|
||||
$('.titolo').html(`${params.nome}`);
|
||||
$('.larghezza-max').html(`${minLarghezza}-${maxLarghezza}cm`);
|
||||
$('.altezza-max').html(`${minAltezza}-${maxAltezza}cm`);
|
||||
|
||||
window.sistema = data.sistema;
|
||||
|
||||
buildListaModelli(data.modelli, data.modello_id, data.categoria, data.sistema);
|
||||
|
||||
if (!isMobile) {
|
||||
let hMisure = $(".menu-categorie").outerHeight();
|
||||
|
||||
$('.menu-scroll').height(window.innerHeight - hMisure);
|
||||
} else {
|
||||
if(window.innerWidth < window.innerHeight)
|
||||
container = document.querySelector('.mobile-popup');
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (const key in params.radios) {
|
||||
let options = params.radios[key];
|
||||
|
||||
let res = buildRadios(options, key, model);
|
||||
container.querySelector(`.${key}`).innerHTML = res.html;
|
||||
console.log(key);
|
||||
if (options.length > 0)
|
||||
$(`.cnt-${key}`).removeClass('d-none');
|
||||
|
||||
if (res.has_sub_options) {
|
||||
let radios = container.querySelectorAll(`.${key} input[type=radio]`);
|
||||
radios.forEach((radio) => {
|
||||
radio.addEventListener('change', () => {
|
||||
toggleSubOption(key, { target: radio });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
$(".sistema-menu, .finiture-menu, .accessori-menu,.vetro-menu, .misure-menu").addClass('d-none');
|
||||
|
||||
|
||||
}
|
||||
|
||||
$('.apertura input').on('change', () => {
|
||||
let val = $('.apertura input:checked').val();
|
||||
|
||||
let p = params.radios.apertura.find(r => r.label == val);
|
||||
|
||||
cambiaApertura('infisso', p.scale_x);
|
||||
|
||||
});
|
||||
|
||||
|
||||
/* scorro i tipi di finitura nella form e se è uniforme nascondo i tasti non necessari */
|
||||
params.finiture.forEach((f) => {
|
||||
buildTextureRadio(model, f.nome, f.cartella_anteprime, f.cartella, f.categorie, data[f.data], f.tipo);
|
||||
if(f.nome == 'finitura_interna' && f.tipo == 'uniforme'){
|
||||
//buildTextureRadio(model, 'finitura_esterna', f.cartella_anteprime, f.cartella, f.categorie, data[f.data]);
|
||||
$('.finiture-esterne-menu').addClass('d-none');
|
||||
$('.btn-opzioni.finiture-esterne').addClass('d-none');
|
||||
$('.btn-opzioni.finiture-interne p').text('Finiture');
|
||||
$('.btn-opzioni.finiture-interne img').attr('src','./assets/img/opzioni/finiture.png');
|
||||
$('.finiture-interne-menu .menu-header').text('Finiture');
|
||||
}
|
||||
})
|
||||
|
||||
$('.info-popup').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!$('#popup').hasClass('d-none')) {
|
||||
$('#popup').addClass('d-none');
|
||||
$('#popup img').remove();
|
||||
}
|
||||
|
||||
const imageUrl = $(this).data('image-url');
|
||||
const imgElement = document.createElement('img');
|
||||
imgElement.src = imageUrl;
|
||||
imgElement.alt = 'Popup Image';
|
||||
imgElement.classList.add('img-fluid', 'popup-image');
|
||||
document.querySelector('#popup').appendChild(imgElement);
|
||||
$("#popup").removeClass('d-none');
|
||||
|
||||
});
|
||||
|
||||
$('#popup .close').on('click', function () {
|
||||
$('#popup').addClass('d-none');
|
||||
$('#popup img').remove();
|
||||
});
|
||||
|
||||
for (const key in params.select) {
|
||||
let options = params.select[key];
|
||||
|
||||
buildSelect(options, key);
|
||||
|
||||
}
|
||||
|
||||
/* opzioni disabilitate per richiesta del cliente */
|
||||
/*
|
||||
if(params.select.cerniere_a_scomparsa != null)
|
||||
buildSelect(params.select.cerniere_a_scomparsa, 'cerniere_a_scomparsa');
|
||||
|
||||
if(params.select.altezza_maniglia != null)
|
||||
buildSelect(params.select.altezza_maniglia, 'altezza_maniglia');
|
||||
*/
|
||||
let size = PriceCalculator.getMinSize();
|
||||
|
||||
$('#larghezza').val(size.larghezza + '.00');
|
||||
$('#altezza').val(size.altezza + '.00');
|
||||
|
||||
|
||||
|
||||
return PriceCalculator;
|
||||
}
|
||||
};
|
||||
|
||||
const buildListaModelli = (modelli, modello, categoria, sistema) => {
|
||||
|
||||
let lista_modelli = modelli.filter(m => m.enabled !== false);
|
||||
let html = '';
|
||||
lista_modelli.forEach(m => {
|
||||
|
||||
let selected = m.id == modello ? 'selected' : '';
|
||||
|
||||
html += `<div class="d-inline btn-categoria">
|
||||
<a href="./?type=${m.id}&sistema=${sistema}">
|
||||
<img class="${selected}" src="./assets/data/icone/${m.id}.jpg" alt="${m.id}" />
|
||||
</a>
|
||||
<p>${m.nome}</p>
|
||||
|
||||
</div>`;
|
||||
|
||||
});
|
||||
|
||||
$('.lista-modelli').html(html);
|
||||
}
|
||||
|
||||
const buildSelectFiniture = (options) => {
|
||||
let select = container.querySelector(`#prezzi_finiture`);
|
||||
select.innerHTML = ``;
|
||||
options.forEach(option => {
|
||||
select.innerHTML += `<option value="${option.finitura}">${option.label}</option>`;
|
||||
});
|
||||
|
||||
select.addEventListener('change', (e) => {
|
||||
|
||||
let val = e.target.value;
|
||||
if (val != 'bicolore' && val != 'uniforme') {
|
||||
|
||||
$(container).find(`.menu-container.finitura`).each((i, el) => {
|
||||
|
||||
if (!$(el).hasClass(val) && val != 'uniforme') {
|
||||
$(el).find('.menu-options input').first().trigger('click');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.menu-container.finitura').addClass('d-none');
|
||||
document.querySelectorAll(`.finitura.${val}`).forEach(el => {
|
||||
el.classList.remove('d-none');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const buildSelect = (options, parent) => {
|
||||
let select = container.querySelector(`.${parent}`);
|
||||
|
||||
select.innerHTML = ``;
|
||||
options.forEach(option => {
|
||||
|
||||
select.innerHTML += `<option value="${option.valore}">${option.label}</option>`;
|
||||
});
|
||||
|
||||
select.addEventListener('change', (e) => {
|
||||
let val = e.target.value;
|
||||
const el = options.find(o => o.valore == val);
|
||||
const prezzo = el.prezzo ?? 0;
|
||||
|
||||
if (el.func != null) {
|
||||
window[el.func](el.categoria);
|
||||
}
|
||||
|
||||
if (el.flip != null)
|
||||
checkFlip(el.flip);
|
||||
|
||||
});
|
||||
|
||||
$(`.cnt-${parent}`).removeClass('d-none');
|
||||
}
|
||||
|
||||
const buildTextureRadio = async (model, parent, icon_folder, texture_folder, categories, data, tipo = '') => {
|
||||
|
||||
let html = '';
|
||||
|
||||
let defaultIndex = data.findIndex(option => option.predefinito === true);
|
||||
if (defaultIndex < 0) defaultIndex = 0;
|
||||
|
||||
data.forEach((option, i) => {
|
||||
let popup_link = option.pop_up != null ? option.pop_up : '';
|
||||
|
||||
if (popup_link != '') {
|
||||
popup_link = `<a href="javascript:;" class="info-popup" data-image-url="./assets/data/immagini/${window.sistema}/${model}/pop_up_vetri/${popup_link}" ><img width="20" src="./assets/img/menu/icona_info.png" /></a>`;
|
||||
}
|
||||
|
||||
let checked = i == defaultIndex && parent != 'maniglia' ? 'checked' : '';
|
||||
html =
|
||||
`<div class="d-inline-block texture-radio text-center">
|
||||
<label class="menu-option">
|
||||
<input type="radio" ${checked} class="texture-button ${option.percentuale != null && option.percentuale !== '' ? 'percentuale' : ''} check_finitura" data-percentuale="${option.percentuale ?? ''}" data-tipo="${tipo}" data-predefinito="${i == defaultIndex}" name="${parent}" value="${option.id}">
|
||||
<div class="option-content">
|
||||
<img src="./assets/data/immagini/${window.sistema}/${model}/${icon_folder}/${option.anteprima_img}" alt="${option.descrizione}">
|
||||
<span class="checkmark"></span>
|
||||
</div>
|
||||
</label>
|
||||
<div class="option-label">${option.descrizione} ${popup_link}</div>
|
||||
</div>`;
|
||||
|
||||
|
||||
let radio = document.createElement('div');
|
||||
radio.innerHTML = html;
|
||||
radio = radio.firstChild;
|
||||
|
||||
radio.addEventListener('change', async (e) => {
|
||||
|
||||
textureRequestVersion[parent] = (textureRequestVersion[parent] || 0) + 1;
|
||||
const requestVersion = textureRequestVersion[parent];
|
||||
const isStale = () => textureRequestVersion[parent] !== requestVersion;
|
||||
|
||||
option.categories = categories;
|
||||
option.folder = model;
|
||||
option.texture_folder = texture_folder;
|
||||
option.isStale = isStale;
|
||||
$(".mobile-popup-backdrop, .mobile-popup").addClass("d-none");
|
||||
|
||||
await cambiaTexture(option);
|
||||
if (isStale()) return;
|
||||
|
||||
if (option.categories.includes('interno')) {
|
||||
option.categories = ['corpo_base'];
|
||||
cambiaColoreCB(option);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//if(!container.querySelector(`.menu-options.${parent}`)) console.log(parent);
|
||||
container.querySelector(`.menu-options.${parent}`).appendChild(radio);
|
||||
});
|
||||
|
||||
$(`.cnt-${parent}`).removeClass('d-none');
|
||||
//container.querySelector(`.${parent}`).innerHTML = html;
|
||||
};
|
||||
|
||||
const buildRadios = (options, key, model) => {
|
||||
let html = '';
|
||||
let has_sub_options = false;
|
||||
|
||||
options.forEach((option, i) => {
|
||||
|
||||
let percentuale = '';
|
||||
let modello = '';
|
||||
let class_percentuale = '';
|
||||
let has_options = false;
|
||||
let sub_option_container = null;
|
||||
let html_func = '';
|
||||
let has_options_class = '';
|
||||
let container_id = '';
|
||||
|
||||
if (option.opzioni != null) {
|
||||
has_sub_options = true;
|
||||
has_options = true;
|
||||
|
||||
for (const key_opt in option.opzioni) {
|
||||
let options = option.opzioni[key_opt];
|
||||
console.log(key_opt)
|
||||
|
||||
let res = buildRadios(options, key_opt, model);
|
||||
container.querySelector(`.${key_opt}`).innerHTML = res.html;
|
||||
sub_option_container = container.querySelector(`.${key_opt}`).parentElement.parentElement;
|
||||
sub_option_container.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
if (option.model != null) {
|
||||
modello = `data-model="${option.model}"`;
|
||||
}
|
||||
|
||||
if (option.percentuale != null) {
|
||||
percentuale = `data-percentuale="${option.percentuale}"`;
|
||||
class_percentuale = 'percentuale';
|
||||
}
|
||||
|
||||
if (has_options) {
|
||||
has_options_class = 'has-options';
|
||||
html_func = `onclick="toggleSubOption('${sub_option_container.id}',event)"`;
|
||||
container_id = `data-toggle-id="${sub_option_container.id}"`;
|
||||
}
|
||||
|
||||
let checked = i == 0 ? 'checked' : '';
|
||||
|
||||
html +=
|
||||
`<div class="d-inline-block radio-button text-center">
|
||||
<label class="menu-option">
|
||||
<input type="radio" ${checked} ${percentuale} ${modello} class="${has_options_class} ${class_percentuale} auto-radio" ${container_id} name="${key}" value="${option.label}">
|
||||
<div class="option-content">
|
||||
<img src="./assets/data/immagini/${window.sistema}/${model}/${option.icon}" alt="${option.label}">
|
||||
<span class="checkmark"></span>
|
||||
|
||||
</div>
|
||||
</label>
|
||||
<div class="option-label">${option.label}</div>
|
||||
</div>`;
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
return {
|
||||
html: html,
|
||||
has_sub_options: has_sub_options
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
window.toggleSubOption = (id, e) => {
|
||||
|
||||
let parent_class = id + '-sub-option';
|
||||
const sub_option_container = container.querySelector(`.${parent_class}`);
|
||||
|
||||
if (e.target.classList.contains('has-options')) {
|
||||
container.querySelector(`#${e.target.dataset.toggleId}`).classList.remove('d-none');
|
||||
} else {
|
||||
sub_option_container.classList.add('d-none');
|
||||
}
|
||||
|
||||
}
|
||||
export default MenuBuilder;
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
const ParamsParser = {
|
||||
getQueryParams: () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const queryParams = {};
|
||||
|
||||
params.forEach((value, key) => {
|
||||
queryParams[key] = value;
|
||||
});
|
||||
|
||||
return queryParams;
|
||||
}
|
||||
};
|
||||
|
||||
export default ParamsParser;
|
||||
@@ -0,0 +1,122 @@
|
||||
|
||||
let listini = null;
|
||||
|
||||
const toPercentuale = (valore) => {
|
||||
const perc = parseFloat(valore);
|
||||
return isNaN(perc) ? 0 : perc / 100;
|
||||
};
|
||||
|
||||
const toPrezzo = (valore) => {
|
||||
const prezzo = parseFloat(valore);
|
||||
return isNaN(prezzo) ? 0 : prezzo;
|
||||
};
|
||||
|
||||
const PriceCalculator = {
|
||||
init: async (data) => {
|
||||
|
||||
listini = data;
|
||||
|
||||
|
||||
},
|
||||
getMinSize: () => {
|
||||
|
||||
const firstSize = listini.misure.find(item => item.prezzo !== 0);
|
||||
|
||||
return firstSize;
|
||||
|
||||
},
|
||||
getGridPrice: (width, height) => {
|
||||
let altezza = parseFloat(height);
|
||||
let larghezza = parseFloat(width);
|
||||
|
||||
let mod_altezza = altezza % 10;
|
||||
let mod_larghezza = larghezza % 10;
|
||||
|
||||
if(mod_altezza > 0) altezza = (altezza - mod_altezza) + 10;
|
||||
if(mod_larghezza > 0) larghezza = (larghezza - mod_larghezza) + 10;
|
||||
|
||||
let misure = listini.misure.find((el) => {
|
||||
if(el.altezza == altezza && el.larghezza == larghezza)
|
||||
return el;
|
||||
});
|
||||
|
||||
if(misure == null) return -1;
|
||||
return misure.prezzo;
|
||||
},
|
||||
getConfigurationPrice: (data) => {
|
||||
|
||||
let prezzo_finale = data.prezzo_base;
|
||||
let percentuale_finiture = 0;
|
||||
let prezzo_accessori = 0;
|
||||
let percentuale_vetro = 0;
|
||||
let percentuale_accessori = 0;
|
||||
|
||||
const config = {};
|
||||
|
||||
if(data.finitura && data.override_supplemento_finitura !== true){
|
||||
let supplemento = (listini.finiture ?? []).find((el) => el.finitura === data.finitura);
|
||||
|
||||
config.tipo_finitura = supplemento;
|
||||
|
||||
percentuale_finiture = toPercentuale(supplemento?.percentuale);
|
||||
}
|
||||
|
||||
if(data.cerniere_scomparsa != null){
|
||||
let supplemento = listini.cerniere.find((el) => {
|
||||
if(el.valore == data.cerniere_scomparsa)
|
||||
return el;
|
||||
});
|
||||
|
||||
config.cerniere_scomparsa = supplemento;
|
||||
|
||||
prezzo_accessori += toPrezzo(supplemento?.prezzo);
|
||||
}
|
||||
|
||||
if(data.altezza_maniglia != null){
|
||||
|
||||
let supplemento = listini.altezza_maniglia.find((el) => {
|
||||
if(el.valore == data.altezza_maniglia)
|
||||
return el;
|
||||
});
|
||||
|
||||
config.altezza_maniglia = supplemento;
|
||||
|
||||
prezzo_accessori += toPrezzo(supplemento?.prezzo);
|
||||
}
|
||||
|
||||
if(data.azionamento != null){
|
||||
|
||||
let supplemento = listini.azionamento.find((el) => {
|
||||
if(el.valore == data.azionamento)
|
||||
return el;
|
||||
});
|
||||
|
||||
config.azionamento = supplemento;
|
||||
|
||||
prezzo_accessori += toPrezzo(supplemento?.prezzo);
|
||||
}
|
||||
|
||||
if(data.vetro != null){
|
||||
let vetro = listini.vetri.find((el) => {
|
||||
if(el.id == data.vetro)
|
||||
return el;
|
||||
});
|
||||
|
||||
config.vetro = vetro;
|
||||
percentuale_vetro = toPercentuale(vetro?.percentuale);
|
||||
}
|
||||
|
||||
|
||||
prezzo_finale = (prezzo_finale * (1 + percentuale_finiture+percentuale_vetro+data.percentuale_accessori)) + prezzo_accessori;
|
||||
prezzo_finale += prezzo_finale * 22 / 100; // IVA 22%
|
||||
|
||||
return {
|
||||
prezzo: prezzo_finale,
|
||||
configurazione: config
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default PriceCalculator;
|
||||
@@ -0,0 +1,349 @@
|
||||
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import $ from 'jquery';
|
||||
import { APP } from './app.js';
|
||||
import ParamsParser from './params_parser.js';
|
||||
import MenuBuilder from './menu_builder.js';
|
||||
import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||
import './price_calculator.js';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
import Configurator from './configurator.js';
|
||||
|
||||
|
||||
window.$ = $;
|
||||
window.THREE = THREE; // Used by APP Scripts.
|
||||
window.OrbitControls = OrbitControls; // Used by APP Scripts.
|
||||
window.GLTFLoader = GLTFLoader; // Used by APP Scripts.
|
||||
|
||||
|
||||
$(() => {
|
||||
|
||||
$('.cart-button').on('click', async () => {
|
||||
|
||||
if($('.cart-button').hasClass('disabled'))
|
||||
return;
|
||||
const img = await window.generaImagine();
|
||||
const data = {
|
||||
payload: window.configurazione,
|
||||
img: img,
|
||||
qty: parseInt($('.quantity-input').val()),
|
||||
fn: 'aggiungi_prodotto'
|
||||
};
|
||||
|
||||
|
||||
window.parent.postMessage(data, "https://www.infissionline.it");
|
||||
window.parent.postMessage(data, "https://infissionline.test");
|
||||
});
|
||||
});
|
||||
|
||||
const start = async () => {
|
||||
const params = ParamsParser.getQueryParams();
|
||||
|
||||
let data_folder = `./assets/data/sistemi/${params.sistema}`;
|
||||
let modello_folder = `./assets/data/modelli/${params.sistema}`;
|
||||
|
||||
|
||||
const modelli = await (await fetch(`${data_folder}/modelli.json?rnd=` + Math.random())).json();
|
||||
|
||||
const modello = modelli.find(m => m.id === params.type);
|
||||
|
||||
const data = await (await fetch(`${modello_folder}/${modello.cartella}/form.json?rnd=${Math.random()}`)).json();
|
||||
const data_finiture = modello.moduli.includes('modello') ? (await (await fetch(`${modello_folder}/${modello.cartella}/modello.json?rnd=${Math.random()}`)).json()).filter(el => el.id != "") : [];
|
||||
const data_maniglie = modello.moduli.includes('maniglia') ? (await (await fetch(`${modello_folder}/${modello.cartella}/maniglia.json?rnd=${Math.random()}`)).json()).filter(el => el.id != "") : [];
|
||||
const data_avvolgibile = modello.moduli.includes('avvolgibile') ? (await (await fetch(`${modello_folder}/${modello.cartella}/avvolgibile.json?rnd=${Math.random()}`)).json()).filter(el => el.id != "") : [];
|
||||
const data_vetri = modello.moduli.includes('vetro') ? (await (await fetch(`${modello_folder}/${modello.cartella}/vetro.json?rnd=${Math.random()}`)).json()).filter(el => el.id != "") : [];
|
||||
const listino = modello.moduli.includes('listino') ? await (await fetch(`${modello_folder}/${modello.cartella}/listino.json?rnd=${Math.random()}`)).json() : [];
|
||||
const altezza_maniglia = modello.moduli.includes('altezza_maniglia') ? await (await fetch(`${data_folder}/altezza_maniglia_${modello.categoria}.json?rnd=${Math.random()}`)).json() : [];
|
||||
|
||||
let priceCalculator = await MenuBuilder.build(data, 'left-container', modello.cartella_texture || modello.cartella, {
|
||||
modelli: modelli,
|
||||
categoria: modello.categoria,
|
||||
sistema: params.sistema,
|
||||
data_finiture: data_finiture,
|
||||
data_maniglie: data_maniglie,
|
||||
data_avvolgibile: data_avvolgibile,
|
||||
data_vetri: data_vetri,
|
||||
listino: listino,
|
||||
modello_id: modello.id
|
||||
});
|
||||
|
||||
Configurator.init(priceCalculator, {
|
||||
modello: modello,
|
||||
nome_esteso: data.nome,
|
||||
data_finiture: data_finiture,
|
||||
data_maniglie: data_maniglie,
|
||||
data_avvolgibile: data_avvolgibile,
|
||||
data_vetri: data_vetri,
|
||||
altezza_maniglia: altezza_maniglia,
|
||||
listino: listino
|
||||
});
|
||||
|
||||
Configurator.enable();
|
||||
|
||||
$(`.menu-header-sistema .${params.sistema}`).addClass('selected');
|
||||
$(`.v-divider.${params.sistema}`).addClass('d-none');
|
||||
|
||||
var player = new APP.Player('canvas-container');
|
||||
var playerOff = new APP.Player('canvas-offscreen');
|
||||
|
||||
var loader = new THREE.FileLoader();
|
||||
loader.load('./assets/app.json', function (text) {
|
||||
player.load(JSON.parse(text));
|
||||
playerOff.load(JSON.parse(text));
|
||||
player.rotateBackground(Math.PI);
|
||||
playerOff.rotateBackground(Math.PI);
|
||||
playerOff.setSize(playerOff.dom.clientWidth, playerOff.dom.clientHeight);
|
||||
|
||||
var gltfLoader = new GLTFLoader();
|
||||
|
||||
gltfLoader.load(`./assets/models/${params.sistema}/${modello.modello}`, function (gltf) {
|
||||
document.getElementById('loadingBarContainer').style.display = 'none';
|
||||
//gltf.scene.rotation.y = THREE.MathUtils.degToRad(80);
|
||||
gltf.scene.name = 'infisso';
|
||||
window.current_model = modello.modello;
|
||||
gltf.scene.userData.name = modello.modello;
|
||||
|
||||
//$("input[type=radio]").first().trigger("click");
|
||||
|
||||
gltf.scene.position.y = 0;
|
||||
gltf.scene.position.z = 0.1;
|
||||
//gltf.scene.rotation.set(0, Math.PI, 0);
|
||||
player.addToScene(gltf.scene);
|
||||
player.viewFrontSide();
|
||||
|
||||
playerOff.addToScene(gltf.scene.clone());
|
||||
playerOff.viewFrontSide();
|
||||
$('#canvas-offscreen').addClass('d-none');
|
||||
player.dom.style.position = 'relative';
|
||||
|
||||
if (params.type != 'cassonetto') {
|
||||
$("input[name=maniglia]").first().trigger("click");
|
||||
$("input[name=finitura_interna]").eq(1).trigger("click");
|
||||
$("input[name=finitura_interna]").eq(0).trigger("click");
|
||||
}
|
||||
|
||||
$("#larghezza").first().trigger("change");
|
||||
|
||||
//player.addMarker("Cylinder028", 'left', 'https://www.youtube.com/embed/l_zqI0v7JcU?si=Vq2k8nWHYk13esMQ');
|
||||
//player.addMarker("marker_1", 'left', 'https://www.youtube.com/embed/l_zqI0v7JcU?si=Vq2k8nWHYk13esMQ');
|
||||
//player.addMarker("marker_2", 'right', 'https://www.youtube.com/embed/LCi9jdF_4MQ?si=b8cyxSOI2sKEmmcm');
|
||||
|
||||
},
|
||||
function (xhr) {
|
||||
var percentComplete = (xhr.loaded / xhr.total) * 100;
|
||||
document.getElementById('loadingBarProgress').style.width = percentComplete + '%';
|
||||
document.getElementById('loadingPercentage').innerText = Math.round(percentComplete) + '%';
|
||||
}, function (error) {
|
||||
console.error('An error happened while loading the GLB file:', error);
|
||||
});
|
||||
|
||||
player.setSize(player.dom.clientWidth, player.dom.clientHeight);
|
||||
player.play();
|
||||
|
||||
window.addEventListener('resize', function () {
|
||||
//console.log(player.dom.clientWidth, player.dom.clientHeight);
|
||||
player.setSize(player.dom.clientWidth, player.dom.clientHeight);
|
||||
player.render();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$('.quantity-btn').on('click', (e) => {
|
||||
|
||||
const input = document.querySelector('.quantity-input');
|
||||
let value = parseInt(input.value);
|
||||
|
||||
if (e.target.classList.contains('increment')) {
|
||||
input.value = value + 1;
|
||||
} else if (e.target.classList.contains('decrement') && value > 1) {
|
||||
input.value = value - 1;
|
||||
}
|
||||
});
|
||||
|
||||
window.generaImagine = async () => {
|
||||
playerOff.render();
|
||||
$('#canvas-offscreen').removeClass('d-none');
|
||||
const canvas = $('#canvas-offscreen canvas')[0];
|
||||
const dataUrl = await canvas.toDataURL('image/png');
|
||||
|
||||
$('#canvas-offscreen').addClass('d-none');
|
||||
return dataUrl;
|
||||
const a = document.createElement('a');
|
||||
a.href = dataUrl;
|
||||
a.download = 'immagine.png';
|
||||
a.click();
|
||||
}
|
||||
|
||||
window.render = () => {
|
||||
player.render();
|
||||
}
|
||||
|
||||
let currentView = 'front';
|
||||
|
||||
window.cambiaTexture = (data) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
||||
await player.changeTexture(data)
|
||||
//console.log(data)
|
||||
//console.log('window.rotate', window.rotate);
|
||||
if (data && data.categories.includes('esterno') && currentView !== 'back'){
|
||||
if(window.rotate){
|
||||
player.flipView();
|
||||
currentView = 'back';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (data && (data.categories.includes('interno') || data.categories.includes('maniglia')) && currentView !== 'front'){
|
||||
|
||||
if(window.rotate){
|
||||
player.flipView();
|
||||
currentView = 'front';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.flip180 = () => {
|
||||
player.flipView();
|
||||
currentView = currentView === 'front' ? 'back' : 'front';
|
||||
render();
|
||||
}
|
||||
|
||||
window.checkFlip = (direction) => {
|
||||
|
||||
if(direction != currentView)
|
||||
flip180();
|
||||
|
||||
}
|
||||
|
||||
window.cambiaColoreCB = (data) => {
|
||||
player.changeColor(data);
|
||||
render();
|
||||
}
|
||||
|
||||
window.cambiaApertura = (name, scale) => {
|
||||
player.changeXscale(name, scale);
|
||||
render();
|
||||
}
|
||||
|
||||
window.mostraCerniere = (categoria) => {
|
||||
player.showObject(categoria);
|
||||
render();
|
||||
}
|
||||
|
||||
window.nascondiCerniere = (categoria) => {
|
||||
player.hideObject(categoria);
|
||||
render();
|
||||
}
|
||||
|
||||
window.rotate = true;
|
||||
|
||||
window.caricaModello = (modello) => {
|
||||
|
||||
let textureButtons = $(".texture-button:checked");
|
||||
|
||||
window.rotate = false;
|
||||
|
||||
const radios = {};
|
||||
$('.texture-button[name]').each(function() {
|
||||
radios[$(this).attr('name')] ??= this;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".texture-button[name=maniglia]").forEach(el => el.checked = false)
|
||||
|
||||
//console.log(textureButtons)
|
||||
if(player.swapModel(modello)){
|
||||
|
||||
for(let el in radios){
|
||||
$(radios[el]).trigger("click");
|
||||
}
|
||||
|
||||
$(textureButtons).each((i, el) => {
|
||||
$(el).trigger("click");
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
window.rotate = true;
|
||||
}, 1000);
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('loadingBarContainerAlt').style.display = 'flex';
|
||||
document.getElementById('loadingBarProgressAlt').style.width = '0%';
|
||||
document.getElementById('loadingPercentageAlt').innerText = '0%';
|
||||
|
||||
var gltfLoader = new GLTFLoader();
|
||||
|
||||
gltfLoader.load(`./assets/models/${modello}`, function (gltf) {
|
||||
document.getElementById('loadingBarContainerAlt').style.display = 'none';
|
||||
$('#canvas-offscreen').removeClass('d-none');
|
||||
//gltf.scene.rotation.y = THREE.MathUtils.degToRad(80);
|
||||
gltf.scene.name = 'infisso';
|
||||
|
||||
gltf.scene.userData.name = modello;
|
||||
|
||||
setTimeout(() => {
|
||||
for(let el in radios){
|
||||
$(radios[el]).trigger("click");
|
||||
}
|
||||
});
|
||||
|
||||
gltf.scene.position.y = 0;
|
||||
gltf.scene.position.z = 0.1;
|
||||
//gltf.scene.rotation.set(0, Math.PI, 0);
|
||||
player.hideModel('infisso');
|
||||
playerOff.hideModel('infisso');
|
||||
player.addToScene(gltf.scene);
|
||||
player.viewFrontSide();
|
||||
|
||||
playerOff.addToScene(gltf.scene.clone());
|
||||
//playerOff.viewFrontSide();
|
||||
|
||||
$('#canvas-offscreen').addClass('d-none');
|
||||
player.dom.style.position = 'relative';
|
||||
|
||||
if (params.type != 'cassonetto') {
|
||||
$("input[name=maniglia]").first().trigger("click");
|
||||
}
|
||||
|
||||
$("#larghezza").first().trigger("change");
|
||||
|
||||
$(textureButtons).each((i, el) => {
|
||||
$(el).trigger("click");
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
window.rotate = true;
|
||||
}, 1000);
|
||||
//player.addMarker("Cylinder028", 'left', 'https://www.youtube.com/embed/l_zqI0v7JcU?si=Vq2k8nWHYk13esMQ');
|
||||
//player.addMarker("marker_1", 'left', 'https://www.youtube.com/embed/l_zqI0v7JcU?si=Vq2k8nWHYk13esMQ');
|
||||
//player.addMarker("marker_2", 'right', 'https://www.youtube.com/embed/LCi9jdF_4MQ?si=b8cyxSOI2sKEmmcm');
|
||||
|
||||
},
|
||||
function (xhr) {
|
||||
var percentComplete = (xhr.loaded / xhr.total) * 100;
|
||||
document.getElementById('loadingBarProgressAlt').style.width = percentComplete + '%';
|
||||
document.getElementById('loadingPercentageAlt').innerText = Math.round(percentComplete) + '%';
|
||||
}, function (error) {
|
||||
console.error('An error happened while loading the GLB file:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
start();
|
||||
Reference in New Issue
Block a user