Skip to content

Commit

Permalink
Add zoom image on move 🐁 (#44)
Browse files Browse the repository at this point in the history
* chore: add basic zoomed image on mouse move

* feat: replace img tag by background image

* chore: cleanup image zoom move vanilla example

* chore: update package.json

* docs: update createZoomImageMove section

* docs: add vue example

* docs: add svelte example

* docs: add examples for the rest of frameworks

* chore: add changeset and update pnpm lock

* chore: enhance zoomed image on move

* chore: run prettier on ci

* chore: update branch for push action

* chore: update ci.yml

* chore: with force

* chore: format code with Prettier

* chore: update ad-m/github-push-action to use master

* chore: change Github action job name

* chore: fix failure on nothing change

* chore: test ci on change

* chore: format code with Prettier

* chore: update doc demo

* chore: update demo gif image

---------

Co-authored-by: GitHub Action <[email protected]>
  • Loading branch information
willnguyen1312 and actions-user authored May 11, 2023
1 parent ddb0193 commit 2fe07ad
Show file tree
Hide file tree
Showing 30 changed files with 351 additions and 114 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-flowers-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoom-image/core": minor
---

Add support for zooming image on move
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- main

jobs:
test:
verify:
runs-on: ubuntu-latest

steps:
Expand Down Expand Up @@ -37,3 +37,19 @@ jobs:

- name: Test
run: pnpm test:ci

- name: Run prettier
run: pnpm prettier-fix

- name: Commit changes
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git diff --quiet && git diff --staged --quiet || (git commit -am "chore: format code with Prettier" --no-verify)
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.head_ref }}
force: true
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
- [Zoom Image](#zoom-image)
- [Demo](#demo)
- [Zoom on hover](#zoom-on-hover)
- [Zoom on wheel](#zoom-on-wheel)
- [Architecture](#architecture)
- [Development](#development)
- [Commands](#commands)
Expand All @@ -21,17 +19,12 @@ A little yet powerful library to zoom image on wheel / hover / pinch actions. It
sites. Examples are written with Preact, React, Svelte, Vanilla JS and Vue.

- ✅ Zoom on hover
- ✅ Zoom on move
- ✅ Zoom on wheel

## Demo

### Zoom on hover

![Demo Zoom on hover](./images/demo-zoom-hover.gif)

### Zoom on wheel

![Demo Zoom on wheel](./images/demo-zoom-wheel.gif)
![Demo Zoom](./images/demo.gif)

## Architecture

Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export default defineConfig({
link: "/api/",
items: [
{ text: "createZoomImageHover", link: "/api/createZoomImageHover" },
{ text: "createZoomImageMove", link: "/api/createZoomImageMove" },
{ text: "createZoomImageWheel", link: "/api/createZoomImageWheel" },
{ text: "makeCalculateZoom", link: "/api/makeCalculateZoom" },
{ text: "makeCalculatePercentage", link: "/api/makeCalculatePercentage" },
Expand Down
2 changes: 1 addition & 1 deletion docs/api/createZoomImageHover.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cleanup()
type ZoomImageHoverOptions = {
// The size of zoomed window where zoomed image will be displayed
customZoom?: { width: number; height: number }
// The source of zoomed image
// The source of zoomed image, default is the same as the original image
zoomImageSource?: string
// The css class will be added to zoom lens element
zoomLensClass?: string
Expand Down
31 changes: 31 additions & 0 deletions docs/api/createZoomImageMove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# createZoomImageMove

### Basic Usage

```ts
const { cleanup } = createZoomImageMove(container, {
zoomImageSource: "large-image.webp",
})

// Call cleanup when you don't need it anymore
cleanup()
```

### Type Declaration

```ts
type ZoomImageMoveOptions = {
// Zoom scale, default is 4
zoomFactor?: number
// The source of zoomed image, default is the same as the original image
zoomImageSource?: string
}

function createZoomImageMove(
container: HTMLElement,
options?: ZoomImageMoveOptions,
): {
// Remove all event listeners and zoomed image
cleanup: () => void
}
```
1 change: 1 addition & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# API Reference

- [createZoomImageWheel](/api/createZoomImageWheel)
- [createZoomImageMove](/api/createZoomImageMove)
- [createZoomImageHover](/api/createZoomImageHover)
- [makeCalculateZoom](/api/makeCalculateZoom)
- [makeCalculatePercentage](/api/makeCalculatePercentage)
5 changes: 0 additions & 5 deletions docs/components/HomeGif.vue

This file was deleted.

8 changes: 8 additions & 0 deletions docs/components/HomeVideo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<template>
<div class="flex justify-center m-x-auto mt-4 px-6 sm:px-12">
<video class="rounded-4" muted autoplay loop playsinline>
<source src="/demo.webm" type="video/webm" />
<source src="/demo.mp4" type="video/mp4" />
</video>
</div>
</template>
7 changes: 5 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ features:
- title: Zoom on pinch
details: Support touch pinch zoom on image
icon: 🤏
- title: Zoom on move
details: Support mouse move zoom on image
icon: 🎢
---

<script setup>
import HomeGif from './components/HomeGif.vue'
import HomeVideo from './components/HomeVideo.vue'
import Footer from './components/Footer.vue'
</script>

<HomeGif />
<HomeVideo />
<Footer />
Binary file removed docs/public/demo.gif
Binary file not shown.
Binary file added docs/public/demo.mp4
Binary file not shown.
Binary file added docs/public/demo.webm
Binary file not shown.
30 changes: 21 additions & 9 deletions examples/preact-ts/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { useRef, useEffect, useState, useMemo } from "preact/hooks"
import { createZoomImageHover, createZoomImageWheel } from "@zoom-image/core"
import { createZoomImageHover, createZoomImageMove, createZoomImageWheel } from "@zoom-image/core"

function App() {
const [tabs, setTabs] = useState<
{
name: string
href: string
current: boolean
value: "wheel" | "hover"
value: "wheel" | "hover" | "move"
}[]
>([
{ name: "Zoom Image Wheel", href: "#", current: true, value: "wheel" },
{ name: "Zoom Image Hover", href: "#", current: false, value: "hover" },
{ name: "Zoom Image Move", href: "#", current: false, value: "move" },
])
const zoomType = useMemo(() => tabs.find((tab) => tab.current)?.value, [tabs])
const imageWheelContainerRef = useRef<HTMLDivElement>(null)
const imageMoveContainerRef = useRef<HTMLDivElement>(null)
const imageHoverContainerRef = useRef<HTMLDivElement>(null)
const zoomTargetRef = useRef<HTMLDivElement>(null)

Expand Down Expand Up @@ -51,6 +53,14 @@ function App() {
cleanup = result.cleanup
}

if (zoomType === "move") {
const imageContainer = imageMoveContainerRef.current as HTMLDivElement
const result = createZoomImageMove(imageContainer, {
zoomImageSource: "/large.webp",
})
cleanup = result.cleanup
}

return cleanup
}, [zoomType])

Expand Down Expand Up @@ -78,20 +88,22 @@ function App() {
{zoomType === "wheel" && (
<>
<p>Scroll inside the image to see zoom in-out effect</p>
<div ref={imageWheelContainerRef} id="image-wheel-container" class="w-[300px] h-[300px] cursor-crosshair">
<div ref={imageWheelContainerRef} class="w-[300px] h-[300px] cursor-crosshair">
<img class="w-full h-full" alt="Large Pic" src="/large.webp" />
</div>
</>
)}

{zoomType === "hover" && (
<div
id="image-hover-container"
ref={imageHoverContainerRef}
class="relative flex items-start w-[250px] h-[250px]"
>
<div ref={imageHoverContainerRef} class="relative flex items-start w-[250px] h-[250px]">
<img class="w-full h-full" alt="Small Pic" src="/small.webp" />
<div ref={zoomTargetRef} id="zoom-hover-target" class="absolute left-[300px]"></div>
<div ref={zoomTargetRef} class="absolute left-[300px]"></div>
</div>
)}

{zoomType === "move" && (
<div ref={imageMoveContainerRef} class="w-[300px] h-[300px] cursor-crosshair relative overflow-hidden">
<img class="w-full h-full" alt="Large Pic" src="/small.webp" />
</div>
)}
</div>
Expand Down
9 changes: 2 additions & 7 deletions examples/qwik-ts/package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
{
"name": "my-qwik-basic-starter",
"description": "App with Routing built-in (recommended)",
"engines": {
"node": ">=15.0.0"
},
"name": "qwik-ts",
"private": true,
"scripts": {
"build": "qwik build",
Expand Down Expand Up @@ -38,6 +34,5 @@
},
"dependencies": {
"@zoom-image/core": "^0.1.0"
},
"version": null
}
}
30 changes: 21 additions & 9 deletions examples/qwik-ts/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { component$, useSignal, useComputed$, useVisibleTask$ } from "@builder.io/qwik"
import { createZoomImageHover, createZoomImageWheel } from "@zoom-image/core"
import { createZoomImageHover, createZoomImageMove, createZoomImageWheel } from "@zoom-image/core"

type Tab = {
name: string
current: boolean
href: string
value: "wheel" | "hover"
value: "wheel" | "hover" | "move"
}

export default component$(() => {
const tabs = useSignal<Tab[]>([
{ name: "Zoom Image Wheel", href: "#", current: true, value: "wheel" },
{ name: "Zoom Image Hover", href: "#", current: false, value: "hover" },
{ name: "Zoom Image Move", href: "#", current: false, value: "move" },
])
const imageWheelContainerRef = useSignal<HTMLDivElement>()
const imageHoverContainerRef = useSignal<HTMLDivElement>()
const imageMoveContainerRef = useSignal<HTMLDivElement>()
const zoomTargetRef = useSignal<HTMLDivElement>()

const zoomType = useComputed$(() => {
Expand All @@ -41,6 +43,14 @@ export default component$(() => {
const result = createZoomImageWheel(imageContainer)
cleanup(result.cleanup)
}

if (zoomType.value === "move") {
const imageContainer = imageMoveContainerRef.value as HTMLDivElement
const result = createZoomImageMove(imageContainer, {
zoomImageSource: "/large.webp",
})
cleanup = result.cleanup
}
})

return (
Expand Down Expand Up @@ -75,20 +85,22 @@ export default component$(() => {
{zoomType.value === "wheel" && (
<>
<p>Scroll inside the image to see zoom in-out effect</p>
<div ref={imageWheelContainerRef} id="image-wheel-container" class="w-[300px] h-[300px] cursor-crosshair">
<div ref={imageWheelContainerRef} class="w-[300px] h-[300px] cursor-crosshair">
<img class="w-full h-full" alt="Large Pic" src="/large.webp" />
</div>
</>
)}

{zoomType.value === "hover" && (
<div
id="image-hover-container"
ref={imageHoverContainerRef}
class="relative flex items-start w-[250px] h-[250px]"
>
<div ref={imageHoverContainerRef} class="relative flex items-start w-[250px] h-[250px]">
<img class="w-full h-full" alt="Small Pic" src="/small.webp" />
<div ref={zoomTargetRef} id="zoom-hover-target" class="absolute left-[300px]"></div>
<div ref={zoomTargetRef} class="absolute left-[300px]"></div>
</div>
)}

{zoomType.value === "move" && (
<div ref={imageMoveContainerRef} class="w-[300px] h-[300px] cursor-crosshair relative overflow-hidden">
<img class="w-full h-full" alt="Large Pic" src="/small.webp" />
</div>
)}
</div>
Expand Down
31 changes: 22 additions & 9 deletions examples/react-ts/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { useRef, useEffect, useState, useMemo } from "react"
import { createZoomImageHover, createZoomImageWheel } from "@zoom-image/core"
import { createZoomImageHover, createZoomImageMove, createZoomImageWheel } from "@zoom-image/core"

function App() {
const [tabs, setTabs] = useState<
{
name: string
href: string
current: boolean
value: "wheel" | "hover"
value: "wheel" | "hover" | "move"
}[]
>([
{ name: "Zoom Image Wheel", href: "#", current: true, value: "wheel" },
{ name: "Zoom Image Hover", href: "#", current: false, value: "hover" },
{ name: "Zoom Image Move", href: "#", current: false, value: "move" },
])

const zoomType = useMemo(() => tabs.find((tab) => tab.current)?.value, [tabs])
const imageWheelContainerRef = useRef<HTMLDivElement>(null)
const imageHoverContainerRef = useRef<HTMLDivElement>(null)
const imageMoveContainerRef = useRef<HTMLDivElement>(null)
const zoomTargetRef = useRef<HTMLDivElement>(null)

const makeHandleTabClick = (tab: (typeof tabs)[0]) => () => {
Expand Down Expand Up @@ -53,6 +56,14 @@ function App() {
cleanup = result.cleanup
}

if (zoomType === "move") {
const imageContainer = imageMoveContainerRef.current as HTMLDivElement
const result = createZoomImageMove(imageContainer, {
zoomImageSource: "/large.webp",
})
cleanup = result.cleanup
}

return cleanup
}, [zoomType])

Expand Down Expand Up @@ -80,20 +91,22 @@ function App() {
{zoomType === "wheel" && (
<>
<p>Scroll inside the image to see zoom in-out effect</p>
<div ref={imageWheelContainerRef} id="image-wheel-container" className="w-[300px] h-[300px] cursor-crosshair">
<div ref={imageWheelContainerRef} className="w-[300px] h-[300px] cursor-crosshair">
<img className="w-full h-full" alt="Large Pic" src="/large.webp" />
</div>
</>
)}

{zoomType === "hover" && (
<div
id="image-hover-container"
ref={imageHoverContainerRef}
className="relative flex items-start w-[250px] h-[250px]"
>
<div ref={imageHoverContainerRef} className="relative flex items-start w-[250px] h-[250px]">
<img className="w-full h-full" alt="Small Pic" src="/small.webp" />
<div ref={zoomTargetRef} id="zoom-hover-target" className="absolute left-[300px]"></div>
<div ref={zoomTargetRef} className="absolute left-[300px]"></div>
</div>
)}

{zoomType === "move" && (
<div ref={imageMoveContainerRef} className="w-[300px] h-[300px] cursor-crosshair relative overflow-hidden">
<img className="w-full h-full" alt="Large Pic" src="/small.webp" />
</div>
)}
</div>
Expand Down
Loading

0 comments on commit 2fe07ad

Please sign in to comment.