Skip to content

Commit

Permalink
feat(pdf-helipad): add component pdf-helipad
Browse files Browse the repository at this point in the history
  • Loading branch information
adenvt committed Mar 3, 2023
1 parent cca2c7d commit 52e2f8d
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ export default defineConfig({
text: 'PDF Object',
link: '/components/pdf-object/',
},
{
text: 'PDF Helipad',
link: '/components/pdf-helipad/',
},
],
},
{
Expand Down
1 change: 1 addition & 0 deletions src/.vitepress/theme/components/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

<div class="flex flex-col items-center justify-center pt-10 space-gap-2 md:flex-row">
<Button
color="primary"
size="lg"
@click="gettingStarted">
Get Started
Expand Down
115 changes: 115 additions & 0 deletions src/components/pdf-helipad/PdfHelipad.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<template>
<div
ref="root"
class="pdf-helipad">
<div
ref="object"
class="pdf-object pdf-object--external"
:style="{ width: `${width}px`, height: `${height}px` }">
<slot />
</div>
<div
class="pdf-helipad__shadow"
:style="{ width: `${width}px`, height: `${height}px` }">
<slot />
</div>
</div>
</template>

<script lang="ts">
import { templateRef } from '@vueuse/core'
import {
defineComponent,
ref,
toRef,
watchEffect,
} from 'vue-demi'
import { getPosition } from '../pdf-object/utils/position'
import useDrag from './utils/use-drag'
export default defineComponent({
props: {
scale: {
type : Number,
default: 1,
},
width: {
type : Number,
default: 198,
},
height: {
type : Number,
default: 106,
},
},
emits: ['landed'],
setup (props, { emit }) {
const object = templateRef<HTMLDivElement>('object')
const scale = toRef(props, 'scale')
const isDragged = ref(false)
const x = ref(0)
const y = ref(0)
useDrag(object, {
onstart () {
const { left, top } = object.value.getBoundingClientRect()
isDragged.value = true
x.value = left
y.value = top
},
onmove (event) {
x.value += event.dx
y.value += event.dy
},
onend (event) {
isDragged.value = false
if (event.relatedTarget) {
const reference = event.relatedTarget
const container = reference.closest('.pdf__container')
const result = getPosition({
reference: reference as HTMLDivElement,
container: container as HTMLDivElement,
object : object.value,
scale : scale.value,
})
emit('landed', result)
}
},
})
watchEffect(() => {
if (object.value) {
if (isDragged.value) {
object.value.style.position = 'fixed'
object.value.style.transform = `translate(${x.value}px, ${y.value}px) scale(${scale.value})`
object.value.style.zIndex = '50'
} else {
object.value.style.position = 'absolute'
object.value.style.transform = ''
object.value.style.zIndex = '2'
}
}
})
return {}
},
})
</script>

<style lang="postcss">
.pdf-helipad {
@apply relative;
.pdf-object {
@apply top-0 left-0 border-2 border-dashed border-subtle rounded;
}
&__shadow {
@apply opacity-25 z-1;
}
}
</style>
102 changes: 102 additions & 0 deletions src/components/pdf-helipad/assets/helicopter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions src/components/pdf-helipad/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: PDF Helipad · Components
description: Add object to PDF Viewer with Drag'n'Drop
---

<script setup>
import pPdfHelipad from './PdfHelipad.vue'
import pPdfObject from '../pdf-object/PdfObject.vue'
import pPdfObjectAddon from '../pdf-object/PdfObjectAddon.vue'
import pPdfViewer from '../pdf-viewer/PdfViewer.vue'
import pButton from '../button/Button.vue'
import IconClose from '@carbon/icons-vue/lib/close/16'
import FILE from '../pdf-viewer/assets/Calibrator-v3.pdf?url'
import IMG_HELICOPTER from './assets/helicopter.svg'
import { reactive, ref } from 'vue-demi'

const objects = reactive([])
const scale = ref(1)

function onLanded (item) {
objects.push({
_id : Symbol('ObjectId'),
page : item.page,
x : item.x,
y : item.y,
width : 198,
height: 106,
})
}

function remove (index) {
objects.splice(index, 1)
}
</script>

# PDF Helipad

## Usage

### Simple Usage

(Drag this to PDF Viewer)

<p-pdf-helipad :scale="scale" @landed="onLanded">
<img class="w-full h-full" :src="IMG_HELICOPTER" />
</p-pdf-helipad>

<preview>
<p-pdf-viewer :src="FILE" v-model:scale="scale">
<p-pdf-object
v-for="(object, i) in objects"
:key="object._id"
v-model:page="object.page"
v-model:x="object.x"
v-model:y="object.y"
v-model:width="object.width"
v-model:height="object.height">
<img class="w-full h-full rounded" :src="IMG_HELICOPTER" />
<p-pdf-object-addon>
<p-button size="sm" icon color="danger" @click="remove(i)">
<IconClose />
</p-button>
</p-pdf-object-addon>
</p-pdf-object>
</p-pdf-viewer>
</preview>
68 changes: 68 additions & 0 deletions src/components/pdf-helipad/utils/use-drag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { InteractEvent, Interactable } from '@interactjs/types'
import {
onScopeDispose,
Ref,
shallowRef,
watch,
} from 'vue-demi'

export interface DragHooks {
onstart?: (event: InteractEvent) => void,
onmove?: (event: InteractEvent) => void,
onend?: (event: InteractEvent) => void,
}

export default function useDrag (target: Ref<HTMLElement>, hooks?: DragHooks) {
const enable = shallowRef(true)
const instance = shallowRef<Interactable>()

async function init () {
destroy()

if (target.value) {
const { default: Interact } = await import('interactjs')

// Interact.dynamicDrop(true)

instance.value = Interact(target.value)
.draggable({
inertia : true,
enabled : enable.value,
onstart : hooks.onstart,
onmove : hooks.onmove,
onend : hooks.onend,
modifiers: [
Interact.modifiers.restrict({
restriction: 'body',
elementRect: {
top : 0,
left : 0,
bottom: 1,
right : 1,
},
}),
],
})
}
}

function destroy () {
if (instance.value)
instance.value.unset()
}

watch(target, async () => {
await init()
})

watch(enable, (value) => {
if (instance.value)
instance.value.draggable(value)
})

onScopeDispose(() => {
destroy()
})

return enable
}
2 changes: 2 additions & 0 deletions src/components/pdf-viewer/PdfViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
v-p-aspect-ratio="layout === 'fixed' ? ratio : 16/9"
data-testid="pdf-viewer"
class="pdf"
:data-page="pdfPage"
:data-scale="pdfScale"
:class="classNames">
<div
class="pdf__header">
Expand Down

0 comments on commit 52e2f8d

Please sign in to comment.