Files
GlModelViewer/modules/glmv-prev.js
2024-11-19 08:53:02 -07:00

350 lines
9.3 KiB
JavaScript

//Initialize globals
require('./glmv-mvconfig.js')
require('./glmv-hs.js')
/**
* Use the OOui js library to create wikis-style menu
* options on the preview edits page for interaction
* with the model
*/
buildPreviewMenu = function() {
let [_, origMetadata] = extractMvconfig()
//Annotation Edit Controls
const addHS = new OO.ui.ButtonWidget({
icon: 'mapPinAdd',
label: 'Add annotation',
invisibleLabel: true,
class: 'edit-button'
})
addHS.on('click', readyAddHotspot)
addHS.setDisabled(true)
const deleteHS = new OO.ui.ButtonWidget({
icon: 'cancel',
label: 'Delete annotation',
invisibleLabel: true
})
deleteHS.on('click', readyDelHotspot)
deleteHS.setDisabled(true)
const setOptions = ['default', ...Object.keys(origMetadata.annotationSets), 'Add new']
let setOptionItems = []
setOptions.forEach(opt => {
setOptionItems.push(new OO.ui.MenuOptionWidget({data: opt, label: opt}))
})
const setSelectHS = new OO.ui.ButtonMenuSelectWidget({
icon: 'mapTrail',
label: 'Select annotation set',
invisibleLabel: true,
menu: {
items: setOptionItems,
width: 'min-content'
},
$overlay: $('#bodyContent')
})
setSelectHS.getMenu().on( 'choose', selSet => {
onSetMenu(selSet.data)
})
setSelectHS.setDisabled(true)
const hotspotButtons = new OO.ui.ButtonGroupWidget({
items: [ addHS, deleteHS, setSelectHS ]
})
//View Edit Controls
const setView = new OO.ui.ButtonWidget({
icon: 'camera',
label: 'Set Initial View',
invisibleLabel: true
})
setView.on('click', writeCameraOrbit)
setView.setDisabled(true)
const setControl = new OO.ui.ButtonWidget({
icon: 'hand',
label: 'Toggle camera control',
invisibleLabel: true
})
setControl.on('click', () => $('model-viewer')[0].toggleAttribute('camera-controls', toggleCameraControl()))
setControl.setDisabled(true)
//View Limit Controls
const setMinYaw = new OO.ui.ButtonWidget({
label: 'Min'
})
setMinYaw.on('click', () => {
writeCameraLimit('yaw','min')
})
const setMaxYaw = new OO.ui.ButtonWidget({
label: 'Max'
})
setMaxYaw.on('click', () => {
writeCameraLimit('yaw','max')
})
const yawLimitButtons = new OO.ui.ButtonGroupWidget({
items: [ setMinYaw, setMaxYaw ]
})
const labelYaw = new OO.ui.LabelWidget({
label: "Yaw:"
})
const yawButtons = new OO.ui.HorizontalLayout({
items: [
labelYaw,
yawLimitButtons
],
id: 'yaw-limits'
})
const setMinPitch = new OO.ui.ButtonWidget({
label: 'Min'
})
setMinPitch.on('click', () => {
writeCameraLimit('pitch','min')
})
const setMaxPitch = new OO.ui.ButtonWidget({
label: 'Max'
})
setMaxPitch.on('click', () => {
writeCameraLimit('pitch','max')
})
const pitchLimitButtons = new OO.ui.ButtonGroupWidget({
items: [ setMinPitch, setMaxPitch ]
})
const labelPitch = new OO.ui.LabelWidget({
label: "Pitch:"
})
const pitchButtons = new OO.ui.HorizontalLayout({
items: [
labelPitch,
pitchLimitButtons
],
id: 'pitch-limits'
})
const setLims = new OO.ui.PopupButtonWidget({
label: 'Set View Limits',
invisibleLabel: true,
icon: 'tableMergeCells',
popup: {
$content: yawButtons.$element.add(pitchButtons.$element),
padded: true,
position: 'above'
},
$overlay: $('#bodyContent')
})
setLims.setDisabled(true)
const setViewConfig = [...Object.keys(origMetadata.viewerConfig), 'Add new']
let setViewItems = []
setViewConfig.forEach(opt => {
setViewItems.push(new OO.ui.MenuOptionWidget({data: opt, label: opt}))
})
const selectVC = new OO.ui.ButtonMenuSelectWidget({
icon: 'eye',
label: 'Select view configuration',
invisibleLabel: true,
menu: {
items: setViewItems,
width: 'min-content'
},
$overlay: $('#bodyContent')
})
selectVC.getMenu().on( 'choose', selSet => {
onViewMenu(selSet.data)
})
selectVC.setDisabled(true)
const cameraButtons = new OO.ui.ButtonGroupWidget({
items: [ setControl, setView, setLims, selectVC ]
})
//General controls
const downloadViewerImage = new OO.ui.ButtonWidget({
icon: 'imageAdd',
label: 'Download current image',
invisibleLabel: true
})
downloadViewerImage.on('click', () => {
downloadImage(mw.config.values.wgTitle)
})
downloadViewerImage.setDisabled(true)
const updateViewer = new OO.ui.ButtonWidget({
icon: 'reload',
label: 'Update from text',
invisibleLabel: true
})
updateViewer.on('click', refreshConfigs)
updateViewer.setDisabled(true)
const generalButtons = new OO.ui.ButtonGroupWidget({
items: [ downloadViewerImage, updateViewer ]
})
//Main Menu
const modelMenu = new OO.ui.HorizontalLayout({
items: [
hotspotButtons,
cameraButtons,
generalButtons
],
id: 'edit-model-menu'
})
$('#wikiPreview').after(modelMenu.$element)
return [modelMenu, selectVC, setSelectHS]
}
/**
* Enable all the preview menu widgets (called by
* model load event)
*/
enableMenu = function() {
modelMenu.items.forEach(group => {
group.items.forEach(el => el.setDisabled(false))
});
}
/**
* Disable general interaction with model
* viewer for specific additional function
*
* @param {string} fnClass class to add to model-viewer
* @param {callback} viewCall callback function to add to model-viewer
* @return {Element} model-viewer element
*/
disableViewer = function(fnClass, viewCall) {
const previewMv = $('model-viewer')
if (viewCall) previewMv.one('click', viewCall)
if (fnClass) previewMv.addClass(fnClass)
previewMv[0].disableTap = true
previewMv[0].toggleAttribute('camera-controls', false)
return previewMv[0]
}
/**
* Enable general interaction with model
* viewer
*
* @return {Element} model-viewer element
*/
enableViewer = function() {
const previewMv = $('model-viewer')
previewMv.off('click', clickAddHotspot)
previewMv.off('click', cancelDeleteHotspot)
previewMv.removeClass('AddingHotspot DeletingHotspot')
previewMv[0].disableTap = false
previewMv[0].toggleAttribute('camera-controls', true)
return previewMv[0]
}
/**
* Use the model viewer methods to get image
* of current view and download
*
* @param {string} defName wiki page name to use as base file name
*/
downloadImage = function(defName) {
const imgName = defName.split('.')[0]
const mView = $('model-viewer')[0]
const dlA = document.createElement('a')
dlA.setAttribute('download',imgName + '.png')
const reader = new FileReader()
reader.addEventListener("load", () => {
dlA.setAttribute('href',reader.result)
dlA.click()
},{once: true})
mView.toBlob(null, null, true)
.then(imgBlob => {
reader.readAsDataURL(imgBlob)
})
}
/**
* Process view selection menu select event
*
* @param {string} selectData data associated with the selected menu label
*/
onViewMenu = function(selectData) {
if (selectData == 'Add new') {
const newSelectIdx = viewSelector.menu.items.length
const newView = `View${newSelectIdx}`
viewSelector.menu.addItems([new OO.ui.MenuOptionWidget({data: newView, label: newView})], newSelectIdx - 1)
addViewConfig(newView)
} else {
selectViewConfig(selectData)
}
}
/**
* Process annotation set menu select event
*
* @param {string} selectData data associated with the selected menu label
*/
onSetMenu = function(selectData) {
if (selectData == 'Add new') {
const newSelectIdx = setSelector.menu.items.length
const newSet = `Set${newSelectIdx - 1}`
setSelector.menu.addItems([new OO.ui.MenuOptionWidget({data: newSet, label: newSet})], newSelectIdx - 1)
addAnnotationSet(newSet)
} else {
selectAnnotationSet(selectData)
}
}
/**
* Update the available menu options in the given menu
* from an array
*
* @param {string} menuTYpe 'set'|'view' to determine which menu to update
* @param {array} newOpts array of strings containing new menu options
*/
updateMenu = function(menuType, newOpts) {
let menuObj
switch (menuType) {
case 'set':
menuObj = setSelector
menuOpts = ['default', ...newOpts, 'Add new']
break
case 'view':
menuObj = viewSelector
menuOpts = [...newOpts, 'Add new']
break
}
menuObj.menu.clearItems()
menuOpts.forEach(opt => {
menuObj.menu.addItems([new OO.ui.MenuOptionWidget({data: opt, label: opt})])
})
}
/**
* Refresh all viewer settings and menus from the edit input text
*/
refreshConfigs = function() {
const newLists = readMvconfig()
if (newLists) {
for (let lst in newLists) {
updateMenu(lst, newLists[lst])
}
}
}
//Initialize the menu and get required global objects
const [modelMenu,
viewSelector,
setSelector] = buildPreviewMenu()