IFC Viewer SDK · v1.18.0
Integra il viewer IFC nel tuo prodotto
Inserisci lo stesso viewer del browser nel tuo CDE, digital twin o strumenti interni di progetto. Carica dati IFC dalla tua app mentre ogni modello viene analizzato nel client.
Tre righe fino al primo render
const viewer = new IfcViewer("#viewer");
await viewer.add("project.ifc", ifcBytes);
// → rendered, validated, all on the client- 100% lato client
- Nessun backend di upload
- Zero dipendenze a runtime
- Wrapper di ~6 KB
- Tipi TypeScript
- 10 lingue
- Motore validato con IDS
Configurazione
Avvio rapido
Scegli il tuo stack. Copia, incolla, renderizza — senza build, senza chiave API.
<div id="viewer" style="height:520px"></div>
<script type="module">
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/ifc-viewer.es.js";
const viewer = new IfcViewer("#viewer");
// Load IFC bytes from your app — nothing is uploaded
const bytes = await fetch("/models/project.ifc").then(r => r.arrayBuffer());
await viewer.add("project.ifc", bytes);
</script>Zero JavaScript — metti il tag in qualsiasi pagina o dashboard e imposta gli attributi.
<script type="module" src="https://www.ifcvieweronline.eu/sdk/ifc-viewer.es.js"></script>
<ifc-viewer model="https://your-cde.com/model.ifc" ui="minimal" accent="#3fa866"
style="display:block;height:520px"></ifc-viewer>Monta in un effect e smonta all’unmount. Sicuro con la doppia invocazione dello StrictMode di React 18.
import { useEffect, useRef } from "react";
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/ifc-viewer.es.js";
export function ModelViewer({ url }) {
const host = useRef(null);
useEffect(() => {
const viewer = new IfcViewer(host.current, { model: url });
return () => viewer.dispose(); // StrictMode-safe teardown
}, [url]);
return <div ref={host} style={{ height: 520 }} />;
}Monta in onMounted, libera in onUnmounted.
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/ifc-viewer.es.js";
const host = ref(null);
let viewer;
onMounted(() => { viewer = new IfcViewer(host.value, { model: "https://host/m.ifc" }); });
onUnmounted(() => viewer && viewer.dispose());
</script>
<template>
<div ref="host" style="height: 520px" />
</template>Ospitato da noi o da te
Gli snippet importano dalla nostra CDN, che funziona su qualsiasi origine. Per ospitarlo tu, servi ifc-viewer.es.js dal tuo dominio — l’SDK ricava l’URL dell’app relativamente allo script. L’app è altrove? Usa l’opzione baseUrl.
Non c’è ancora un pacchetto npm: importa il modulo via URL (sopra) oppure includi ifc-viewer.es.js nella tua app.
Dimostrazione
Demo live
Questa pagina sta eseguendo il SDK. Clicca un controllo per scaricare un IFC di esempio e guidare il viewer — ogni pulsante mostra la chiamata che effettua.
⚠ L’host di esempio potrebbe limitare le richieste. Riprova tra un momento.
Architettura
Come funziona
Un wrapper minimo nella tua pagina, il viewer completo in un iframe isolato, i tuoi byte trasferiti tra i due — ed elaborati dove già si trovano.
La tua app
Un modulo ES da ~6 KB che crea un iframe e un’API JS tipizzata. Nulla del peso 3D o del parsing finisce nel tuo bundle.
Ponte postMessage
I byte IFC vengono trasferiti all’iframe come ArrayBuffer (senza copia). Comandi e query sono messaggi correlati di richiesta/risposta.
Il viewer
three.js + web-ifc compilato in WebAssembly effettuano il parsing e il rendering del modello dentro l’iframe — sulla macchina del visitatore.
Perché è privato
I modelli non raggiungono mai un server. Nessuna pipeline di upload da proteggere, nessuna questione di residenza dei dati, nessuna coda per dimensione del file.
Perché scala
Il calcolo gira sul dispositivo di ogni visitatore. Servire un modello da 200 MB costa quanto uno da 2 MB — è un file statico.
Concetti
Concetti chiave
Quattro cose da sapere prima di costruire.
Montaggio e prontezza
new IfcViewer(target) monta subito e mette in coda i comandi finché il viewer non è pronto. await IfcViewer.create(target) (o whenReady()) restituisce un’istanza utilizzabile immediatamente.
// queues commands until ready
const viewer = new IfcViewer("#viewer");
// …or await an instance that is ready to use
const viewer = await IfcViewer.create("#viewer");Byte o URL
add(name, bytes) trasmette byte che hai già — niente CORS, niente caricato; il buffer viene trasferito (resta detached), quindi passa una copia se ti serve ancora. addFromUrl(url) scarica invece un URL pubblico con CORS abilitato.
// you already have the bytes — no CORS, nothing uploaded
await viewer.add("a.ifc", bytes);
// …or load a public, CORS-enabled URL
await viewer.addFromUrl("https://host/b.ifc");Eventi
Iscriviti con on(event, cb), che restituisce una funzione per annullare l’iscrizione. Hai ready, model-progress, model-loaded, validation-completed, model-error ed element-selected.
const off = viewer.on("model-loaded", (m) => {
console.log(m.fileName, m.elementCount);
});
// later: off();Query
Estrai dati su richiesta: getModels, getElement, getValidation, getStats, getIssues, checkIds, checkEir, screenshot. Ognuna è richiesta/risposta e viene rifiutata dopo un timeout (30 s; IDS / EIR fino a 120 s).
const models = await viewer.getModels();
const { qualityScore } = await viewer.getValidation();
const png = await viewer.screenshot();Riferimento
Riferimento API
Tutti i metodi, raggruppati — con firme e tipi di ritorno. Seguono le opzioni del costruttore, gli eventi e il web component <ifc-viewer>.
Costruttore
new IfcViewer(target, options?)IfcViewerMonta in un selettore CSS o elemento. Vedi le opzioni qui sotto.
IfcViewer.create(target, options?)Promise<IfcViewer>Crea un viewer e si risolve non appena è pronto ad accettare comandi.
Caricamento dei modelli
add(name, bytes)Promise<ModelLoadedEvent>Carica byte IFC (ArrayBuffer/Uint8Array) dalla tua app. Il buffer viene trasferito per un passaggio senza copia.
addFromUrl(url, name?)Promise<ModelLoadedEvent>Carica un URL IFC pubblico con CORS.
removeModel(modelId)voidScarica un modello per id.
clear()voidRimuovi tutti i modelli caricati.
Camera e selezione
select(expressId | globalId, modelId?)voidSeleziona e inquadra un elemento — per expressID IFC o per GlobalId (che trova anche il suo modello).
setView(view)voidVola a una vista con nome della scena — iso, front, back, left, right, top, bottom — con tutta la scena inquadrata. Senza risposta (tra 1.14 e 1.17 il viewer la ignorava).
frame({ view?, fill?, azimuth?, elevation?, animate? })Promise<{ scope }>Inquadratura per la presentazione: il modello occupa `fill` del riquadro (0,2–0,98, predefinito 0,85), adattato ai suoi spigoli e non alla sfera che lo contiene. azimuth / elevation scelgono l’angolo.
frame(elementId, modelId?, options?)Promise<{ scope: 'element' }>Inquadra un elemento (expressID): dall’angolazione attuale salvo che sia indicata una vista. Rifiuta se non è nel modello.
fit() · reset()voidInquadra il modello attivo dall’angolazione attuale, con margine / reimposta la camera.
setCamera(position, direction)voidPosiziona la camera in una posizione guardando in una direzione.
getCamera()Promise<CameraState | null>Dove si trova la camera e cosa guarda — salvalo e ripristinalo con lookAt.
lookAt(position, target, animate?)Promise<void>Porta la camera in una posizione guardando un obiettivo (metri di scena, Y in alto).
setWalkMode(enabled, { speed? })Promise<WalkState>Modalità passeggiata in prima persona (WASD, trascina per guardare, Esc per uscire). Emette walk-changed.
getWalkState()Promise<WalkState>Se la modalità passeggiata è attiva e a che velocità.
Visibilità
isolate(ifcType?)voidIsola una categoria (es. "IfcWall"); ometti per azzerare.
showAll()voidRipristina la piena visibilità (rimuovi nascosti + isolamento).
hideElements(ids, modelId?) · showElements(ids, modelId?)voidNasconde / mostra un insieme di elementi per expressID.
setModelVisible(modelId, visible)Promise<void>Mostra o nasconde un modello di una scena federata senza scaricarlo.
setModelOpacity(opacity, modelId?)Promise<void>Rende traslucido un modello (0,05–1) — ad es. l’architettura attorno agli impianti.
isolateModel(modelId | null)Promise<void>Mostra solo questo modello; null li mostra di nuovo tutti.
Aspetto e presentazione
setBackground(background)Promise<BackgroundState>Cambia lo sfondo della scena: un preset ('white', 'paper', 'blueprint', 'sky', 'studio'), '#rrggbb', '#alto,#basso' o { top, bottom }. Non salvato come preferenza del visitatore.
getBackground()Promise<BackgroundState>Lo sfondo attuale della scena.
setAccent(color)Promise<void>Cambia il colore d'accento dell'interfaccia a runtime (#rrggbb).
setClientMode(enabled)Promise<void>Attiva o disattiva la vista cliente — quella per gli stakeholder, come ui: 'client'.
setRenderQuality(quality)Promise<void>'quality' attiva il rendering più pesante per un'immagine di copertina; 'standard' per tutti i giorni.
Studio solare
setSolar(opts?)Promise<SolarState>Ombre reali a una data e ora locali del sito: { date: '06-21', time: '18:00' }. Il sito viene dalla georeferenziazione IFC; passa location per un modello senza — mai una città predefinita in silenzio.
getSolar()Promise<SolarState>Data, ora e fuso dello studio, e dove si trova il sito.
Modalità mappa
setSiteContext(opts?)Promise<SiteContextState>Colloca il modello sulla mappa con terreno e dintorni OpenStreetMap. Chiamarlo significa che la tua pagina dichiara il consenso alle tessere per i suoi visitatori; mostra le attribuzioni.
getSiteContext()Promise<SiteContextState>Stato della modalità mappa, il posizionamento e le attribuzioni da mostrare.
Scene
openScene(url | SceneDocument)Promise<void>Aprire un’altra scena: l’URL di un .scene.json o un documento di scena (viaggia compresso nell’indirizzo del frame, quindi deve stare in un link). Il visualizzatore si ricarica; le chiamate in attesa vengono rifiutate e ready scatta di nuovo.
exportScene({ title?, description?, camera? })Promise<SceneExport>La scena a schermo come documento di scena — modelli per URL, livelli, gemello, mappa, camera — con le fonti da citare e un link che la contiene.
packScene(doc)Promise<string | null>Comprimere da sé un documento di scena per un link #scene= (null se è troppo grande per un link).
Livelli di dati e gemello
getLayerPresets()Promise<LayerPreset[]>Il catalogo delle fonti pubbliche in tempo reale, con nome nella lingua del visualizzatore, ciò che serve a ciascuna in un browser (una chiave, un proxy) e se ha dati vicino al sito.
addLayer({ preset } | { url, live? } | { geojson })Promise<DataLayerInfo>Aggiungere un livello: una fonte del catalogo ({ preset }), GeoJSON o un feed in tempo reale a un URL ({ url, live }), o GeoJSON che hai già ({ geojson }). Solo per la sessione: mai salvato nei livelli del visitatore.
getLayers()Promise<DataLayerInfo[]>Tutti i livelli di dati: stato, numero di elementi, estensione, aggiornamento e attribuzione.
setLayerVisible(id, visible)Promise<DataLayerInfo>Mostrare o nascondere un livello.
frameLayer(id)Promise<void>Portare la camera sugli elementi di un livello.
removeLayer(id)Promise<void>Rimuovere un livello.
getTwin()Promise<TwinState>Il gemello operativo adesso: fonti dei dispositivi (stato, ultima lettura) e, per collegamento, la regola soddisfatta, il suo colore, il valore dell’etichetta e se è in allarme.
Sezioni
addSection({ axis?, offset?, level?, flip? })Promise<SectionsState & { id }>Aggiunge un piano di sezione. { level: 'Piano 1' } è una pianta a quel livello; { axis: 'x', offset: 4.5 } una sezione a 4,5 m.
updateSection(id, { offset?, enabled?, flipped? })Promise<SectionsState>Sposta, attiva/disattiva o inverte un piano.
removeSection(id?)Promise<SectionsState>Rimuove un piano, o tutti i tagli senza id.
setSectionBox('model' | 'selection' | false)Promise<SectionsState>Un box di sezione attorno al modello o alla selezione; false lo rimuove.
getSections()Promise<SectionsState>Tutti i piani, il box e i livelli disponibili per i tagli per piano.
Tour
startTour(template?, { autoplay?, title? })Promise<TourState>Avvia un tour predefinito: 'social', 'client-walkthrough' o 'technical-review' (percorre le anomalie di validazione). Riprodotto dalla barra tour del viewer.
playTour({ title?, steps }, { startAt?, autoplay? })Promise<TourState>Riproduce un tour creato da te: soste della camera con didascalie, evidenziazioni e classi isolate. autoplay: true o ms per sosta.
nextTourStep() · prevTourStep() · goToTourStep(i)Promise<TourState>Passare da una sosta all’altra.
setTourAutoplay(autoplay)Promise<TourState>Attiva o disattiva l’avanzamento automatico del tour in corso.
stopTour()Promise<TourState>Ferma il tour e restituisce la camera.
getTour()Promise<TourState>Il tour e le sue soste, nel formato di playTour() — salvalo e riproducilo più tardi.
Regista di presentazioni
getPresentationRecipes()Promise<PresentationRecipe[]>Le ricette integrate del regista (demo per riunione, reel, teaser LinkedIn, lancio, look editoriali…).
createPresentation(recipe?, options?)Promise<PresentationState>Trasforma il modello in un video montato da una ricetta: inquadrature pianificate dall’IFC, didascalie, musica. Apre Clip Studio con il risultato. Segui presentation-progress.
exportPresentation({ resolution?, music? })Promise<PresentationVideo>Codifica la presentazione nel browser del visitatore e restituisce i byte dell’MP4 — da caricare, allegare o riprodurre in un <video>.
closePresentation()Promise<void>Chiude Clip Studio.
Studio copertine
getCoverOptions()Promise<CoverCatalog>Le ricette, i modelli, i formati e le palette dello studio copertine.
createCover({ recipe?, template?, format?, palette?, text? })Promise<CoverState>Crea una copertina: esegue una ricetta (cattura le viste necessarie), poi imposta modello, formato, palette e testi. Apre lo studio, ancora modificabile.
getCover()Promise<CoverState | null>La copertina così com’è, o null se lo studio è chiuso.
exportCover({ type?, slide? })Promise<CoverFile>Esportala: png / jpeg (una pagina), pdf / pptx (tutto il documento), zip (tutte le pagine). Restituisce i byte.
closeCover()Promise<void>Chiude lo studio copertine.
Kit articolo
activate()voidAvvia subito un visualizzatore differito (ciò che fa il pulsante del poster). Le chiamate precedenti erano in coda.
bindSteps(steps, { rootMargin? })() => voidScrollytelling: mentre ogni paragrafo attraversa il centro dello schermo, inquadra, isola, muove il sole o esegue il tuo codice. Restituisce una funzione per sganciare.
setTurntable(enabled | degPerSec)Promise<{ active, speed }>Una lenta rotazione a riposo (gradi al secondo; false la ferma). Si ferma al primo tocco, mai con movimento ridotto.
toggleFullscreen()Promise<void>Porta la figura a schermo intero, o torna indietro.
setPaused(paused)Promise<{ paused }>Sospende o riprende il rendering. pauseOffscreen lo fa per te.
Gruppi di scena
getGroups()Promise<SceneGroupsState>Tutti i gruppi della scena — dedotti dall’IFC (progetto, sito, posizione) e creati dagli utenti.
createGroup(name, modelIds?)Promise<string>Crea un gruppo, eventualmente con modelli. Restituisce il suo id.
renameGroup(id, name) · deleteGroup(id)Promise<void>Rinomina o elimina un gruppo utente. I gruppi automatici non si modificano.
assignToGroup(itemId, groupId | null | 'loose')Promise<void>Sposta un modello o una nuvola di punti in un gruppo; null lo restituisce al raggruppamento automatico, 'loose' lo lascia senza gruppo.
setGroupVisible(id, visible) · isolateGroup(id | null)Promise<void>Mostra o nasconde un intero gruppo, o ne mostra solo uno.
frameGroup(id)Promise<void>Inquadra la camera su un gruppo, membri nascosti inclusi.
Misure
setMeasureTool(tool)Promise<void>Arma uno strumento di misura per il visitatore (apre il pannello Misura), o 'none'. I risultati arrivano su measurements-changed.
getMeasurements()Promise<MeasurementsState>Tutte le misure sullo schermo. Valori in SI — metri, m², gradi — qualunque cosa mostri il viewer.
clearMeasurements(id?)Promise<MeasurementsState>Rimuove una misura, o tutte.
Query
getModels()Promise<ModelSummary[]>Elenca i modelli caricati. Restituisce una promise.
findElements({ ifcClass?, globalId?, name?, modelId?, limit? })Promise<ElementSummary[]>Trova elementi per classe IFC, GlobalId e/o nome nei modelli caricati. Ogni risultato ha ciò che chiedono getElement(), select() e frame().
getElement(expressId | globalId, modelId?)Promise<IfcElementData | null>Per expressID o GlobalId. I dati IFC di un elemento: attributi con il GlobalId, i suoi set di proprietà e quantità, e quelli del suo tipo — typeName, typeProperties — con unità. effectivePropertySets li unisce e vince il valore proprio dell’elemento.
validate(modelId?, { force? })Promise<ValidationRunResult>Valida un modello adesso (di default, quello attivo) e risolve con il suo Health Score e il conteggio dei problemi. Rifiuta con il motivo.
getValidation()Promise<ValidationSummary | null>Il risultato di validazione a schermo, o null prima che un’esecuzione ne abbia prodotto uno. Vedi «Ciclo della validazione».
getValidationStatus()Promise<ValidationStatus>A che punto è la validazione: idle, running (con avanzamento), done o error.
getStats()Promise<StatsResult>Conteggio elementi per categoria e modello — per i grafici. Restituisce una promise.
getIssues({ severity?, limit?, modelId? })Promise<IssuesResult>Problemi di validazione per una tabella (filtra per gravità / limite). Restituisce una promise.
screenshot()Promise<string>Cattura la vista 3D corrente come data URL PNG. Restituisce una promise.
compare({ base, head, baseLabel?, headLabel? })Promise<{ changes }>Confronta due consegne per URL (per GlobalId) e apre l’area di confronto sul risultato.
Pannelli
openPanel(panel | null) · closePanel()voidApre un pannello strumento, oppure null per chiudere quello aperto. Un pannello non disponibile — nascosto dal chrome, o senza nulla di caricato su cui agire — non fa nulla, e non è un errore.
getPanels()Promise<PanelsResult>Quale pannello è aperto e quali sono offerti in questo momento. Uno strumento assente da `available` non può essere aperto; non è semplicemente disabilitato.
setPanels(panels)voidLimita la barra a questi pannelli, a runtime. Stesso vocabolario del parametro URL `panels=` e ha la precedenza su di esso. Restringe ciò che il viewer offre e non aggiunge mai; un array vuoto significa nessuna barra.
Nuvole di punti
addPointCloud(fileName, bytes)Promise<string>Carica una scansione da byte — LAS, LAZ, COPC, PLY, PCD o testo. Il buffer viene trasferito, non copiato. Restituisce l'id della nuvola.
addPointCloudFromUrl(url, fileName?)Promise<string>Carica una scansione che il visualizzatore scarica da sé. L'URL deve consentire CORS.
listPointClouds()Promise<PointCloudInfo[]>Tutte le scansioni caricate. `pointCount` è ciò che risiede in memoria, `declaredCount` ciò che contiene il file — differiscono quando il budget ha troncato la lettura.
removePointCloud(cloudId) · clearPointClouds()Promise<void>Scarica una scansione e libera i suoi buffer GPU, oppure scaricale tutte.
setPointCloudVisible(cloudId, visible)Promise<void>Mostra o nasconde una scansione senza scaricarla.
fitPointCloud(cloudId?)Promise<void>Inquadra la camera su una scansione, o sulla prima caricata.
setPointCloudDisplay(display, renderBudget?)Promise<void>Dimensione dei punti, opacità, modalità colore, densità, soglia di confidenza — condivisi da tutte. Ognuno è un uniform dello shader, quindi immediato su 20 milioni di punti.
inspectPointCloud(enabled?)Promise<void>Arma il clic per leggere. Da armato, cliccare un punto emette `pointcloud-picked` con le coordinate DEL FILE accanto a quelle della scena.
setPointCloudPlacement(placement, cloudId?)Promise<void>Regola una scansione a mano: posizione, imbardata, livellamento, scala. Parziale e limitato; si applica sopra l'allineamento dedotto senza sostituirlo.
setPointCloudUpAxis(axis, cloudId?)Promise<void>Corregge quale asse la scansione considera verticale. PLY, PCD e testo non dichiarano orientamento, il visualizzatore lo deduce — controlla `upAxisSource`.
Imported 3D models
addMesh(files)Promise<string>Importa un modello da byte. Richiede un ELENCO: un .gltf ha bisogno del suo .bin e delle texture, un .obj del suo .mtl — da solo, il file di ingresso dà geometria grigia.
addMeshFromUrl(urls)Promise<string>Importa un modello che il visualizzatore scarica. Passa tutti gli URL necessari; vengono scaricati in parallelo e devono tutti consentire CORS.
listMeshes()Promise<MeshInfo[]>Tutti i modelli importati, con i conteggi di triangoli e texture. Leggi `unitSource` e `upAxisSource` prima di fidarti dei valori accanto.
removeMesh(meshId?) · clearMeshes()Promise<void>Rimuove un'importazione e libera geometria, materiali e texture, oppure rimuovile tutte.
setMeshVisible(visible, meshId?)Promise<void>Mostra o nasconde un'importazione senza scaricarla.
fitMesh(meshId?)Promise<void>Inquadra la camera su un'importazione, o su tutte.
setMeshPlacement(placement, meshId?)Promise<void>Posiziona un'importazione a mano: posizione, imbardata, livellamento, scala. Parziale e limitato. Le importazioni partono centrate sull'IFC, appoggiate al suo piano.
setMeshUpAxis(axis, meshId?)Promise<void>Corregge l'asse verticale dell'origine. Ha senso solo per OBJ — la specifica glTF impone Y in alto, quindi riporta `upAxisSource: 'declared'`.
setMeshUnit(unitScale, meshId?)Promise<void>Corregge l'unità di origine: 1 metri, 0,01 centimetri, 0,001 millimetri, 0,3048 piedi. Nessuno di questi formati la registra, il visualizzatore la deduce dalla dimensione.
Conformità IDS ed EIR
checkIds(idsXml)Promise<IdsResult>Verifica il modello rispetto a un IDS di buildingSMART (XML .ids). Gira in un worker. Restituisce superato/non superato per specifica.
checkEir(profile)Promise<IdsResult>Verifica il modello rispetto a un profilo di validazione EIR / BIM — un oggetto, il suo JSON (incl. la forma compatta) o l'id di un profilo integrato come 'builtin-en14351-1'. Compilato in IDS ed eseguito dallo stesso motore: stesso IdsResult di checkIds.
Lingue
setLanguage(lang)voidCambia la lingua dell'interfaccia a runtime.
getLanguages()string[]Elenca i codici lingua supportati (etichette in IfcViewer.LANGUAGES).
Ciclo di vita ed eventi
whenReady()Promise<void>Si risolve quando il viewer è pronto ad accettare comandi.
isReadybooleanGetter — true non appena il viewer ha segnalato di essere pronto.
on(event, cb)() => voidIscriviti a un evento; restituisce una funzione di annullamento.
off(event, cb)voidRimuove un listener di eventi aggiunto in precedenza.
dispose()voidSmonta il viewer e rimuovi l'iframe.
Le chiamate concorrenti a add() / addFromUrl() sono serializzate internamente e ogni promise è correlata al proprio caricamento — un caricamento avviato dall’app (parametro URL, upload dentro l’iframe) non risolve mai la tua promise di add().
Opzioni del costruttore
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
ui | 'minimal' | 'full' | 'kiosk' | 'client' | 'article' | 'embed' | 'minimal' | Preset dell’interfaccia. 'embed': per un’app ospite che fornisce il file — 3D, proprietà alla selezione, una barra compatta con Valida e Misura; senza Apri, Condividi, account né lingua. |
toolbar | boolean | preset | Mostra la barra degli strumenti (di default, quella del preset). false lascia la vista 3D e i pannelli. |
tools | ('validate' | 'measure')[] | ['validate', 'measure'] | Strumenti della barra compatta di ui: 'embed' — 'validate', 'measure'. [] per nessuno. |
autoFrame | boolean | true | Inquadra tutta la scena in iso, con margine, ogni volta che un caricamento termina. false lascia a te la camera. |
validate | boolean | true | Esegue la validazione al caricamento (alimenta l’Health Score). |
panel | boolean | false | Apre automaticamente il pannello di validazione. |
panels | PanelName[] | — | Limita la barra degli strumenti a questi pannelli, dal primo fotogramma — `['scene','map']`, oppure `[]` per nessuna barra. Stessi nomi di setPanels e del parametro URL `panels=`. Preferibile a chiamare setPanels dopo il caricamento, che mostra la barra completa e poi toglie strumenti. |
lang | string | auto | Forza la lingua dell’interfaccia (es. en, es, ja). |
accent | #rrggbb | brand | Colora il viewer in tinta con la tua dashboard. |
model | string | — | Carica automaticamente questo URL IFC pubblico non appena pronto. |
background | BackgroundSpec | — | Sfondo della scena dal primo fotogramma — un preset, '#rrggbb' o '#alto,#basso'. |
map | boolean | ('terrain' | 'buildings' | 'showcase')[] | — | Colloca il modello sulla mappa al caricamento: true, o i livelli ['terrain','buildings','showcase']. |
solar · moon | 'MM-DDTHH:MM' · boolean | — | Apre lo studio solare a un'ora locale del sito: '06-21T18:00'. |
scans | string[] | — | URL di nuvole di punti da caricare insieme al modello. |
layers | string | — | Configurazione di livelli di dati da aprire: l’URL di un JSON esportato dal pannello Livelli di dati (fonti dal vivo, stili, avvisi). Dalla 1.16. |
scene | string | — | Scena da aprire: l’URL di un documento di scena (modelli, livelli di dati, dispositivi in tempo reale, mappa, camera). Dalla 1.17. |
view · fill | CameraView · number | — | Quando tutti i modelli sono caricati, inquadrarli stretti da questa vista. ui: 'article' implica 'iso'. |
wheel | 'always' | 'ctrl' | 'always' | 'ctrl': la rotellina scorre la pagina e fa zoom solo con Ctrl/⌘ premuto, come una mappa incorporata. ui: 'article' lo implica. |
lazy | boolean | 'visible' | false | Non caricare nulla finché non serve: true mostra un poster con pulsante, 'visible' si avvia quando la figura si avvicina allo schermo. |
poster · posterTitle · posterText · launchLabel | string | — | Immagine, titolo, testo ed etichetta del pulsante del poster, finché il visualizzatore non è pronto. |
aspectRatio | string ('16/10') | — | Dimensione per proporzione ('16/10'): poster e visualizzatore condividono il riquadro, nulla si sposta nella pagina. |
turntable | boolean | number | false | Lenta rotazione dopo il caricamento (true = 6°/s, o gradi al secondo). |
pauseOffscreen | boolean | ui === 'article' | Non renderizzare fuori schermo. true di default con ui: 'article'. |
fullscreenButton | boolean | false | Un piccolo pulsante di ingrandimento nell’angolo. |
height · width | number | string | '100%' | Dimensione dell’iframe (numero → px). |
baseUrl | string | auto | URL base dell’app. Ricavato dall’URL dello script. |
loadTimeout | number | 120000 | Rifiuta add()/addFromUrl() dopo N ms (0 disattiva). |
className · title | string | — | Classe aggiuntiva / title dell’iframe. |
on* callbacks | function | — | Callback di comodo — equivalenti a .on(...). |
Eventi
| Evento | Payload | Descrizione |
|---|---|---|
ready | { languages } | Viewer montato e pronto. |
model-progress | { percent, phase } | Avanzamento del caricamento (download → parsing → render). |
model-loaded | { modelId, fileName, elementCount, fromCache } | Un modello ha finito di caricare. |
validation-started | { modelId } | È iniziata una validazione su un modello — dopo un caricamento (validate: true) o da validate(). |
validation-completed | { modelId, qualityScore, errors, warnings, info, total } | Validazione completata: l’Health Score e i conteggi, e il modello a cui si riferiscono (null per l’aggregato federato). |
validation-failed | { modelId, message } | Una validazione non è potuta partire o non è terminata — con il motivo. |
model-error | { message, url?, name? } | Un caricamento è fallito. |
element-selected | { expressId, modelId, ifcType, name, globalId } | L’utente ha scelto un elemento — con il suo GlobalId, per collegarlo ai tuoi dati. |
pointcloud-picked | { cloudId, position, sourcePosition, classification, intensity, distance } | È stato letto un punto da una scansione, nelle coordinate del file e non della scena. |
map-feature-picked | { id, name?, label?, featureKind, heightM?, heightEstimated } | È stato cliccato un edificio dei dintorni OpenStreetMap. Contesto, non modello. |
walk-changed | { active, speed } | La modalità passeggiata è stata attivata o disattivata — dal visitatore o dall'host. |
measurements-changed | { tool, units, items } | Una misura è stata aggiunta, rimossa o rinominata. Contiene l’elenco completo. |
tour-started | { title, total, template } | È iniziato un tour. |
tour-step | { index, total, caption } | Il tour è passato a un’altra sosta. |
tour-ended | { completed } | Il tour si è fermato; completed se ha raggiunto l’ultima sosta. |
presentation-progress | { stage, label?, progress } | Il regista sta generando o esportando una presentazione. |
layer-feature-picked | { layerId, layer, featureId, geometry, lonLat, properties } | È stato cliccato un elemento di un livello di dati: il suo livello, le proprietà e un punto da segnare. |
alert | { kind, from, id, name, rule, count, sample } | Una regola di un livello di dati o del gemello ha iniziato o smesso di segnalare un allarme. |
Membri statici
IfcViewer.LANGUAGES ({ code, label }[], nomi nativi) e IfcViewer.SUPPORTED_LANGUAGES (codici) — per costruire un selettore di lingua prima che il viewer sia pronto.
Web component
Zero JavaScript — metti il tag in qualsiasi pagina o dashboard e imposta gli attributi.
Attributi: modeluilangaccentvalidatepanelbase-urltoolbartoolsauto-frame
Gli eventi vengono riemessi come CustomEvent del DOM chiamati ifcviewer:<type> (detail = payload). L’IfcViewer sottostante è su .viewer dell’elemento; getStats / getIssues / screenshot sono delegati a esso.
const el = document.querySelector("ifc-viewer");
el.addEventListener("ifcviewer:validation-completed", (e) => {
updateScore(e.detail.qualityScore);
});
const stats = await el.getStats();Guide
Ricette
Pattern da copiare e incollare, per quello che i team costruiscono davvero.
Ispettore di elementi
Clicca nel 3D e porta i property set IFC nel tuo pannello.
viewer.on("element-selected", async (e) => {
const data = await viewer.getElement(e.expressId, e.modelId);
renderPanel(data.name, data.globalId, data.propertySets);
});Widget Health Score
Mostra il punteggio di qualità del modello e il conteggio dei problemi nella tua dashboard.
viewer.on("validation-completed", (v) => {
setScore(v.qualityScore); // 0–100, or null
setCounts(v.errors, v.warnings, v.info);
});Verifica di conformità IDS
Valida contro un IDS di buildingSMART ed elenca superato / non superato per specifica.
const ids = await fetch("/specs/project.ids").then(r => r.text());
const res = await viewer.checkIds(ids); // runs in a worker
res.specs.forEach((spec) => {
row(spec.name, spec.status, spec.passedCount + "/" + spec.applicableCount);
spec.failures.forEach((f) => onClick(() => viewer.select(f.expressId, f.modelId)));
});Validazione EIR / BIM
Esegui un profilo EIR modificabile (in stile ISO 19650) — senza file .ids. I fallimenti portano il GlobalId dell’elemento.
// An editable EIR profile — object, JSON, or the compact shorthand below.
const profile = {
name: "Door QA",
rules: [
{ type: "requiredProperty", entity: "IfcDoor", property: "FireRating", severity: "error" },
{ type: "allowedValues", entity: "IfcDoor", property: "FireRating",
values: ["EI30", "EI60", "EI90"], severity: "warning" },
],
};
const res = await viewer.checkEir(profile); // same IdsResult as checkIds
res.specs.forEach((spec) => {
spec.failures.forEach((f) => row(spec.name, f.globalId, f.reasons.join(" · ")));
});Una scena per un articolo di blog
Sfondo bianco, il modello nel suo sito e l’ombra serale del solstizio d’estate — dichiarato in anticipo, senza clic.
// Declared up front: the iframe boots with all of it, no clicks, no flash.
const viewer = await IfcViewer.create("#viewer", {
model: "https://example.com/house.ifc",
ui: "client",
background: "white",
map: ["terrain", "buildings"], // your page declares tile consent
solar: "06-21T19:30", // summer solstice, site-local
});
// …or change the story as the reader scrolls
await viewer.setSolar({ date: "12-21", time: "09:30" });
const { attributions } = await viewer.getSiteContext(); // show thesePianta e misure
Taglia una pianta a un livello per nome, lascia misurare il lettore e rileggi i risultati in unità SI.
const { levels } = await viewer.getSections();
await viewer.addSection({ level: levels[0].name }); // floor plan, 1.2 m up
viewer.setView("top");
await viewer.setMeasureTool("distance");
viewer.on("measurements-changed", ({ items }) => {
// value is SI — metres, m², degrees — whatever the viewer displays
render(items.map((m) => m.kind + ": " + m.value?.toFixed(2)));
});Un tour guidato in un articolo
Definisci le soste una volta con getCamera(), poi lascia che il tour scorra da solo accanto al testo.
// 1. Once, while writing the post: frame each view and copy the camera.
console.log(JSON.stringify(await viewer.getCamera()));
// 2. In the page: play the stops, self-running, next to your text.
await viewer.playTour({
title: "Casa Poblenou",
steps: [
{ position: { x: 52, y: 29, z: 24 }, target: { x: 18, y: 7, z: -11 }, caption: "The site" },
{ position: { x: 18, y: 40, z: 11 }, target: { x: 18, y: 0, z: 10 },
caption: "Structure", isolate: ["IfcColumn", "IfcSlab"] },
],
}, { autoplay: 6000 });
viewer.on("tour-step", ({ index, caption }) => highlightParagraph(index));Un video del modello, dalla tua pagina
Genera una presentazione con una ricetta e ricevi l’MP4 — senza registrare lo schermo, senza upload.
viewer.on("presentation-progress", ({ stage, progress }) => bar.value = progress ?? 0);
await viewer.createPresentation("linkedin-teaser", { title: "Casa Poblenou", targetSec: 20 });
const { bytes, mimeType } = await viewer.exportPresentation({ resolution: 1080 });
video.src = URL.createObjectURL(new Blob([bytes], { type: mimeType }));Una copertina per il tuo post
Genera un pin Pinterest o una card LinkedIn del modello con il tuo titolo e ricevi il PNG.
await viewer.createCover({
recipe: "pinterest",
text: { title: "Casa Poblenou", location: "Barcelona", website: "https://example.com" },
});
const { bytes, mimeType } = await viewer.exportCover({ type: "png" });
img.src = URL.createObjectURL(new Blob([bytes], { type: mimeType }));Un modello dentro un articolo
ui: 'article' è solo il canvas, inquadrato perché il modello lo riempia, con una rotellina che lascia continuare a leggere. L’angolo si sceglie con frame().
const viewer = new IfcViewer("#figure", {
ui: "article", // canvas only, tight iso framing, wheel scrolls the page
model: "https://example.com/pavilion.ifc",
lazy: true, // nothing loads until the reader asks
poster: "/img/pavilion.jpg",
posterTitle: "The pavilion, live",
aspectRatio: "16/10", // no layout shift from poster to viewer
background: "auto", // paper on a light page, studio on a dark one
turntable: true, // a slow turn until the reader takes over
fullscreenButton: true,
validate: false,
});Una storia che avanza con il testo
Fissa il visualizzatore e lascia che ogni paragrafo scelga l’inquadratura: isola i muri, gira intorno, porta il sole della sera.
// <div id="figure" style="position:sticky;top:1rem"></div>
// <p id="s1">…</p> <p id="s2">…</p> <p id="s3">…</p>
const viewer = new IfcViewer("#figure", { ui: "article", aspectRatio: "16/10", model: url });
viewer.bindSteps([
{ el: "#s1", frame: { view: "iso" } },
{ el: "#s2", isolate: "IfcWall", frame: { azimuth: 225, elevation: 20 } },
{ el: "#s3", isolate: null, solar: { active: true, date: "06-21", time: "19:30" } },
]);Un gemello di città in tempo reale nella tua pagina
Apri una scena pubblicata, reagisci ai suoi allarmi e clic, aggiungi la tua fonte in tempo reale accanto e condividi un link al risultato.
const viewer = new IfcViewer("#twin", {
ui: "client",
scene: "https://www.ifcvieweronline.eu/scenes/barcelona-placa-catalunya.scene.json",
});
viewer.on("alert", (a) => { if (a.kind === "start") notify(a.name + ": " + a.rule) });
viewer.on("layer-feature-picked", (f) => showCard(f.layer, f.properties));
// Your own live source next to the scene's (GeoJSON with CORS, every 60 s)
await viewer.addLayer({ url: "https://example.org/sensors.geojson", live: 60 });
const { link, sources } = await viewer.exportScene({ title: "Our twin" });Una scheda prodotto nella tua app
Fissa la versione, passa il file e mostra ciò che il produttore ha messo nel tipo: trasmittanza, classe di carico del vento, produttore.
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js";
const viewer = await IfcViewer.create("#product-3d", {
ui: "embed", // 3D + properties, Validate and Measure only
panels: ["properties"],
lang: "es",
});
const bytes = await fetch(product.ifcUrl).then(r => r.arrayBuffer());
await viewer.add("V-70-PR.ifc", bytes); // framed for you
// The product, by class (or by its GlobalId) — no expressIDs to know
const [win] = await viewer.findElements({ ifcClass: "IfcWindow" });
// What the manufacturer put in the type (IfcWindowType → HasPropertySets)
const el = await viewer.getElement(win.globalId);
const pset = (name) => el.effectivePropertySets.find(s => s.name === name);
const uw = pset("Pset_WindowCommon")?.properties.find(p => p.name === "ThermalTransmittance");
console.log(el.typeName, el.globalId, uw?.value, uw?.unit); // "Ventana V-70 practicable" … 1.2 "W/(m²·K)"
const { qualityScore } = await viewer.validate(); // Health Score, on demand
// Declared performance per EN 14351-1: wind, water, acoustics, Uw, g / τv, DoP
const en = await viewer.checkEir("builtin-en14351-1");
const missing = en.specs.filter(s => s.status === "fail").map(s => s.name);Adattalo al tuo brand
Allinea il viewer al tuo prodotto con un solo colore d’accento.
new IfcViewer("#viewer", { accent: "#3fa866" });
// …or on the web component:
// <ifc-viewer accent="#3fa866" model="…"></ifc-viewer>Selettore di lingua
Costruisci un selettore dalle lingue incluse nel viewer.
// build a <select> from the bundled languages
IfcViewer.LANGUAGES.forEach(({ code, label }) => addOption(code, label));
// switch at runtime
viewer.setLanguage("ja");Health Score
Ciclo della validazione
validate: true valida ogni modello appena caricato; validate() la esegue su richiesta e risolve con il risultato. Cosa restituisce getValidation() momento per momento:
| Quando | getValidation() restituisce |
|---|---|
| Prima di qualsiasi validazione | null — getValidationStatus() dice idle. |
| Durante la prima esecuzione | null — getValidationStatus() dice running, con avanzamento; validation-started è già stato emesso. |
| Dopo un’esecuzione | { qualityScore, errors, warnings, info, total, status: 'done', modelId }. Con più modelli, l’aggregato (modelId: null). |
| Durante un’esecuzione più recente | I numeri precedenti, con status: 'running'. |
| Dopo un errore | I numeri precedenti con status: 'error' ed error — o null se non c’erano. È stato emesso validation-failed e validate() ha rifiutato. |
Versioni
Fissa una versione
Dalla 1.18.0, ogni versione è pubblicata anche in un percorso che non cambia mai. Fissala in produzione; il percorso mobile segue l’ultima versione.
<script type="module">
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js";
</script>| Percorso | Cache | Uso |
|---|---|---|
/sdk/ifc-viewer.es.js | riconvalidato a ogni caricamento | Per provare — sempre l’ultima. |
/sdk/1.18.0/ifc-viewer.es.js | immutabile, in cache per un anno | Produzione — il codice testato è il codice che gira. |
Quale viewer apre un SDK fissato?
L’iframe è il viewer dal vivo della stessa origine, non una copia congelata: un SDK fissato mantiene la sua API e il suo comportamento mentre il viewer al suo interno continua a migliorare. Il viewer risponde a ogni comando di qualsiasi SDK pubblicato — il build lo verifica —, quindi una vecchia versione fissata continua a funzionare.
Fissa anche il contenuto
versions.json, accanto all’SDK, elenca l’hash Subresource Integrity di ogni versione:
<script type="module" src="https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js"
integrity="sha384-WsT4d0DS1oqva4rLWCGBDrx50uZVA3B95IDWbfxaFt8lnjs6NgOrjKNcWQL57/0z" crossorigin="anonymous"></script>Registro delle modifiche
1.18.0 — oggetti di catalogo in un’app ospite. getElement() restituisce il GlobalId e i dati del tipo (typeName, typeProperties con unità, effectivePropertySets; tipi IFC4 e stili IFC2x3). validate(), getValidationStatus(), validation-started / validation-failed, e validate: true valida davvero dopo ogni caricamento. Inquadratura automatica dopo il caricamento, fit() e frame() con margine per oggetti piccoli, frame(elementId), e setView() muove di nuovo la camera. ui: 'embed' con toolbar e tools. Versioni fisse in /sdk/1.18.0/. findElements(), GlobalId in getElement() / select() / element-selected, set di telaio e anta di finestre e porte, e i materiali del tipo; in ui: 'embed' il pannello delle proprietà lascia in vista l’oggetto scelto. checkEir('builtin-en14351-1') verifica le prestazioni dichiarate di finestre e porte esterne secondo la EN 14351-1 — vento, tenuta all'acqua, acustica, trasmittanza termica, g e τv, fabbricante e codice prodotto — nei property set IFC standard; le regole EIR acquisiscono where (solo elementi con un valore di proprietà) e optional.
Aiuto
Risoluzione dei problemi
Le poche cose su cui si inciampa.
Non viene renderizzato nulla
Controlla, in quest’ordine: che il viewer abbia raggiunto ready, che il modello sia stato caricato (model-loaded invece di model-error), che il contenitore abbia altezza diversa da zero e che la sorgente di byte sia IFC valido. Il messaggio di model-error indica la causa.
Ricevo un errore CORS caricando un modello
Il CORS riguarda solo addFromUrl(url). Se controlli i byte, scaricali tu e chiama add(name, bytes) — il CORS non si applica perché consegni i dati direttamente.
L’iframe resta bianco o si rifiuta di caricare
L’app deve essere incorporabile — niente X-Frame-Options: DENY e nessuna CSP frame-ancestors restrittiva sull’host. La nostra app ospitata consente l’incorporamento.
Il mio ArrayBuffer è vuoto dopo add()
add() trasferisce il buffer per una consegna senza copia, il che lo lascia detached nel tuo codice. Passa una copia (bytes.slice(0)) se ti servono ancora i byte dopo.
I caricamenti o le query vanno in timeout
add()/addFromUrl() vengono rifiutate dopo loadTimeout (120 s di default; 0 disattiva). Le query dopo 30 s, checkIds dopo 120 s. Modelli grandi su dispositivi lenti possono richiedere un loadTimeout più alto.
Quali browser sono supportati?
Qualsiasi browser moderno con WebAssembly e moduli ES — Chrome, Edge, Firefox, Safari. Niente Internet Explorer.
Ottengo un 404 sul mio server di sviluppo locale
Un dev server SPA può intercettare /sdk/ con il suo fallback HTML. Prova con una build reale o un hosting statico, oppure importa direttamente il modulo /sdk/ifc-viewer.es.js.