|
|
@@ -8,13 +8,45 @@
|
|
|
</view>
|
|
|
<template v-else>
|
|
|
<!-- #ifdef H5 -->
|
|
|
- <view class="pdf-viewer-wrapper">
|
|
|
- <view class="pdf-container" :id="containerId"></view>
|
|
|
+ <view class="pdf-viewport" :id="viewportId" :style="{ height: viewerHeight }">
|
|
|
+ <view class="pdf-transform-layer" :style="transformStyle">
|
|
|
+ <view class="pdf-container" :id="containerId"></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="pdf-zoom-bar">
|
|
|
+ <view class="zoom-btn" @click="zoomOut">
|
|
|
+ <text class="zoom-btn-text">−</text>
|
|
|
+ </view>
|
|
|
+ <text class="zoom-label">{{ zoomPercent }}%</text>
|
|
|
+ <view class="zoom-btn" @click="zoomIn">
|
|
|
+ <text class="zoom-btn-text">+</text>
|
|
|
+ </view>
|
|
|
+ <view class="zoom-btn zoom-btn-reset" @click="resetZoom">
|
|
|
+ <text class="zoom-btn-text">重置</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
<!-- #endif -->
|
|
|
<!-- #ifndef H5 -->
|
|
|
- <view v-if="imageSrc" class="pdf-image-container">
|
|
|
- <image :src="imageSrc" mode="aspectFit" class="pdf-image" />
|
|
|
+ <view v-if="imageSrc" class="pdf-image-area" :style="{ height: viewerHeight }">
|
|
|
+ <movable-area class="pdf-movable-area">
|
|
|
+ <movable-view
|
|
|
+ v-if="imageWidth > 0 && imageHeight > 0"
|
|
|
+ direction="all"
|
|
|
+ :scale="true"
|
|
|
+ scale-min="0.5"
|
|
|
+ scale-max="5"
|
|
|
+ :scale-value="1"
|
|
|
+ class="pdf-movable-view"
|
|
|
+ :style="{ width: imageWidth + 'px', height: imageHeight + 'px' }"
|
|
|
+ >
|
|
|
+ <image
|
|
|
+ :src="imageSrc"
|
|
|
+ mode="aspectFit"
|
|
|
+ class="pdf-image"
|
|
|
+ :style="{ width: imageWidth + 'px' }"
|
|
|
+ />
|
|
|
+ </movable-view>
|
|
|
+ </movable-area>
|
|
|
</view>
|
|
|
<view v-else class="pdf-placeholder">
|
|
|
<text class="placeholder-text">暂无PDF预览</text>
|
|
|
@@ -25,14 +57,16 @@
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
|
|
+import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
|
|
|
|
|
interface Props {
|
|
|
source: ArrayBuffer | Blob | null
|
|
|
+ viewerHeight?: string
|
|
|
}
|
|
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
source: null,
|
|
|
+ viewerHeight: '100vh',
|
|
|
})
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
@@ -40,10 +74,9 @@ const emit = defineEmits<{
|
|
|
error: [message: string]
|
|
|
}>()
|
|
|
|
|
|
-const containerId = ref(`pdf-viewer-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`)
|
|
|
+const containerId = ref(`pdf-c-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`)
|
|
|
const loading = ref(false)
|
|
|
const errorMsg = ref('')
|
|
|
-
|
|
|
const pageCount = ref(0)
|
|
|
let pdfDoc: any = null
|
|
|
|
|
|
@@ -54,9 +87,261 @@ const imageHeight = ref(0)
|
|
|
let isMounted = false
|
|
|
|
|
|
// #ifdef H5
|
|
|
-import * as pdfjsLib from 'pdfjs-dist'
|
|
|
-import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
|
|
|
-// #endif
|
|
|
+import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs'
|
|
|
+import pdfjsWorker from 'pdfjs-dist/legacy/build/pdf.worker.min.mjs?url'
|
|
|
+
|
|
|
+const viewportId = ref(`pdf-vp-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`)
|
|
|
+
|
|
|
+const MIN_ZOOM = 0.5
|
|
|
+const MAX_ZOOM = 5
|
|
|
+const ZOOM_STEP = 0.25
|
|
|
+
|
|
|
+const zoomScale = ref(1)
|
|
|
+const panX = ref(0)
|
|
|
+const panY = ref(0)
|
|
|
+
|
|
|
+let contentHeight = 0
|
|
|
+
|
|
|
+const zoomPercent = computed(() => Math.round(zoomScale.value * 100))
|
|
|
+
|
|
|
+const transformStyle = computed(() => ({
|
|
|
+ transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoomScale.value})`,
|
|
|
+ transformOrigin: '0 0',
|
|
|
+}))
|
|
|
+
|
|
|
+let touchStartDistance = 0
|
|
|
+let touchStartScale = 1
|
|
|
+let touchStartPanX = 0
|
|
|
+let touchStartPanY = 0
|
|
|
+let pinchCenterX = 0
|
|
|
+let pinchCenterY = 0
|
|
|
+let isPinching = false
|
|
|
+let isPanning = false
|
|
|
+let isScrolling = false
|
|
|
+let singleTouchStartX = 0
|
|
|
+let singleTouchStartY = 0
|
|
|
+let scrollMoveStartY = 0
|
|
|
+let touchStartClientY = 0
|
|
|
+let lastTapTime = 0
|
|
|
+let scrollVelocity = 0
|
|
|
+let momentumAnimId = 0
|
|
|
+let lastTouchY = 0
|
|
|
+let lastTouchTime = 0
|
|
|
+
|
|
|
+function getTouchDistance(touches: TouchList): number {
|
|
|
+ const dx = touches[0].clientX - touches[1].clientX
|
|
|
+ const dy = touches[0].clientY - touches[1].clientY
|
|
|
+ return Math.sqrt(dx * dx + dy * dy)
|
|
|
+}
|
|
|
+
|
|
|
+function getTouchCenter(touches: TouchList): { x: number; y: number } {
|
|
|
+ return {
|
|
|
+ x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
|
+ y: (touches[0].clientY + touches[1].clientY) / 2,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function clampScroll() {
|
|
|
+ if (zoomScale.value > 1.01) return
|
|
|
+ panX.value = 0
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (!viewport) return
|
|
|
+ const vh = viewport.clientHeight
|
|
|
+ const maxScroll = Math.max(0, contentHeight - vh)
|
|
|
+ panY.value = Math.max(-maxScroll, Math.min(0, panY.value))
|
|
|
+}
|
|
|
+
|
|
|
+function onTouchStart(e: TouchEvent) {
|
|
|
+ cancelAnimationFrame(momentumAnimId)
|
|
|
+ scrollVelocity = 0
|
|
|
+
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (!viewport) return
|
|
|
+ const rect = viewport.getBoundingClientRect()
|
|
|
+
|
|
|
+ if (e.touches.length === 2) {
|
|
|
+ isPinching = true
|
|
|
+ isPanning = false
|
|
|
+ isScrolling = false
|
|
|
+ touchStartDistance = getTouchDistance(e.touches)
|
|
|
+ touchStartScale = zoomScale.value
|
|
|
+ touchStartPanX = panX.value
|
|
|
+ touchStartPanY = panY.value
|
|
|
+ const center = getTouchCenter(e.touches)
|
|
|
+ pinchCenterX = center.x - rect.left
|
|
|
+ pinchCenterY = center.y - rect.top
|
|
|
+ e.preventDefault()
|
|
|
+ } else if (e.touches.length === 1) {
|
|
|
+ const now = Date.now()
|
|
|
+ touchStartClientY = e.touches[0].clientY
|
|
|
+ if (now - lastTapTime < 300) {
|
|
|
+ if (zoomScale.value > 1.05) {
|
|
|
+ zoomScale.value = 1
|
|
|
+ panX.value = 0
|
|
|
+ clampScroll()
|
|
|
+ } else {
|
|
|
+ const cx = e.touches[0].clientX - rect.left
|
|
|
+ const cy = e.touches[0].clientY - rect.top
|
|
|
+ const newScale = 2
|
|
|
+ const ratio = newScale / zoomScale.value
|
|
|
+ panX.value = cx - cx * ratio
|
|
|
+ panY.value = cy - (cy - panY.value) * ratio
|
|
|
+ zoomScale.value = newScale
|
|
|
+ }
|
|
|
+ e.preventDefault()
|
|
|
+ } else if (zoomScale.value > 1.01) {
|
|
|
+ isPanning = true
|
|
|
+ isPinching = false
|
|
|
+ isScrolling = false
|
|
|
+ singleTouchStartX = e.touches[0].clientX
|
|
|
+ singleTouchStartY = e.touches[0].clientY
|
|
|
+ touchStartPanX = panX.value
|
|
|
+ touchStartPanY = panY.value
|
|
|
+ } else {
|
|
|
+ isScrolling = true
|
|
|
+ isPanning = false
|
|
|
+ isPinching = false
|
|
|
+ scrollMoveStartY = e.touches[0].clientY
|
|
|
+ lastTouchY = scrollMoveStartY
|
|
|
+ lastTouchTime = Date.now()
|
|
|
+ }
|
|
|
+ lastTapTime = now
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onTouchMove(e: TouchEvent) {
|
|
|
+ if (isPinching && e.touches.length >= 2) {
|
|
|
+ e.preventDefault()
|
|
|
+ const currentDistance = getTouchDistance(e.touches)
|
|
|
+ const newScale = Math.min(
|
|
|
+ MAX_ZOOM,
|
|
|
+ Math.max(MIN_ZOOM, touchStartScale * (currentDistance / touchStartDistance)),
|
|
|
+ )
|
|
|
+ const ratio = newScale / touchStartScale
|
|
|
+ panX.value = pinchCenterX - (pinchCenterX - touchStartPanX) * ratio
|
|
|
+ panY.value = pinchCenterY - (pinchCenterY - touchStartPanY) * ratio
|
|
|
+ zoomScale.value = newScale
|
|
|
+ } else if (isPanning && e.touches.length === 1) {
|
|
|
+ e.preventDefault()
|
|
|
+ panX.value = touchStartPanX + (e.touches[0].clientX - singleTouchStartX)
|
|
|
+ panY.value = touchStartPanY + (e.touches[0].clientY - singleTouchStartY)
|
|
|
+ } else if (isScrolling && e.touches.length === 1) {
|
|
|
+ e.preventDefault()
|
|
|
+ const y = e.touches[0].clientY
|
|
|
+ if (Math.abs(y - touchStartClientY) > 10) {
|
|
|
+ lastTapTime = 0
|
|
|
+ }
|
|
|
+ const now = Date.now()
|
|
|
+ const dt = now - lastTouchTime
|
|
|
+ if (dt > 0) {
|
|
|
+ scrollVelocity = ((lastTouchY - y) / dt) * 16
|
|
|
+ }
|
|
|
+ lastTouchY = y
|
|
|
+ lastTouchTime = now
|
|
|
+ panY.value += y - scrollMoveStartY
|
|
|
+ scrollMoveStartY = y
|
|
|
+ clampScroll()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onTouchEnd(e: TouchEvent) {
|
|
|
+ if (e.touches.length === 0) {
|
|
|
+ if (isScrolling) {
|
|
|
+ isScrolling = false
|
|
|
+ startMomentumScroll()
|
|
|
+ }
|
|
|
+ isPinching = false
|
|
|
+ isPanning = false
|
|
|
+ if (zoomScale.value >= 0.95 && zoomScale.value < 1.05) {
|
|
|
+ zoomScale.value = 1
|
|
|
+ panX.value = 0
|
|
|
+ clampScroll()
|
|
|
+ }
|
|
|
+ } else if (e.touches.length === 1 && isPinching) {
|
|
|
+ isPinching = false
|
|
|
+ if (zoomScale.value > 1.01) {
|
|
|
+ isPanning = true
|
|
|
+ singleTouchStartX = e.touches[0].clientX
|
|
|
+ singleTouchStartY = e.touches[0].clientY
|
|
|
+ touchStartPanX = panX.value
|
|
|
+ touchStartPanY = panY.value
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function startMomentumScroll() {
|
|
|
+ const friction = 0.95
|
|
|
+ function step() {
|
|
|
+ if (Math.abs(scrollVelocity) < 0.5) return
|
|
|
+ panY.value += scrollVelocity
|
|
|
+ scrollVelocity *= friction
|
|
|
+ clampScroll()
|
|
|
+ momentumAnimId = requestAnimationFrame(step)
|
|
|
+ }
|
|
|
+ momentumAnimId = requestAnimationFrame(step)
|
|
|
+}
|
|
|
+
|
|
|
+function onWheel(e: WheelEvent) {
|
|
|
+ e.preventDefault()
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (!viewport) return
|
|
|
+ const rect = viewport.getBoundingClientRect()
|
|
|
+
|
|
|
+ if (e.ctrlKey || e.metaKey) {
|
|
|
+ const delta = -e.deltaY
|
|
|
+ const factor = delta > 0 ? 1.1 : 1 / 1.1
|
|
|
+ const newScale = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoomScale.value * factor))
|
|
|
+ const cx = e.clientX - rect.left
|
|
|
+ const cy = e.clientY - rect.top
|
|
|
+ const ratio = newScale / zoomScale.value
|
|
|
+ panX.value = cx - (cx - panX.value) * ratio
|
|
|
+ panY.value = cy - (cy - panY.value) * ratio
|
|
|
+ zoomScale.value = newScale
|
|
|
+ if (newScale <= 1.01) {
|
|
|
+ panX.value = 0
|
|
|
+ clampScroll()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (zoomScale.value > 1.01) {
|
|
|
+ panY.value -= e.deltaY
|
|
|
+ panX.value -= e.deltaX
|
|
|
+ } else {
|
|
|
+ panY.value -= e.deltaY
|
|
|
+ clampScroll()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function applyZoom(newScale: number, cx: number, cy: number) {
|
|
|
+ const ratio = newScale / zoomScale.value
|
|
|
+ panX.value = cx - (cx - panX.value) * ratio
|
|
|
+ panY.value = cy - (cy - panY.value) * ratio
|
|
|
+ zoomScale.value = newScale
|
|
|
+ if (newScale <= 1.01) {
|
|
|
+ panX.value = 0
|
|
|
+ clampScroll()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function zoomIn() {
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (!viewport) return
|
|
|
+ const rect = viewport.getBoundingClientRect()
|
|
|
+ applyZoom(Math.min(MAX_ZOOM, zoomScale.value + ZOOM_STEP), rect.width / 2, rect.height / 2)
|
|
|
+}
|
|
|
+
|
|
|
+function zoomOut() {
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (!viewport) return
|
|
|
+ const rect = viewport.getBoundingClientRect()
|
|
|
+ applyZoom(Math.max(MIN_ZOOM, zoomScale.value - ZOOM_STEP), rect.width / 2, rect.height / 2)
|
|
|
+}
|
|
|
+
|
|
|
+function resetZoom() {
|
|
|
+ zoomScale.value = 1
|
|
|
+ panX.value = 0
|
|
|
+ panY.value = 0
|
|
|
+}
|
|
|
|
|
|
const renderAllPages = async () => {
|
|
|
if (!pdfDoc) return
|
|
|
@@ -67,6 +352,8 @@ const renderAllPages = async () => {
|
|
|
container.innerHTML = ''
|
|
|
|
|
|
const containerWidth = uni.getSystemInfoSync().windowWidth - 32
|
|
|
+ const dpr = window.devicePixelRatio || 1
|
|
|
+ let totalHeight = 0
|
|
|
|
|
|
for (let i = 1; i <= pdfDoc.numPages; i++) {
|
|
|
const page = await pdfDoc.getPage(i)
|
|
|
@@ -75,23 +362,28 @@ const renderAllPages = async () => {
|
|
|
const viewport = page.getViewport({ scale })
|
|
|
|
|
|
const canvas = document.createElement('canvas')
|
|
|
- canvas.width = viewport.width
|
|
|
- canvas.height = viewport.height
|
|
|
+ canvas.width = Math.floor(viewport.width * dpr)
|
|
|
+ canvas.height = Math.floor(viewport.height * dpr)
|
|
|
canvas.style.display = 'block'
|
|
|
canvas.style.width = viewport.width + 'px'
|
|
|
canvas.style.height = viewport.height + 'px'
|
|
|
|
|
|
const context = canvas.getContext('2d')
|
|
|
+ context!.scale(dpr, dpr)
|
|
|
await page.render({ canvasContext: context!, viewport }).promise
|
|
|
|
|
|
container.appendChild(canvas)
|
|
|
+ totalHeight += viewport.height
|
|
|
}
|
|
|
+
|
|
|
+ contentHeight = totalHeight
|
|
|
} catch (error) {
|
|
|
console.error('PDF页面渲染失败:', error)
|
|
|
errorMsg.value = 'PDF页面渲染失败'
|
|
|
emit('error', 'PDF页面渲染失败')
|
|
|
}
|
|
|
}
|
|
|
+// #endif
|
|
|
|
|
|
const loadPDFFromArrayBuffer = async (data: ArrayBuffer) => {
|
|
|
loading.value = true
|
|
|
@@ -161,6 +453,15 @@ const resetViewer = () => {
|
|
|
pageCount.value = 0
|
|
|
imageSrc.value = ''
|
|
|
errorMsg.value = ''
|
|
|
+
|
|
|
+ // #ifdef H5
|
|
|
+ zoomScale.value = 1
|
|
|
+ panX.value = 0
|
|
|
+ panY.value = 0
|
|
|
+ contentHeight = 0
|
|
|
+ scrollVelocity = 0
|
|
|
+ cancelAnimationFrame(momentumAnimId)
|
|
|
+ // #endif
|
|
|
}
|
|
|
|
|
|
watch(
|
|
|
@@ -191,6 +492,16 @@ watch(
|
|
|
onMounted(async () => {
|
|
|
isMounted = true
|
|
|
|
|
|
+ // #ifdef H5
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (viewport) {
|
|
|
+ viewport.addEventListener('touchstart', onTouchStart, { passive: false })
|
|
|
+ viewport.addEventListener('touchmove', onTouchMove, { passive: false })
|
|
|
+ viewport.addEventListener('touchend', onTouchEnd, { passive: false })
|
|
|
+ viewport.addEventListener('wheel', onWheel, { passive: false })
|
|
|
+ }
|
|
|
+ // #endif
|
|
|
+
|
|
|
if (props.source) {
|
|
|
if (props.source instanceof Blob) {
|
|
|
await loadPDFFromBlob(props.source)
|
|
|
@@ -202,6 +513,18 @@ onMounted(async () => {
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
isMounted = false
|
|
|
+
|
|
|
+ // #ifdef H5
|
|
|
+ cancelAnimationFrame(momentumAnimId)
|
|
|
+ const viewport = document.getElementById(viewportId.value)
|
|
|
+ if (viewport) {
|
|
|
+ viewport.removeEventListener('touchstart', onTouchStart)
|
|
|
+ viewport.removeEventListener('touchmove', onTouchMove)
|
|
|
+ viewport.removeEventListener('touchend', onTouchEnd)
|
|
|
+ viewport.removeEventListener('wheel', onWheel)
|
|
|
+ }
|
|
|
+ // #endif
|
|
|
+
|
|
|
resetViewer()
|
|
|
})
|
|
|
|
|
|
@@ -212,6 +535,7 @@ defineExpose({
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.pdf-viewer {
|
|
|
+ position: relative;
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
@@ -245,32 +569,108 @@ defineExpose({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.pdf-viewer-wrapper {
|
|
|
+/* #ifdef H5 */
|
|
|
+.pdf-viewport {
|
|
|
+ position: relative;
|
|
|
width: 100%;
|
|
|
- margin-bottom: 16px;
|
|
|
+ overflow: hidden;
|
|
|
+ touch-action: none;
|
|
|
+ user-select: none;
|
|
|
+ -webkit-user-select: none;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-transform-layer {
|
|
|
+ will-change: transform;
|
|
|
}
|
|
|
|
|
|
.pdf-container {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
width: 100%;
|
|
|
- overflow: auto;
|
|
|
- background-color: #f5f5f5;
|
|
|
- border-radius: 8px;
|
|
|
- min-height: 200px;
|
|
|
+
|
|
|
+ canvas {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-zoom-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ margin: 8px auto 0;
|
|
|
+ background-color: rgba(0, 0, 0, 0.65);
|
|
|
+ border-radius: 20px;
|
|
|
+ width: fit-content;
|
|
|
+}
|
|
|
+
|
|
|
+.zoom-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ background-color: rgba(255, 255, 255, 0.2);
|
|
|
+ border-radius: 50%;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ background-color: rgba(255, 255, 255, 0.4);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.zoom-btn-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #fff;
|
|
|
+ line-height: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.zoom-btn-reset {
|
|
|
+ width: auto;
|
|
|
+ padding: 0 10px;
|
|
|
+ border-radius: 12px;
|
|
|
+ margin-left: 4px;
|
|
|
+
|
|
|
+ .zoom-btn-text {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-.pdf-image-container {
|
|
|
+.zoom-label {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #fff;
|
|
|
+ min-width: 40px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+/* #endif */
|
|
|
+
|
|
|
+/* #ifndef H5 */
|
|
|
+.pdf-image-area {
|
|
|
width: 100%;
|
|
|
- overflow: hidden;
|
|
|
background-color: #f5f5f5;
|
|
|
border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
|
|
|
- .pdf-image {
|
|
|
- display: block;
|
|
|
- width: 100%;
|
|
|
- }
|
|
|
+.pdf-movable-area {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-movable-view {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-image {
|
|
|
+ display: block;
|
|
|
}
|
|
|
+/* #endif */
|
|
|
|
|
|
.pdf-placeholder {
|
|
|
display: flex;
|