Compare commits
9 Commits
a2246015c9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8294edc1d1 | |||
| 846106a1a8 | |||
| 717ef152f1 | |||
| 859183fe2e | |||
| 9953dff4a0 | |||
| 8ed4e1f679 | |||
| 7e353bee24 | |||
| 383818b6f8 | |||
| 88cd5e4727 |
@@ -183,10 +183,10 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
$attrModelView = array_merge(['src' => $srcUrl, 'class' => 'mv-model', 'interpolation-decay' => '100', 'interaction-prompt' => 'none'], $attrModelView);
|
||||
$attrModelView['style'] = 'width: 100%; height: 100%;';
|
||||
$attrModelView['onload'] = 'modelLoaded(event)';
|
||||
$hotspotHtml = (isset($hotspots)) ? implode($hotspots) : '';
|
||||
$hotspotHtml = (!empty($hotspots)) ? implode($hotspots) : '';
|
||||
|
||||
$elModel = Html::rawElement('model-viewer', $attrModelView, $hotspotHtml);
|
||||
$elMenu = self::buildViewMenu();
|
||||
$elMenu = self::buildViewMenu(!empty($hotspots));
|
||||
|
||||
$elFileLink = '';
|
||||
if (!isset($viewParams['preview']) && $context->getTitle() != $this->file->getTitle()) {
|
||||
@@ -213,9 +213,10 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
/**
|
||||
* Build the button menu used for viewer actions
|
||||
*
|
||||
* @param bool $annotsDrawn true to enable the annotation buttons
|
||||
* @return string
|
||||
*/
|
||||
private static function buildViewMenu() {
|
||||
private static function buildViewMenu($annotsDrawn) {
|
||||
$attrMenu = array(
|
||||
'class' => 'glmv-menu awaiting-model',
|
||||
'style' => 'display: none;'
|
||||
@@ -230,13 +231,15 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
|
||||
$gotoUrl = $mainConfig->get( 'ExtensionAssetsPath' ) . '/GlModelViewer/resources/goto_hs.svg';
|
||||
$attrMenuButtonPrev = array (
|
||||
'class' => 'glmv-menu-button prev-hs disable-on-hide',
|
||||
'class' => 'glmv-menu-button prev-hs disable-on-hide disable-on-none',
|
||||
'disabled' => !$annotsDrawn,
|
||||
'onclick' => 'prevAnnotation(event.target.closest(".glmv-container").querySelector("model-viewer"))',
|
||||
'onmousedown' => 'event.stopPropagation()',
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
);
|
||||
$attrMenuButtonNext = array (
|
||||
'class' => 'glmv-menu-button next-hs disable-on-hide',
|
||||
'class' => 'glmv-menu-button next-hs disable-on-hide disable-on-none',
|
||||
'disabled' => !$annotsDrawn,
|
||||
'onclick' => 'nextAnnotation(event.target.closest(".glmv-container").querySelector("model-viewer"))',
|
||||
'onmousedown' => 'event.stopPropagation()',
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
@@ -244,7 +247,8 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
|
||||
$slideUrl = $mainConfig->get( 'ExtensionAssetsPath' ) . '/GlModelViewer/resources/hs_slideshow.svg';
|
||||
$attrMenuButtonSlides = array (
|
||||
'class' => 'glmv-menu-button disable-on-hide',
|
||||
'class' => 'glmv-menu-button disable-on-hide disable-on-none',
|
||||
'disabled' => !$annotsDrawn,
|
||||
'onclick' => 'event.target.toggleAttribute("toggled"); slideshowAnnotations(event.target.closest(".glmv-container").querySelector("model-viewer"))',
|
||||
'onmousedown' => 'event.stopPropagation()',
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
@@ -252,7 +256,8 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
|
||||
$hideUrl = $mainConfig->get( 'ExtensionAssetsPath' ) . '/GlModelViewer/resources/hs_hide.svg';
|
||||
$attrMenuButtonHide = array (
|
||||
'class' => 'glmv-menu-button',
|
||||
'class' => 'glmv-menu-button disable-on-none',
|
||||
'disabled' => !$annotsDrawn,
|
||||
'onclick' => 'event.target.toggleAttribute("toggled"); toggleAnnotations(event.target.closest(".glmv-container").querySelector("model-viewer"))',
|
||||
'onmousedown' => 'event.stopPropagation()',
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
@@ -267,12 +272,21 @@ class GlModelTransformOutput extends MediaTransformOutput {
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
);
|
||||
|
||||
$resetUrl = $mainConfig->get( 'ExtensionAssetsPath' ) . '/GlModelViewer/resources/reset.svg';
|
||||
$attrMenuButtonReset = array (
|
||||
'class' => 'glmv-menu-button',
|
||||
'onclick' => 'resetView(event.target.closest(".glmv-container").querySelector("model-viewer"))',
|
||||
'onmousedown' => 'event.stopPropagation()',
|
||||
'ontouchstart' => 'event.stopPropagation()'
|
||||
);
|
||||
|
||||
$menuButtons = array(
|
||||
Html::rawElement('div', $attrMenuButtonPrev, '<img class="awaiting-model" src="' . $gotoUrl . '"></image>'),
|
||||
Html::rawElement('div', $attrMenuButtonSlides, '<img class="awaiting-model" src="' . $slideUrl . '"></image>'),
|
||||
Html::rawElement('div', $attrMenuButtonNext, '<img class="awaiting-model" src="' . $gotoUrl . '"></image>'),
|
||||
Html::rawElement('div', $attrMenuButtonHide, '<img class="awaiting-model" src="' . $hideUrl . '"></image>'),
|
||||
Html::rawElement('div', $attrMenuButtonScreen, '<img class="awaiting-model full-hide" src="' . $screenUpUrl . '"></image><img class="awaiting-model full-show" src="' . $screenDownUrl . '"></image>')
|
||||
Html::rawElement('div', $attrMenuButtonScreen, '<img class="awaiting-model full-hide" src="' . $screenUpUrl . '"></image><img class="awaiting-model full-show" src="' . $screenDownUrl . '"></image>'),
|
||||
Html::rawElement('div', $attrMenuButtonReset, '<img class="awaiting-model" src="' . $resetUrl . '"></image>')
|
||||
);
|
||||
|
||||
return Html::rawElement('div', $attrMenu, $menuImg . implode($menuButtons));
|
||||
|
||||
@@ -69,13 +69,15 @@ clickDeleteHotspot = function (hs) {
|
||||
deleteHotspot = null
|
||||
enableViewer()
|
||||
const anName = hs.target.childNodes[0].innerText
|
||||
let purgeAnnotation = new RegExp('(?<="annotationSets"[\\S\\s]*?)(^.*?' + anName + '.*\n)','gm')
|
||||
hs.target.remove()
|
||||
const editText = $('#wpTextbox1').val()
|
||||
const newText = editText.replace(purgeAnnotation,'')
|
||||
const finalText = newText.replace(/(,)(\n\s+])/gm,'$2')
|
||||
$('#wpTextbox1').val(finalText)
|
||||
writeMvconfig()
|
||||
let currentText = $('#wpTextbox1').val()
|
||||
let [_, mvconfig] = extractMvconfig(currentText)
|
||||
delete mvconfig.annotations[anName]
|
||||
for (anSet in mvconfig.annotationSets) {
|
||||
mvconfig.annotationSets[anSet]=mvconfig.annotationSets[anSet].filter( x => x !== anName )
|
||||
}
|
||||
let newText = currentText.replace(/(.*?<mvconfig>)[\S\s]*?(<\/mvconfig>.*)/,`$1\n${TOML.stringify(mvconfig, null, 2)}\n$2`)
|
||||
$('#wpTextbox1').val(newText)
|
||||
readMvconfig()
|
||||
}
|
||||
|
||||
@@ -93,7 +95,7 @@ isDeleting = function() {
|
||||
*/
|
||||
grabAnnotation = function(e) {
|
||||
if (e.ctrlKey) {
|
||||
grabHotspot = {x: e.x, y: e.y}
|
||||
grabHotspot = {x: e.x, y: e.y, target: e.target}
|
||||
const contEl = $('.glmv-container')[0]
|
||||
contEl.addEventListener('mousemove', moveAnnotation)
|
||||
const mvEl = $('model-viewer')[0]
|
||||
@@ -110,7 +112,7 @@ grabAnnotation = function(e) {
|
||||
moveAnnotation = function(e) {
|
||||
if (grabHotspot) {
|
||||
grabHotspot.move = true
|
||||
e.target.style['transform'] = `translate(${e.x - grabHotspot.x}px, ${e.y - grabHotspot.y}px) scale(1.1,1.1)`
|
||||
grabHotspot.target.style['transform'] = `translate(${e.x - grabHotspot.x}px, ${e.y - grabHotspot.y}px) scale(1.1,1.1)`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ extractMvconfig = function() {
|
||||
if (mvconfig.annotations === undefined) {
|
||||
mvconfig.annotations = {}
|
||||
}
|
||||
const mView = $('model-viewer')[0]
|
||||
const hsButtons = [...mView.parentElement.querySelectorAll('.disable-on-none')]
|
||||
hsButtons.forEach( mb => {
|
||||
mb.toggleAttribute('disabled',$.isEmptyObject(mvconfig.annotations))
|
||||
})
|
||||
|
||||
if (mvconfig.annotationSets === undefined) {
|
||||
mvconfig.annotationSets = {}
|
||||
}
|
||||
@@ -36,7 +42,7 @@ readMvconfig = function() {
|
||||
let mvconfig
|
||||
let slotNum = 1
|
||||
|
||||
createHotspot = function(hsLabel, hsSlot, hsTag) {
|
||||
createHotspot = function(hsLabel, hsSlot, hsTag, hsSkip) {
|
||||
let newHs = document.createElement('button')
|
||||
newHs.classList.add('Hotspot')
|
||||
newHs.setAttribute('slot',`hotspot-${hsSlot}`)
|
||||
@@ -44,6 +50,7 @@ readMvconfig = function() {
|
||||
newHs.setAttribute('onclick', 'onAnnotation(event)')
|
||||
newHs.setAttribute('onmousedown', 'grabAnnotation(event)')
|
||||
newHs.setAttribute('onmouseup', 'releaseAnnotation(event)')
|
||||
newHs.toggleAttribute('seq-skip', !!hsSkip)
|
||||
Object.keys(mvconfig.annotations[hsLabel]).forEach((prop) => {
|
||||
newHs.setAttribute(prop, mvconfig.annotations[hsLabel][prop])
|
||||
})
|
||||
@@ -75,7 +82,7 @@ readMvconfig = function() {
|
||||
return
|
||||
}
|
||||
let label = (currentSet != 'default' && mvconfig.annotationSets[currentSet]) ? '-' : null
|
||||
createHotspot(hs, slotNum, label)
|
||||
createHotspot(hs, slotNum, label, true)
|
||||
slotNum += 1
|
||||
})
|
||||
|
||||
@@ -238,6 +245,7 @@ selectViewConfig = function(view) {
|
||||
mView.removeAttribute(s)
|
||||
}
|
||||
})
|
||||
mView.setAttribute('current-view',selectView)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,6 +254,7 @@ selectViewConfig = function(view) {
|
||||
*/
|
||||
writeCameraOrbit = function() {
|
||||
const mView = $('model-viewer')[0]
|
||||
const currentView = mView.getAttribute('current-view') ? mView.getAttribute('current-view') : 'default'
|
||||
const newOrbit = orb2degree(mView.getCameraOrbit().toString(),[2,2,5])
|
||||
mView.setAttribute('camera-orbit', newOrbit)
|
||||
const targetObj = mView.getCameraTarget()
|
||||
@@ -254,9 +263,9 @@ writeCameraOrbit = function() {
|
||||
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
|
||||
mvconfig.viewerConfig[currentView]['camera-orbit'] = newOrbit
|
||||
mvconfig.viewerConfig[currentView]['camera-target'] = newTarget
|
||||
mvconfig.viewerConfig[currentView]['field-of-view'] = newField
|
||||
const textUpdate = currentText.replace(/(?<=<mvconfig>)([\S\s]*?)(?=<\/mvconfig>)/gm,`\n${TOML.stringify(mvconfig, null, 2)}\n`)
|
||||
$('#wpTextbox1').val(textUpdate)
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
justify-content: flex-start;
|
||||
|
||||
&:hover {
|
||||
width: 196px;
|
||||
width: 232px;
|
||||
|
||||
& .glmv-menu-image {
|
||||
transform: rotate(180deg);
|
||||
@@ -209,7 +209,7 @@
|
||||
border-radius: 9px;
|
||||
|
||||
&:hover {
|
||||
width: 294px;
|
||||
width: 342px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ selectAnnotation = function(mView, annotId) {
|
||||
*/
|
||||
nextAnnotation = function(mView) {
|
||||
let incrAnnotation = 0
|
||||
const numSpots = [...mView.querySelectorAll('Button')].length
|
||||
const numSpots = [...mView.querySelectorAll('Button:not([seq-skip])')].length
|
||||
const currentAnnotation = mView.querySelectorAll('Button:has(.HotspotAnnotation:not(.HiddenAnnotation))')[0]
|
||||
if (!currentAnnotation) {
|
||||
incrAnnotation = 1
|
||||
@@ -95,7 +95,7 @@ nextAnnotation = function(mView) {
|
||||
*/
|
||||
prevAnnotation = function(mView) {
|
||||
let decrAnnotation = 0
|
||||
const numSpots = [...mView.querySelectorAll('Button')].length
|
||||
const numSpots = [...mView.querySelectorAll('Button:not([seq-skip])')].length
|
||||
const currentAnnotation = mView.querySelectorAll('Button:has(.HotspotAnnotation:not(.HiddenAnnotation))')[0]
|
||||
if (!currentAnnotation) {
|
||||
decrAnnotation = numSpots
|
||||
@@ -158,4 +158,18 @@ toggleFullScreen = function(glCont) {
|
||||
} else {
|
||||
glCont.requestFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset view to initial position
|
||||
*
|
||||
* @param {ModelViewer} mView
|
||||
*/
|
||||
resetView = function(mView) {
|
||||
const resetOrb = mView.getAttribute('camera-orbit') || 'auto auto auto'
|
||||
const resetTarg = mView.getAttribute('camera-target') || 'auto auto auto'
|
||||
const resetFov = mView.getAttribute('field-of-view') || 'auto'
|
||||
mView.cameraOrbit = resetOrb
|
||||
mView.cameraTarget = resetTarg
|
||||
mView.fieldOfView = resetFov
|
||||
}
|
||||
1
resources/reset.svg
Normal file
1
resources/reset.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M320-280q-33 0-56.5-23.5T240-360v-240q0-33 23.5-56.5T320-680h40l40-40h160l40 40h40q33 0 56.5 23.5T720-600v240q0 33-23.5 56.5T640-280H320Zm0-80h320v-240H320v240Zm160-40q33 0 56.5-23.5T560-480q0-33-23.5-56.5T480-560q-33 0-56.5 23.5T400-480q0 33 23.5 56.5T480-400ZM342-940q34-11 68.5-15.5T480-960q94 0 177.5 33.5t148 93Q870-774 911-693.5T960-520h-80q-7-72-38-134.5t-79.5-110Q714-812 651-842t-135-36l62 62-56 56-180-180ZM618-20Q584-9 549.5-4.5T480 0q-94 0-177.5-33.5t-148-93Q90-186 49-266.5T0-440h80q8 72 38.5 134.5t79 110Q246-148 309-118t135 36l-62-62 56-56L618-20ZM480-480Z"/></svg>
|
||||
|
After Width: | Height: | Size: 696 B |
Reference in New Issue
Block a user