<template>
<!-- 垂直選單: 改用w-threejs-vue同款組件WGroupIconCheck(:dir='vertical'), 最頂為設定鈕, 收合時僅顯示設定鈕, 展開才顯示其餘按鈕 -->
<div
v-if="cfg.useMenu"
:class="['vue-flow__panel', `vue-flow__panel--${cfg.menuPosition}`]"
:style="panelStyle"
>
<!-- 淺色系配色(w-flow-vue圖台為白底, 沿用原Controls之#fefefe白底/深灰icon風格; iconSize預設22, 按鈕寬=22+左右padding8=30px與w-threejs-vue選單一致) -->
<!-- 全數為一般動作鈕(不用active態): 鎖頭點擊即切換上鎖/解鎖並換icon(比照fitView等), 不留固定灰底; value恆空故無任一鈕呈active, 故不開放*ColorActive類選項 -->
<WGroupIconCheck
:items="useItems"
:dir="'vertical'"
:iconColor="cfg.menuIconColor"
:iconColorHover="cfg.menuIconColorHover"
:iconColorFocus="cfg.menuIconColorFocus"
:iconSize="cfg.menuIconSize"
:backgroundColor="cfg.menuBackgroundColor"
:backgroundColorHover="cfg.menuBackgroundColorHover"
:backgroundColorFocus="cfg.menuBackgroundColorFocus"
:seplineColor="cfg.menuSeparatorColor"
:shadow="cfg.menuShadow"
:tooltipTextColor="cfg.menuTooltipTextColor"
:tooltipTextFontSize="cfg.menuTooltipTextFontSize"
:tooltipBackgroundColor="cfg.menuTooltipBackgroundColor"
:value="[]"
@click="onClickItem"
></WGroupIconCheck>
</div>
</template>
<script>
import WGroupIconCheck from 'w-component-vue/src/components/WGroupIconCheck.vue'
import { mdiCogOutline, mdiMagnifyPlusOutline, mdiMagnifyMinusOutline, mdiFitToPageOutline, mdiLockOutline, mdiLockOpenVariantOutline } from '@mdi/js/mdi.js'
//menuDef, 選單各項之預設值, 未被opt覆寫者沿用之
//注意: menuIconSize, menuTooltipTextColor, menuTooltipBackgroundColor原為WGroupIconCheck之預設值,
//因w-component-vue為浮動相依(^2.5.2), 子套件改預設會靜默改變本套件外觀, 故於此明寫鎖住現值
let menuDef = {
//整體
useMenu: true,
menuPosition: 'top-left',
menuYShift: 0,
useSetting: true,
//設定鈕(收合/展開)
menuSettingIcon: mdiCogOutline,
menuSettingTooltip: 'Settings',
//放大
useMenuItemZoomIn: true,
menuZoomInIcon: mdiMagnifyPlusOutline,
menuZoomInTooltip: 'Zoom In',
//縮小
useMenuItemZoomOut: true,
menuZoomOutIcon: mdiMagnifyMinusOutline,
menuZoomOutTooltip: 'Zoom Out',
//全圖
useMenuItemFitView: true,
menuFitViewIcon: mdiFitToPageOutline,
menuFitViewTooltip: 'Fit View',
//鎖定(雙態: 無後綴為未鎖態, Locked後綴為已鎖態)
useMenuItemLock: true,
menuLockIcon: mdiLockOpenVariantOutline,
menuLockTooltip: 'Lock',
menuLockIconLocked: mdiLockOutline,
menuLockTooltipLocked: 'Unlock',
//樣式
menuIconColor: '#555',
menuIconColorHover: '#222',
menuIconColorFocus: '#222',
menuIconSize: 22,
menuBackgroundColor: '#fefefe',
menuBackgroundColorHover: '#f0f0f0',
menuBackgroundColorFocus: '#f0f0f0',
menuSeparatorColor: '#e6e6e6',
menuShadow: true,
menuTooltipTextColor: 'white',
menuTooltipTextFontSize: '0.7rem',
menuTooltipBackgroundColor: 'rgba(60,60,60,0.75)',
}
//menuPositions, menuPosition之允許值, 不在其中者回退預設
let menuPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right']
/**
* 取單項設定值, 型別與menuDef同型且有效才採用, 否則回退menuDef
*/
function pickMenuValue(k, v) {
let d = menuDef[k]
if (typeof d === 'string') {
return (typeof v === 'string' && v !== '') ? v : d
}
if (typeof d === 'boolean') {
return (typeof v === 'boolean') ? v : d
}
if (typeof d === 'number') {
return (typeof v === 'number' && isFinite(v)) ? v : d
}
return d
}
export default {
name: 'FlowControls',
components: { WGroupIconCheck },
props: {
//選單設定物件, 鍵值同menuDef, 由WFlowVue自opt原樣取出後傳入; 各鍵未給或型別不符即回退menuDef
menu: { type: Object, default: () => ({}) },
locked: { type: Boolean, default: false },
},
data() {
return {
//設定鈕展開狀態(收合時僅顯示設定鈕, 展開才顯示其餘按鈕), 比照w-threejs-vue; 初值取menu.useSetting
useSetting: pickMenuValue('useSetting', (this.menu || {}).useSetting),
}
},
computed: {
cfg() {
let m = this.menu || {}
let r = {}
for (let k in menuDef) {
r[k] = pickMenuValue(k, m[k])
}
//menuPosition另檢核列舉值
if (menuPositions.indexOf(r.menuPosition) < 0) {
r.menuPosition = menuDef.menuPosition
}
return r
},
allItems() {
let c = this.cfg
let rs = [
{ id: 'setting', icon: c.menuSettingIcon, tooltip: c.menuSettingTooltip },
]
if (c.useMenuItemZoomIn) {
rs.push({ id: 'zoomIn', icon: c.menuZoomInIcon, tooltip: c.menuZoomInTooltip })
}
if (c.useMenuItemZoomOut) {
rs.push({ id: 'zoomOut', icon: c.menuZoomOutIcon, tooltip: c.menuZoomOutTooltip })
}
if (c.useMenuItemFitView) {
rs.push({ id: 'fitView', icon: c.menuFitViewIcon, tooltip: c.menuFitViewTooltip })
}
if (c.useMenuItemLock) {
rs.push({ id: 'interactive', icon: this.locked ? c.menuLockIconLocked : c.menuLockIcon, tooltip: this.locked ? c.menuLockTooltipLocked : c.menuLockTooltip })
}
return rs
},
useItems() {
//設定鈕恆在最頂; 收合時僅顯示設定鈕
if (this.useSetting) {
return this.allItems
}
return [this.allItems[0]]
},
panelStyle() {
//向下偏移: top-*位置加margin-top, bottom-*位置加margin-bottom(margin於絕對定位元素上等同再位移該側)
//故menuYShift之語義為[正值使選單遠離其錨定邊]: top-*向下, bottom-*向上
let s = 'z-index:5;'
if (this.cfg.menuPosition.indexOf('bottom') >= 0) {
s += `margin-bottom:${this.cfg.menuYShift}px;`
}
else {
s += `margin-top:${this.cfg.menuYShift}px;`
}
return s
},
},
methods: {
onClickItem(item) {
let id = (item && item.id) || ''
if (id === 'setting') {
this.useSetting = !this.useSetting
}
else if (id === 'zoomIn') {
this.$emit('zoom-in')
}
else if (id === 'zoomOut') {
this.$emit('zoom-out')
}
else if (id === 'fitView') {
this.$emit('fit-view')
}
else if (id === 'interactive') {
this.$emit('toggle-interactive')
}
},
},
}
</script>
<style scoped>
.vue-flow__panel {
position: absolute;
z-index: 5;
}
.vue-flow__panel--top-left { top: 10px; left: 10px; }
.vue-flow__panel--top-right { top: 10px; right: 10px; }
.vue-flow__panel--bottom-left { bottom: 10px; left: 10px; }
.vue-flow__panel--bottom-right { bottom: 10px; right: 10px; }
</style>