Skip to content

Commit

Permalink
Merge pull request #905 from geoadmin/feat-PB-412-infobox-print-impro…
Browse files Browse the repository at this point in the history
…vement

PB-412: Update print to use native print inside a modal for Infobox, Map-Popover and Legend
  • Loading branch information
ltshb authored Jun 18, 2024
2 parents f5b4ee5 + 090ae09 commit 79358e2
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 122 deletions.
65 changes: 14 additions & 51 deletions src/modules/infobox/InfoboxModule.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
<script setup>
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { computed, nextTick, ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { MAX_WIDTH_SHOW_FLOATING_TOOLTIP } from '@/config'
import FeatureEdit from '@/modules/infobox/components/FeatureEdit.vue'
import FeatureElevationProfile from '@/modules/infobox/components/FeatureElevationProfile.vue'
import FeatureList from '@/modules/infobox/components/FeatureList.vue'
import InfoboxContent from '@/modules/infobox/components/InfoboxContent.vue'
import { FeatureInfoPositions } from '@/store/modules/ui.store'
import PrintButton from '@/utils/components/PrintButton.vue'
import TextTruncate from '@/utils/components/TextTruncate.vue'
import ZoomToExtentButton from '@/utils/components/ZoomToExtentButton.vue'
import promptUserToPrintHtmlContent from '@/utils/print'
const dispatcher = { dispatcher: 'InfoboxModule.vue' }
const showContent = ref(true)
const content = ref(null)
const i18n = useI18n()
const store = useStore()
Expand All @@ -25,12 +22,6 @@ const showFeatureInfoInBottomPanel = computed(() => store.getters.showFeatureInf
const showFeatureInfoInTooltip = computed(() => store.getters.showFeatureInfoInTooltip)
const showDrawingOverlay = computed(() => store.state.drawing.drawingOverlay.show)
const width = computed(() => store.state.ui.width)
const selectedFeature = computed(() => selectedFeatures.value[0])
const isSelectedFeatureEditable = computed(() => selectedFeature.value?.isEditable)
const isEditingDrawingFeature = computed(
() => showDrawingOverlay.value && isSelectedFeatureEditable.value
)
const profileFeature = computed(() => store.state.features.profileFeature)
const showElevationProfile = computed(() => profileFeature.value !== null)
Expand Down Expand Up @@ -67,9 +58,6 @@ watch(selectedFeatures, (features) => {
return
}
showContent.value = true
nextTick(() => {
content.value?.scrollTo(0, 0)
})
})
function onToggleContent() {
Expand All @@ -81,9 +69,6 @@ function setTooltipInfoPosition() {
...dispatcher,
})
}
function onPrint() {
promptUserToPrintHtmlContent(content.value)
}
function onClose() {
if (showFeatureInfoInBottomPanel.value) {
store.dispatch('clearAllSelectedFeatures', dispatcher)
Expand Down Expand Up @@ -126,9 +111,16 @@ function onHideProfile() {
:extent="profileFeature.extent"
class="zoom-to-extent-button btn-light"
/>
<button class="btn btn-light btn-sm d-flex align-items-center" @click.stop="onPrint">
<FontAwesomeIcon icon="print" />
</button>
<PrintButton>
<div class="card rounded">
<div
class="header-title d-flex flex-grow-1 justify-content-center p-2 border-bottom"
>
<TextTruncate>{{ title }}</TextTruncate>
</div>
<InfoboxContent :animation="false" />
</div>
</PrintButton>
<button
v-if="showTooltipToggle"
class="btn btn-light btn-sm d-flex align-items-center"
Expand All @@ -155,36 +147,7 @@ function onHideProfile() {
</div>

<!-- if we add d-flex directly in classes, Bootstap's !important overwrites Vue's display none and it is always visible -->
<div
v-show="showContent"
ref="content"
class="infobox-content flex-column"
:class="{ 'd-flex': showContent }"
data-cy="infobox-content"
>
<div
v-if="isEditingDrawingFeature"
class="drawing-feature d-flex flex-column flex-md-row"
>
<FeatureEdit
v-if="showFeatureInfoInBottomPanel"
:feature="selectedFeature"
class="drawing-feature-edit p-3"
:class="{ 'flex-grow-1': !showElevationProfile }"
/>
<FeatureElevationProfile v-if="showElevationProfile" class="flex-grow-1" />
</div>
<div v-else class="d-flex flex-column h-100 overflow-y-auto">
<div
v-if="showElevationProfile"
key="profile-detail"
class="h-100 d-flex flex-column flex-md-row align-content-stretch"
>
<FeatureElevationProfile class="flex-grow-1 profile-with-feature" />
</div>
<FeatureList v-if="showFeatureInfoInBottomPanel" v-show="!showElevationProfile" />
</div>
</div>
<InfoboxContent v-show="showContent" />
</div>
</template>

Expand Down
10 changes: 7 additions & 3 deletions src/modules/infobox/components/FeatureElevationProfile.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import proj4 from 'proj4'
import { computed } from 'vue'
import { computed, toRefs } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
Expand All @@ -14,6 +14,9 @@ import { generateFilename } from '@/utils/utils'
const dispatcher = { dispatcher: 'FeatureElevationProfile.vue' }
const props = defineProps({ animation: { type: Boolean, default: true } })
const { animation } = toRefs(props)
const i18n = useI18n()
const store = useStore()
const projection = computed(() => store.state.position.projection)
Expand Down Expand Up @@ -84,19 +87,20 @@ function onCSVDownload() {
v-if="hasData"
:elevation-profile="profileData"
:tracking-point-color="RED"
:animation="animation"
class="flex-grow-1"
/>
<FeatureElevationProfileInformation v-if="hasData" :profile="profileData">
<button
class="btn btn-light d-flex align-items-center mx-1"
class="btn btn-light d-flex align-items-center mx-1 no-print"
data-cy="profile-popup-csv-download-button"
@click="onCSVDownload"
>
<FontAwesomeIcon icon="download" />
</button>
<button
v-if="isFeatureEditable"
class="btn btn-light d-flex align-items-center"
class="btn btn-light d-flex align-items-center no-print"
data-cy="profile-popup-delete-button"
@click="onDelete"
>
Expand Down
47 changes: 35 additions & 12 deletions src/modules/infobox/components/FeatureElevationProfilePlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
@mouseenter="startPositionTracking"
@mouseleave="stopPositionTracking"
>
<div class="chart-container position-relative w-100">
<LineChart
ref="chart"
:data="chartJsData"
:options="chartJsOptions"
class="profile-graph-container"
data-cy="profile-graph"
@mouseleave="clearHoverPosition"
@contextmenu.prevent="resetZoom"
/>
</div>
<!-- Here below we need to set the w-100 in order to have proper PDF print of the Chart -->
<LineChart
ref="chart"
:data="chartJsData"
:options="chartJsOptions"
class="profile-graph-container w-100"
data-cy="profile-graph"
@mouseleave="clearHoverPosition"
@contextmenu.prevent="resetZoom"
/>
<div
v-show="pointBeingHovered && track"
ref="profileTooltip"
Expand Down Expand Up @@ -107,6 +106,7 @@ export default {
type: FeatureStyleColor,
required: true,
},
animation: { type: Boolean, default: true },
},
data() {
return {
Expand Down Expand Up @@ -345,7 +345,7 @@ export default {
},
chartJsOptions() {
return {
animation: true,
animation: this.animation,
responsive: true,
maintainAspectRatio: false,
plugins: {
Expand All @@ -369,6 +369,20 @@ export default {
}
},
},
mounted() {
// TODO: Here we make sure to do the resize only for the render of the print (currently when animation is disable)
// we should in future use a dedicated variable for this.
if (!this.animation) {
window.addEventListener('beforeprint', this.resizeChartForPrint)
window.addEventListener('afterprint', this.resizeChart)
}
},
unmounted() {
if (!this.animation) {
window.removeEventListener('beforeprint', this.resizeChartForPrint)
window.removeEventListener('afterprint', this.resizeChart)
}
},
methods: {
startPositionTracking() {
this.track = true
Expand All @@ -382,6 +396,15 @@ export default {
resetZoom() {
resetZoom(this.$refs.chart.chart, 'none')
},
resizeChartForPrint() {
// Here in order to have a nice PDF print of the profile we need to resize it to a fix
// size somehow. If we don't do this then the print is a bit deformed and pixelized.
// The resize to 1024x1024 is a choice that provide a nice output
this.$refs.chart.chart.resize(1024, 1024)
},
resizeChart() {
this.$refs.chart.chart.resize()
},
},
}
</script>
Expand Down
2 changes: 1 addition & 1 deletion src/modules/infobox/components/FeatureListCategory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const { t } = useI18n()
<div class="d-flex p-1">
<button
v-if="canLoadMore"
class="btn btn-sm btn-secondary flex-grow-1"
class="btn btn-sm btn-secondary flex-grow-1 no-print"
data-cy="feature-list-load-more"
@click="emits('loadMoreResults')"
>
Expand Down
71 changes: 71 additions & 0 deletions src/modules/infobox/components/InfoboxContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script setup>
import { computed, nextTick, ref, toRefs, watch } from 'vue'
import { useStore } from 'vuex'
import FeatureEdit from '@/modules/infobox/components/FeatureEdit.vue'
import FeatureElevationProfile from '@/modules/infobox/components/FeatureElevationProfile.vue'
import FeatureList from '@/modules/infobox/components/FeatureList.vue'
const props = defineProps({
animation: { type: Boolean, default: true },
})
const { animation } = toRefs(props)
const content = ref(null)
const store = useStore()
const selectedFeatures = computed(() => store.getters.selectedFeatures)
const showFeatureInfoInBottomPanel = computed(() => store.getters.showFeatureInfoInBottomPanel)
const showDrawingOverlay = computed(() => store.state.drawing.drawingOverlay.show)
const selectedFeature = computed(() => selectedFeatures.value[0])
const isSelectedFeatureEditable = computed(() => selectedFeature.value?.isEditable)
const isEditingDrawingFeature = computed(
() => showDrawingOverlay.value && isSelectedFeatureEditable.value
)
const profileFeature = computed(() => store.state.features.profileFeature)
const showElevationProfile = computed(() => profileFeature.value !== null)
watch(selectedFeatures, (features) => {
if (features.length === 0) {
return
}
nextTick(() => {
content.value?.scrollTo(0, 0)
})
})
</script>
<template>
<div ref="content" class="infobox-content flex-column" data-cy="infobox-content">
<div v-if="isEditingDrawingFeature" class="drawing-feature d-flex flex-column flex-md-row">
<FeatureEdit
v-if="showFeatureInfoInBottomPanel"
:feature="selectedFeature"
class="drawing-feature-edit p-3"
:class="{ 'flex-grow-1': !showElevationProfile }"
/>
<FeatureElevationProfile
v-if="showElevationProfile"
class="flex-grow-1"
:animation="animation"
/>
</div>
<div v-else class="d-flex flex-column h-100 overflow-y-auto">
<div
v-if="showElevationProfile"
key="profile-detail"
class="h-100 d-flex flex-column flex-md-row align-content-stretch"
>
<FeatureElevationProfile
class="flex-grow-1 profile-with-feature"
:animation="animation"
/>
</div>
<FeatureList v-if="showFeatureInfoInBottomPanel" v-show="!showElevationProfile" />
</div>
</div>
</template>
6 changes: 5 additions & 1 deletion src/modules/infobox/components/ShowGeometryProfileButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ function showProfile() {
</script>

<template>
<button class="btn btn-xs btn-outline-secondary" data-cy="show-profile" @click="showProfile">
<button
class="btn btn-xs btn-outline-secondary no-print"
data-cy="show-profile"
@click="showProfile"
>
<FontAwesomeIcon icon="fa-chart-area" class="me-1" />
<span>{{ i18n.t('display_profile') }}</span>
</button>
Expand Down
22 changes: 6 additions & 16 deletions src/modules/map/components/MapPopover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import {
cssTimeSliderBarHeight,
cssTimeSliderDropdownHeight,
} from '@/scss/exports'
import PrintButton from '@/utils/components/PrintButton.vue'
import { useMovableElement } from '@/utils/composables/useMovableElement.composable'
import { useTippyTooltip } from '@/utils/composables/useTippyTooltip'
import promptUserToPrintHtmlContent from '@/utils/print'
const props = defineProps({
authorizePrint: {
Expand Down Expand Up @@ -58,6 +57,7 @@ const emits = defineEmits(['close'])
const popoverHeader = ref(null)
const popover = ref(null)
const mapPopoverContent = ref(null)
const showContent = ref(true)
const store = useStore()
Expand Down Expand Up @@ -103,8 +103,6 @@ const popoverLimits = computed(() => {
}
})
useTippyTooltip('.map-popover-header [data-tippy-content]')
onMounted(() => {
if (mode.value === MapPopoverMode.FLOATING && popover.value && popoverHeader.value) {
useMovableElement(popover.value, {
Expand All @@ -117,9 +115,6 @@ onMounted(() => {
function onClose() {
emits('close')
}
function printContent() {
promptUserToPrintHtmlContent('mapPopoverContent')
}
</script>

<template>
Expand Down Expand Up @@ -153,15 +148,10 @@ function printContent() {
<span class="flex-grow-1 align-self-center">
{{ title }}
</span>
<button
v-if="authorizePrint"
class="print-button btn btn-sm btn-light d-flex align-items-center"
data-tippy-content="print"
@click="printContent"
@mousedown.stop=""
>
<FontAwesomeIcon icon="print" />
</button>
<PrintButton
v-if="authorizePrint && showContent"
:content="mapPopoverContent"
></PrintButton>
<slot name="extra-buttons"></slot>
<button
class="btn btn-sm btn-light d-flex align-items-center"
Expand Down
Loading

0 comments on commit 79358e2

Please sign in to comment.