350 lines
9.3 KiB
JavaScript
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() |