94 lines
3.0 KiB
Vue
94 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import * as d3 from "d3"
|
|
import { onMounted } from "vue"
|
|
|
|
import { IMAGE_URL } from '../../constants'
|
|
|
|
const props = defineProps(['files'])
|
|
|
|
onMounted(async () => {
|
|
const files = props.files
|
|
// const width = 1920
|
|
// const height = 1080
|
|
const width = window.innerWidth
|
|
const height = window.innerHeight
|
|
|
|
const svg = d3.select('#gallery').append("svg")
|
|
.attr("viewBox", [0, 0, width, height])
|
|
.attr("stroke-width", 2);
|
|
|
|
var defs = svg.append('svg:defs');
|
|
|
|
files.forEach((element: any, i: number) => {
|
|
// const src = element[1].default
|
|
const src = `${IMAGE_URL}/${element.file}`
|
|
defs.append("svg:pattern")
|
|
.attr("id", `img${i}`)
|
|
.attr("width", width)
|
|
.attr("height", height)
|
|
.attr("patternUnits", "userSpaceOnUse")
|
|
.attr("preserveAspectRatio", "none")
|
|
.append("svg:image")
|
|
.attr("xlink:href", src)
|
|
.attr("width", width)
|
|
.attr("height", height)
|
|
.attr("x", 0)
|
|
.attr("y", 0);
|
|
});
|
|
const range = files.length + 2
|
|
const circles = d3.range(range).map(() => ({
|
|
x: Math.random() * width,
|
|
y: Math.random() * height,
|
|
}));
|
|
|
|
let voronoi = d3.Delaunay
|
|
.from(circles, d => d.x, d => d.y)
|
|
.voronoi([0, 0, width, height]);
|
|
|
|
const circle = svg.append("g")
|
|
.selectAll("circle")
|
|
.data(circles)
|
|
.join("circle")
|
|
.attr("cx", d => d.x)
|
|
.attr("cy", d => d.y)
|
|
.attr("r", 0)
|
|
.attr("fill", 'none');
|
|
|
|
const mesh = svg.append("path")
|
|
.attr("fill", "none")
|
|
.attr("stroke", "#ccc")
|
|
.attr("stroke-width", 0)
|
|
.attr("d", voronoi.render());
|
|
|
|
const cell = svg.append("g")
|
|
.attr("fill", "none")
|
|
.attr("pointer-events", "all")
|
|
.selectAll("path")
|
|
.data(circles)
|
|
.join("path")
|
|
.attr("d", (d, i) => voronoi.renderCell(i))
|
|
.attr('fill', (d, i) => i < (range - 2) ? `url(#img${i})` : 'none')
|
|
.call(d3.drag()
|
|
.on("start", (event, d) => circle.filter(p => p === d).raise().attr("stroke", "black"))
|
|
.on("drag", (event, d: any) => (d.x = event.x, d.y = event.y))
|
|
.on("end", (event, d) => circle.filter(p => p === d).attr("stroke", null))
|
|
.on("start.update drag.update end.update", update) as any)
|
|
|
|
function update() {
|
|
voronoi = d3.Delaunay.from(circles, d => d.x, d => d.y).voronoi([0, 0, width, height]);
|
|
circle.attr("cx", d => d.x).attr("cy", d => d.y);
|
|
cell.attr("d", (d, i) => voronoi.renderCell(i));
|
|
mesh.attr("d", voronoi.render());
|
|
}
|
|
|
|
if (document.querySelector('.pin')) {
|
|
const rect = (document.querySelector('.pin') as HTMLElement).getBoundingClientRect()
|
|
circles[circles.length - 1] = { x: rect.x + rect.width, y: rect.y + rect.height }
|
|
circles[circles.length - 2] = { x: rect.x, y: rect.y }
|
|
update()
|
|
}
|
|
})
|
|
</script>
|
|
<template>
|
|
<div id="gallery"></div>
|
|
</template> |