Skip to content

Commit

Permalink
feat: add support for background image
Browse files Browse the repository at this point in the history
  • Loading branch information
robertrosman committed May 9, 2024
1 parent ea85775 commit 685b568
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 16 deletions.
Binary file added public/pexels-apasaric.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import VueDraw from './components/VueDraw.vue'
import type { Settings, Crop, SaveParameters } from './types'
import { toCanvas } from './utils/toCanvas';
import { toImgSrc } from './utils/toImgSrc';
import { useAsyncState } from '@vueuse/core';
import { urlToBlob } from './utils/urlToBlob';
const canvasRef = ref()
const imgSrc = ref<string>()
const { state: backgroundImage } = useAsyncState(
urlToBlob('/public/pexels-apasaric.jpg'),
undefined
)
function save({ svg, crop }: SaveParameters) {
imgSrc.value = toImgSrc({ svg, crop })
toCanvas({ svg, canvas: canvasRef, crop })
Expand All @@ -28,4 +35,7 @@ function save({ svg, crop }: SaveParameters) {
</div>
<h1>Barebones example</h1>
<vue-draw class="vue-draw" @save="save"></vue-draw>

<h1>With background</h1>
<vue-draw v-if="backgroundImage" class="vue-draw" @save="save" :background="backgroundImage"></vue-draw>
</template>
39 changes: 23 additions & 16 deletions src/components/VueDraw.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { useElementBounding, usePointerSwipe } from '@vueuse/core'
import { computed, ref } from 'vue';
import { computed, ref, unref, watchEffect, type MaybeRef } from 'vue';
import type { Crop, SaveParameters, Settings, Shape, Tool } from '../types'
import { getArrowId } from '@/utils/getArrowId';
import SvgShape from './SvgShape.vue';
import { createDataUrl } from '@/utils/createDataUrl';
const emit = defineEmits<{
(e: 'crop', crop: Crop | undefined): void
Expand All @@ -19,6 +20,16 @@ const settings = defineModel<Settings>("settings", {
})
})
const props = defineProps<{
/**
* Use background prop to set a background image. There are several ways to create a blob, like these:
* @example
* const blob1 = await canvasToBlob(canvas)
* const blob2 = await urlToBlob(url)
*/
background?: MaybeRef<Blob>
}>()
const history = defineModel<Shape[]>("history", { default: [] })
const crop = defineModel<Crop | undefined>("crop", { default: undefined })
Expand Down Expand Up @@ -100,6 +111,15 @@ const minY = computed(() => Math.min(posStart.y - top.value, posEnd.y - top.valu
const maxX = computed(() => Math.max(posStart.x - left.value, posEnd.x - left.value))
const maxY = computed(() => Math.max(posStart.y - top.value, posEnd.y - top.value))
const backgroundSrc = ref()
watchEffect(() => {
const unreffed = unref(props.background)
if (!unreffed) {
return undefined
}
createDataUrl(unreffed).then(src => backgroundSrc.value = src)
})
function setTool(tool: Tool) {
settings.value.tool = tool
}
Expand Down Expand Up @@ -135,8 +155,9 @@ const arrowMarkers = computed(() =>

<template>
<div ref="container" class="container">
<svg ref="svgRef" :width="width" :height="height" class="absolute inset-0" :viewBox="`0 0 ${width} ${height}`"
<svg ref="svgRef" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`"
xmlns="http://www.w3.org/2000/svg">
<image v-if="background" :xlink:href="backgroundSrc" :width="width" />
<svg-shape v-for="shape, i in history" :key="i" :shape="shape" />
<svg-shape v-if="activeShape" :shape="activeShape" />
<path v-if="crop" class="overlay" :d="`
Expand Down Expand Up @@ -182,22 +203,8 @@ const arrowMarkers = computed(() =>
cursor: crosshair;
}
svg {
z-index: 100;
}
.toolbar {
position: absolute;
}
.dashed-line {
fill: none;
stroke: #ffffff;
stroke-width: 1;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-opacity: 1;
stroke-dasharray: 4, 8;
stroke-dashoffset: 0;
}
</style>
16 changes: 16 additions & 0 deletions src/utils/createDataUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Inspired by https://stackoverflow.com/a/58569300/829505
export function createDataUrl(blob: Blob) {
return new Promise(function(resolve, reject) {
const reader = new FileReader();

reader.onloadend = function() {
resolve(reader.result);
};

reader.onerror = function() {
reject()
}

reader.readAsDataURL(blob);
});
}
9 changes: 9 additions & 0 deletions src/utils/urlToBlob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Use this function to fetch a url and convert in into a Blob. Useful when you want to set a background image to your editor.
* @example
* const blob = await urlToBlob(url)
*
*/
export async function urlToBlob(url: string) {
return fetch(url).then(res => res.blob())
}

0 comments on commit 685b568

Please sign in to comment.