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
282 lines
7.4 KiB
JavaScript
282 lines
7.4 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 updateHS = new OO.ui.ButtonWidget({
|
|
icon: 'reload',
|
|
label: 'Update annotations',
|
|
invisibleLabel: true
|
|
})
|
|
updateHS.on('click', readMvconfig)
|
|
updateHS.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)]
|
|
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 => {
|
|
selectAnnotationSet(selSet.data)
|
|
})
|
|
setSelectHS.setDisabled(true)
|
|
|
|
const hotspotButtons = new OO.ui.ButtonGroupWidget({
|
|
items: [ addHS, updateHS, deleteHS, setSelectHS ]
|
|
})
|
|
|
|
//View Edit 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 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)]
|
|
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 => {
|
|
selectViewConfig(selSet.data)
|
|
})
|
|
selectVC.setDisabled(true)
|
|
|
|
const cameraButtons = new OO.ui.ButtonGroupWidget({
|
|
items: [ downloadViewerImage, setControl, setView, setLims, selectVC ]
|
|
})
|
|
|
|
//Main Menu
|
|
const modelMenu = new OO.ui.HorizontalLayout({
|
|
items: [
|
|
hotspotButtons,
|
|
cameraButtons
|
|
],
|
|
id: 'edit-model-menu'
|
|
})
|
|
|
|
$('#wikiPreview').after(modelMenu.$element)
|
|
|
|
return [modelMenu, selectVC]
|
|
}
|
|
|
|
/**
|
|
* Enable all the preview menu widgets (called by
|
|
* model load event)
|
|
*/
|
|
enableMenu = function() {
|
|
modelMenu.items.forEach(group => {
|
|
group.items.forEach(el => el.setDisabled(false))
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add a selection option to a ButtonMenuSelectWidget
|
|
*
|
|
* @param {ButtonMenuSelectWidget} menuWidget
|
|
*/
|
|
addMenuOption = function(menuWidget) {
|
|
menuWidget.menu.addItems([new OO.ui.MenuOptionWidget({data: 'New option', label: 'New option'})])
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
})
|
|
}
|
|
|
|
//Initialize the menu and get required global objects
|
|
const [modelMenu, viewSelector] = buildPreviewMenu() |