The Dental Odontogram can export all treatment and note data as structured JSON, suitable for integration with dental practice management systems, electronic health records, or data analysis.
The JSON export includes:
Patient information : Name and date
Tooth-level data : Treatments categorized by type and layer
Surface mapping : Anatomical surface names for surface-specific treatments
Clinical notes : Per-tooth notes
JSON structure
The exported data follows this structure:
{
"fecha" : "2024-03-15" ,
"nombre" : "Juan Pérez" ,
"piezas" : [
{
"pieza" : 11 ,
"condiciones" : [ "Caries Incurable - Cara/s: vestibular" ],
"prestacion_requerida" : [ "Corona" ],
"prestacion_preexistente" : [ "Obturación - Cara/s: mesial, distal" ],
"notas" : "Paciente refiere sensibilidad al frío"
},
{
"pieza" : 21 ,
"condiciones" : [],
"prestacion_requerida" : [],
"prestacion_preexistente" : [ "Tratamiento de Conducto" ],
"notas" : ""
}
]
}
Field descriptions
Export date in YYYY-MM-DD format (Argentina timezone)
Patient name from DOM or URL parameter
Array of tooth objects with treatment data
Tooth object fields
FDI tooth number (11-48 for permanent, 51-85 for deciduous)
Pathological conditions (caries, paradentosis)
piezas[].prestacion_requerida
Required treatments (blue layer)
piezas[].prestacion_preexistente
Pre-existing treatments (red layer)
Clinical notes for this tooth (empty string if none)
Export implementation
The export is handled by the exportOdontogramData() function in dental-app.js:
function exportOdontogramData () {
const $canvas = $ ( '#odontogram' )
const odontogram = $canvas . data ( 'odontogram' )
if ( ! odontogram ) {
alert ( 'No hay datos para exportar' )
return
}
const geometry = odontogram . geometry || {}
const piezas = []
// Get patient name and date
const patientName = getPatientNameFromDOM () || 'Paciente sin nombre'
const exportDate = new Date (). toLocaleDateString ( 'es-AR' )
// Process each tooth
Object . keys ( geometry ). forEach (( toothKey ) => {
const toothNum = parseInt ( toothKey . split ( '-' )[ 0 ])
const treatments = geometry [ toothKey ] || []
if ( treatments . length === 0 && ! toothNotes [ toothNum ]) return
const toothInfo = getToothInfo ( toothNum )
// Initialize tooth data structure
const toothData = {
pieza: toothNum ,
condiciones: [],
prestacion_requerida: [],
prestacion_preexistente: [],
notas: toothNotes [ toothNum ] || ''
}
// ... categorization logic ...
piezas . push ( toothData )
})
// Create export object
const exportData = {
fecha: exportDate ,
nombre: patientName ,
piezas: piezas
}
// Download as JSON file
const dataStr = JSON . stringify ( exportData , null , 2 )
const blob = new Blob ([ dataStr ], { type: 'application/json' })
const url = URL . createObjectURL ( blob )
const link = document . createElement ( 'a' )
link . href = url
link . download = `odontograma_ ${ patientName } _ ${ new Date (). toISOString (). split ( 'T' )[ 0 ] } .json`
link . click ()
URL . revokeObjectURL ( url )
}
Treatment categorization
Treatments are categorized into three groups:
1. Conditions (pathologies)
const condicionTreatments = treatments . filter (( treatment ) => {
const treatmentCode = treatment . name
const wholeTooth = [ 'PRE' ] // Paradentosis
const withSides = [ 'CARIES_UNTREATABLE' ]
return wholeTooth . includes ( treatmentCode ) || withSides . includes ( treatmentCode )
})
Conditions include:
Paradentosis (PRE)
Caries Incurable (CARIES_UNTREATABLE)
2. Required treatments (blue layer)
const requeridas = prestacionTreatments . filter (
( t ) => t . layer === 'req' || ! t . layer
)
3. Pre-existing treatments (red layer)
const preExistentes = prestacionTreatments . filter (
( t ) => t . layer === 'pre'
)
Surface grouping
Surface-specific treatments are grouped and formatted with anatomical surface names:
function groupTreatmentsBySurface ( treatmentList ) {
const grouped = {}
treatmentList . forEach (( treatment ) => {
const treatmentName = getTreatmentName ( treatment . name )
const withSides = [
'CARIES' , 'CARIES_UNTREATABLE' , 'REF' , 'NVT' ,
'SIL' , 'RES' , 'AMF' , 'COF' , 'INC'
]
if ( ! grouped [ treatment . name ]) {
grouped [ treatment . name ] = {
nombre: treatmentName ,
superficies: [],
usa_superficies: withSides . includes ( treatment . name )
}
}
// Map canvas position to anatomical surface
if ( withSides . includes ( treatment . name ) && treatment . pos && toothInfo ) {
const canvasPositionMap = {
'T' : 'top' , 'B' : 'bottom' , 'L' : 'left' ,
'R' : 'right' , 'M' : 'middle'
}
const fullCanvasPosition = canvasPositionMap [ surfaceCode ]
const correctMapping = getCorrectSurfaceMapping ( toothNum )
const anatomical = correctMapping [ fullCanvasPosition ]
if ( anatomical && ! grouped [ treatment . name ]. superficies . includes ( anatomical )) {
grouped [ treatment . name ]. superficies . push ( anatomical )
}
}
})
return grouped
}
Object . values ( groupedConditions ). forEach (( condition ) => {
let conditionText = condition . nombre
if ( condition . usa_superficies && condition . superficies . length > 0 ) {
conditionText += ` - Cara/s: ${ condition . superficies . join ( ', ' ) } `
}
toothData . condiciones . push ( conditionText )
})
Produces strings like:
"Caries" (whole tooth)
"Obturación - Cara/s: vestibular, mesial" (specific surfaces)
Export examples
Example 1: Simple case
Odontogram state:
Tooth 11: Pre-existing filling (red layer)
Tooth 21: Required crown (blue layer)
JSON output:
{
"fecha" : "15/03/2024" ,
"nombre" : "María González" ,
"piezas" : [
{
"pieza" : 11 ,
"condiciones" : [],
"prestacion_requerida" : [],
"prestacion_preexistente" : [ "Obturación" ],
"notas" : ""
},
{
"pieza" : 21 ,
"condiciones" : [],
"prestacion_requerida" : [ "Corona" ],
"prestacion_preexistente" : [],
"notas" : ""
}
]
}
Example 2: Complex case with surfaces and notes
Odontogram state:
Tooth 16: Caries on mesial and oclusal, required filling, with note
Tooth 26: Pre-existing root canal, required crown
JSON output:
{
"fecha" : "15/03/2024" ,
"nombre" : "Carlos Rodríguez" ,
"piezas" : [
{
"pieza" : 16 ,
"condiciones" : [ "Caries - Cara/s: mesial, oclusal" ],
"prestacion_requerida" : [ "Obturación - Cara/s: mesial, oclusal" ],
"prestacion_preexistente" : [],
"notas" : "Lesión profunda, evaluar RCT si hay dolor"
},
{
"pieza" : 26 ,
"condiciones" : [],
"prestacion_requerida" : [ "Corona" ],
"prestacion_preexistente" : [ "Tratamiento de Conducto" ],
"notas" : ""
}
]
}
Validation
Before export, the system checks for data:
let totalTreatments = 0
let totalNotes = 0
Object . keys ( geometry ). forEach (( key ) => {
totalTreatments += geometry [ key ]. length
})
Object . keys ( toothNotes ). forEach (( key ) => {
if ( toothNotes [ key ]) totalNotes ++
})
if ( totalTreatments === 0 && totalNotes === 0 ) {
alert ( 'No hay tratamientos ni notas para exportar' )
return
}
Integration with backend
The JSON export can be sent to the backend upload endpoint:
// From dental-app.js uploadOdontogram function
const formData = new FormData ()
formData . append ( 'file' , pngBlob , filename )
formData . append ( 'recordId' , recordId )
formData . append ( 'fieldName' , 'odontograma' )
formData . append ( 'jsonData' , JSON . stringify ( exportData ))
formData . append ( 'jsonFieldName' , 'odontograma_json' )
const response = await fetch ( '/api/upload-odontogram' , {
method: 'POST' ,
body: formData
})
See Upload endpoint for backend integration details.
Use cases
Treatment planning Export planned treatments for review or approval
Electronic health records Import dental data into practice management systems
Data backup Store patient odontogram data for archival
Reporting and analytics Analyze treatment patterns across patient populations
Best practices
Export JSON data before generating PNG reports. The JSON contains complete surface-level detail that may be truncated in the PNG.
The export only includes teeth that have treatments or notes. Empty teeth are omitted from the piezas array.
Ensure patient information is accurate before exporting. The patient name is read from the DOM and cannot be changed in the export.
Related pages
PNG reports Generate visual reports
Upload endpoint Send data to backend
FDI mapping Understanding surface mapping
Dual layers Pre-existing vs required layer system