This pr is a significant reorg of the js files. 1) All non-basic functions have been moved out of the main glmv.js 2) 'Metadata' has been universally changed to mvconfig to avoid conflict with actual file metadata 3) Configuration changing functions have been split off into glmv-mvconfig.js 4) Hotspot modification functions have been split off into glmv-hs.js Reviewed-on: #48
269 lines
9.1 KiB
JavaScript
269 lines
9.1 KiB
JavaScript
let currentSet = 'default'
|
|
|
|
/**
|
|
* Convert text in the preview text editor to js object
|
|
*
|
|
* @return [string, object] full mvconfig text string and mvconfig object
|
|
*/
|
|
extractMvconfig = function() {
|
|
const editText = $('#wpTextbox1').val()
|
|
const extractConfig = editText.match(/<mvconfig>([\S\s]*?)<\/mvconfig>/)
|
|
let mvconfig = (extractConfig.length >= 2) ? JSON.parse(extractConfig[1]) : {viewerConfig: {}, annotations: {}, annotationSets: {}}
|
|
if (mvconfig.viewerConfig === undefined) {
|
|
mvconfig.viewerConfig = {
|
|
default: {
|
|
"camera-controls": true
|
|
}
|
|
}
|
|
}
|
|
if (mvconfig.annotations === undefined) {
|
|
mvconfig.annotations = {}
|
|
}
|
|
if (mvconfig.annotationSets === undefined) {
|
|
mvconfig.annotationSets = {}
|
|
}
|
|
return [editText, mvconfig]
|
|
}
|
|
|
|
/**
|
|
* Reads the json string in the edit panel
|
|
* and updates hotspot elements
|
|
*
|
|
* @return {bool} true on successful read and update
|
|
*/
|
|
readMvconfig = function() {
|
|
let hotspotsObj = []
|
|
let mvconfig
|
|
let slotNum = 1
|
|
|
|
createHotspot = function(hsLabel, hsSlot, hsTag) {
|
|
let newHs = document.createElement('button')
|
|
newHs.classList.add('Hotspot')
|
|
newHs.setAttribute('slot',`hotspot-${hsSlot}`)
|
|
newHs.setAttribute('ontouchstart', 'event.stopPropagation()')
|
|
newHs.setAttribute('onclick', 'onAnnotation(event)')
|
|
newHs.setAttribute('onmousedown', 'grabAnnotation(event)')
|
|
newHs.setAttribute('onmouseup', 'releaseAnnotation(event)')
|
|
Object.keys(mvconfig.annotations[hsLabel]).forEach((prop) => {
|
|
newHs.setAttribute(prop, mvconfig.annotations[hsLabel][prop])
|
|
})
|
|
let newAn = document.createElement('div')
|
|
newAn.classList.add('HotspotAnnotation', 'HiddenAnnotation')
|
|
newAn.innerText = hsLabel
|
|
newHs.appendChild(newAn)
|
|
newLabel = document.createElement('span')
|
|
newLabel.innerText = hsTag || (hsSlot)
|
|
newHs.appendChild(newLabel)
|
|
hotspotsObj.push(newHs)
|
|
}
|
|
|
|
try {
|
|
[_, mvconfig] = extractMvconfig()
|
|
} catch (err) {
|
|
console.warn('Failed to read model config:' + err.message)
|
|
return false
|
|
}
|
|
if (currentSet != 'default' && mvconfig.annotationSets[currentSet]) {
|
|
mvconfig.annotationSets[currentSet].forEach(hs => {
|
|
createHotspot(hs, slotNum)
|
|
slotNum += 1
|
|
})
|
|
}
|
|
Object.keys(mvconfig.annotations).forEach(hs => {
|
|
if (currentSet != 'default' && mvconfig.annotationSets[currentSet] && mvconfig.annotationSets[currentSet].includes(hs)) {
|
|
return
|
|
}
|
|
let label = (currentSet != 'default' && mvconfig.annotationSets[currentSet]) ? '-' : null
|
|
createHotspot(hs, slotNum, label)
|
|
slotNum += 1
|
|
})
|
|
|
|
$('model-viewer button').remove()
|
|
const mView = $('model-viewer')[0]
|
|
hotspotsObj.forEach(hs => {
|
|
mView.appendChild(hs)
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Parses the current hotspots into json object
|
|
* and writes the json string to the edit panel
|
|
*
|
|
* @return {bool} true on successful write to edit panel
|
|
*/
|
|
writeMvconfig = function () {
|
|
let annotationsObj = {}
|
|
currentButtons = $('.Hotspot').each(function() {
|
|
let buttonEl = $(this)[0]
|
|
annotationsObj[buttonEl.childNodes[0].innerText] = {
|
|
"data-position": buttonEl.getAttribute('data-position'),
|
|
"data-normal": buttonEl.getAttribute('data-normal'),
|
|
"data-orbit": buttonEl.getAttribute('data-orbit'),
|
|
"data-target": buttonEl.getAttribute('data-target')
|
|
}
|
|
})
|
|
if (Object.keys(annotationsObj).length === 0) return false
|
|
const [currentText, mvconfig] = extractMvconfig()
|
|
mvconfig.annotations = annotationsObj
|
|
const newText = currentText.replace(/(.*?<mvconfig>)[\S\s]*?(<\/mvconfig>.*)/,`$1\n${JSON.stringify(mvconfig, null, 2)}\n$2`)
|
|
$('#wpTextbox1').val(newText)
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Convert all radian values returned by model-viewer to degrees
|
|
*
|
|
* @param {string} orbString string with any number of `(number)rad` sub strings
|
|
* @param {number|array} fix Optional: number of decimal places to return in converted numbers
|
|
* @return {string} string with all radian values and units converted to degrees
|
|
*/
|
|
orb2degree = function(orbString, fix = null) {
|
|
let degArray = orbString.split(' ').map(s => {
|
|
if (s.includes('rad')) {
|
|
return (Number.parseFloat(s) / Math.PI * 180) + 'deg'
|
|
} else {
|
|
return s
|
|
}
|
|
})
|
|
if (fix && !['number', 'object'].includes(typeof fix)) {
|
|
console.warn('orb2degree: fix parameter invalid type. Ignoring.')
|
|
fix = null
|
|
}
|
|
if (fix) {
|
|
degArray = degArray.map((v, idx) => {
|
|
let fixReg = new RegExp('(\\d*.\\d{' + (((typeof fix) == 'object') ? fix[idx] : fix) + '})(\\d*)([a-z]*)')
|
|
return v.replace(fixReg,'$1$3')
|
|
})
|
|
}
|
|
return degArray.join(' ')
|
|
}
|
|
|
|
/**
|
|
* Set camera control setting for the current view
|
|
*
|
|
* @param {string} view
|
|
* @return {bool} new camera-controls setting
|
|
*/
|
|
toggleCameraControl = function(view) {
|
|
let [currentText, mvconfig] = extractMvconfig()
|
|
const currentView = (mvconfig.viewerConfig[view]) ? view : 'default'
|
|
const newControl = !mvconfig.viewerConfig[currentView]['camera-controls']
|
|
if (newControl) {
|
|
mvconfig.viewerConfig[currentView]['camera-controls'] = newControl
|
|
} else {
|
|
delete mvconfig.viewerConfig[currentView]['camera-controls']
|
|
}
|
|
const textUpdate = currentText.replace(/(?<=<mvconfig>)([\S\s]*?)(?=<\/mvconfig>)/gm,`\n${JSON.stringify(mvconfig, null, 2)}\n`)
|
|
$('#wpTextbox1').val(textUpdate)
|
|
return newControl
|
|
}
|
|
|
|
selectViewConfig = function(view) {
|
|
const mView = $('model-viewer')[0]
|
|
let [_, mvconfig] = extractMvconfig()
|
|
const selectView = (mvconfig.viewerConfig[view]) ? view : 'default'
|
|
const viewConfig = mvconfig.viewerConfig[selectView]
|
|
const settings = [
|
|
"camera-controls",
|
|
"disable-pan",
|
|
"disable-tap",
|
|
"touch-action",
|
|
"disable-zoom",
|
|
"orbit-sensitivity",
|
|
"zoom-sensitivity",
|
|
"pan-sensitivity",
|
|
"auto-rotate",
|
|
"auto-rotate-delay",
|
|
"rotation-per-second",
|
|
"interaction-prompt-style",
|
|
"interaction-prompt-threshold",
|
|
"camera-orbit",
|
|
"camera-target",
|
|
"field-of-view",
|
|
"max-camera-orbit",
|
|
"min-camera-orbit",
|
|
"max-field-of-view",
|
|
"min-field-of-view",
|
|
"poster",
|
|
"ar",
|
|
"ar-modes",
|
|
"ar-scale",
|
|
"ar-placement"
|
|
]
|
|
settings.forEach(s => {
|
|
if (viewConfig[s]) {
|
|
mView.setAttribute(s,viewConfig[s])
|
|
} else {
|
|
mView.removeAttribute(s)
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Set new default camera orbit and send values to the preview
|
|
* editor
|
|
*/
|
|
writeCameraOrbit = function() {
|
|
const mView = $('model-viewer')[0]
|
|
const newOrbit = orb2degree(mView.getCameraOrbit().toString(),[2,2,5])
|
|
mView.setAttribute('camera-orbit', newOrbit)
|
|
const targetObj = mView.getCameraTarget()
|
|
const newTarget = `${targetObj.x.toFixed(5)}m ${targetObj.y.toFixed(5)}m ${targetObj.z.toFixed(5)}m`
|
|
mView.setAttribute('camera-target', newTarget)
|
|
const newField = mView.getFieldOfView().toFixed(5) + 'deg'
|
|
mView.setAttribute('field-of-view',newField)
|
|
let [currentText, mvconfig] = extractMvconfig()
|
|
mvconfig.viewerConfig.default['camera-orbit'] = newOrbit
|
|
mvconfig.viewerConfig.default['camera-target'] = newTarget
|
|
mvconfig.viewerConfig.default['field-of-view'] = newField
|
|
const textUpdate = currentText.replace(/(?<=<mvconfig>)([\S\s]*?)(?=<\/mvconfig>)/gm,`\n${JSON.stringify(mvconfig, null, 2)}\n`)
|
|
$('#wpTextbox1').val(textUpdate)
|
|
}
|
|
|
|
/**
|
|
* Set new camera orbit limits and send values to the preview
|
|
* editor
|
|
*
|
|
* @param {string} axis [yaw|pitch] orbit value to set
|
|
* @param {string} limit [max|min] limit value to set
|
|
*/
|
|
writeCameraLimit = function(axis, limit) {
|
|
const mView = $('model-viewer')[0]
|
|
const newOrbit = orb2degree(mView.getCameraOrbit().toString(),[2,2,5])
|
|
const newOrbitVals = newOrbit.split(' ')
|
|
const valueIndex = (axis == 'yaw') ? 0 : 1
|
|
let [currentText, mvconfig] = extractMvconfig()
|
|
const oldOrbit = mvconfig.viewerConfig.default[`${limit}-camera-orbit`]
|
|
let oldOrbitVals = (oldOrbit) ? oldOrbit.split(' ') : Array(3).fill('auto')
|
|
oldOrbitVals[valueIndex] = newOrbitVals[valueIndex]
|
|
mvconfig.viewerConfig.default[`${limit}-camera-orbit`] = oldOrbitVals.join(' ')
|
|
mView.setAttribute(`${limit}-camera-orbit`, oldOrbitVals.join(' '))
|
|
const textUpdate = currentText.replace(/(?<=<mvconfig>)([\S\s]*?)(?=<\/mvconfig>)/gm,`\n${JSON.stringify(mvconfig, null, 2)}\n`)
|
|
$('#wpTextbox1').val(textUpdate)
|
|
}
|
|
|
|
/**
|
|
* Change the currently selected annotation set
|
|
*
|
|
* @param {string} newSet name of annotation set to select
|
|
*/
|
|
selectAnnotationSet = function(newSet) {
|
|
currentSet = newSet
|
|
readMvconfig()
|
|
}
|
|
|
|
/*
|
|
export default {
|
|
extractMvconfig,
|
|
readMvconfig,
|
|
writeMvconfig,
|
|
orb2degree,
|
|
toggleCameraControl,
|
|
selectViewConfig,
|
|
writeCameraOrbit,
|
|
writeCameraLimit,
|
|
selectAnnotationSet
|
|
}
|
|
*/ |