updates scrollable graphic example
|
|
@ -2,7 +2,7 @@ import { Meta } from '@storybook/blocks';
|
|||
|
||||
import * as HorizontalScrollerStories from './HorizontalScroller.stories.svelte';
|
||||
|
||||
import IllustratorScreenshot from './assets/illustrator.jpg';
|
||||
import IllustratorScreenshot from './assets/illustrator.png';
|
||||
|
||||
<Meta of={HorizontalScrollerStories} />
|
||||
|
||||
|
|
@ -22,7 +22,10 @@ See the full list of available props under the `Controls` tab in the [demo](?pat
|
|||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||
import {
|
||||
HorizontalScroller,
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||
|
|
@ -69,7 +72,10 @@ By default, `duration` is set to `400` milliseconds.
|
|||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||
import {
|
||||
HorizontalScroller,
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
import { quartInOut } from 'svelte/easing';
|
||||
</script>
|
||||
|
||||
|
|
@ -106,9 +112,13 @@ If using custom `mappedStart` and `mappedEnd` values, you must also set `stops`
|
|||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||
import {
|
||||
HorizontalScroller,
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
import { quartInOut } from 'svelte/easing';
|
||||
</script>
|
||||
|
||||
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||
<Block width="fluid">
|
||||
<HorizontalScroller
|
||||
|
|
@ -154,7 +164,10 @@ allow_overflow: true
|
|||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||
import {
|
||||
HorizontalScroller,
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||
|
||||
// If using with the graphics kit
|
||||
|
|
@ -166,11 +179,7 @@ allow_overflow: true
|
|||
|
||||
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||
<Block width="fluid">
|
||||
<HorizontalScroller
|
||||
height="800lvh"
|
||||
easing={sineInOut}
|
||||
showDebugInfo
|
||||
>
|
||||
<HorizontalScroller height="800lvh" easing={sineInOut} showDebugInfo>
|
||||
<AiGraphic assetsPath={assets} />
|
||||
</HorizontalScroller>
|
||||
</Block>
|
||||
|
|
@ -184,7 +193,7 @@ The demo below has 2 advanced interactions: fade in/out of caption boxes based o
|
|||
|
||||
### Captions fading in/out
|
||||
|
||||
Caption boxes are exported as `htext` [tagged layers](https://reuters-graphics.github.io/ai2svelte/users/tagged-layers/) in ai2svelte. In this example, we use the `handleScroll()` function to check the position of each caption box relative to the viewport width and set its opacity to `1` (visible) or `0` (hidden) based on whether the caption box is within the `threshold` of the viewport.
|
||||
Caption boxes are exported as `htext` [tagged layers](https://reuters-graphics.github.io/ai2svelte/users/tagged-layers/) in ai2svelte. In this example, we use the `handleScroll()` function to check the position of each caption box relative to the viewport width and set its opacity to `1` (visible) or `0` (hidden) based on whether the caption box is within the `threshold` of the viewport. Set `override_text: true` in the ai2svelte export settings to allow custom HTML content in tagged text layers.
|
||||
|
||||
### Parallax effect with png layer
|
||||
|
||||
|
|
@ -194,7 +203,10 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||
import {
|
||||
HorizontalScroller,
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
|
||||
|
|
@ -211,7 +223,7 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
function handleScroll() {
|
||||
// Create a parallax movement for the foreground png layer
|
||||
if (pngLayer) {
|
||||
pngLayer.style.transform = `translateX(${map(progress, 0, 1, -400, 400)}px)`;
|
||||
pngLayer.style.transform = `scale(1.5) translateX(${map(progress, 0, 1, -15, 85)}%)`;
|
||||
}
|
||||
|
||||
// For each caption, checks if position of the caption is below the threshold.
|
||||
|
|
@ -247,6 +259,9 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
window.addEventListener('scroll', handleScroll, {
|
||||
passive: true,
|
||||
});
|
||||
|
||||
// to translate overlay layer on initial load
|
||||
handleScroll();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -259,7 +274,9 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
easing={sineInOut}
|
||||
showDebugInfo={true}
|
||||
>
|
||||
<AiGraphic assetsPath={assets} {onArtboardChange}
|
||||
<AiGraphic
|
||||
assetsPath={assets}
|
||||
{onArtboardChange}
|
||||
taggedText={{
|
||||
htext: {
|
||||
captions: {
|
||||
|
|
@ -273,7 +290,8 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
'<div class="scroller-caption"><strong>Caption 4!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||
},
|
||||
},
|
||||
}} />
|
||||
}}
|
||||
/>
|
||||
</HorizontalScroller>
|
||||
</Block>
|
||||
|
||||
|
|
@ -281,14 +299,14 @@ This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelt
|
|||
:global(.scroller-caption) {
|
||||
padding: 1rem;
|
||||
margin: 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
filter: drop-shadow(0px 2px 16px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
|
||||
## With custom child components
|
||||
|
||||
You can create a custom horizontal layout with any component and pass it as a child to the `HorizontalScroller`. Here's an example with `DatawrapperChart`, `Headline` and ai2svelte components laid out in a horizontal scroll.
|
||||
|
|
@ -355,6 +373,7 @@ You can create a custom horizontal layout with any component and pass it as a ch
|
|||
You can also integrate HorizontalScroller with `ScrollerBase` for a horizontal scroll with vertical captions.
|
||||
|
||||
When using `HorizontalScroller` with `ScrollerBase` or other scrollers, you must:
|
||||
|
||||
- Create a `progress` state variable and bind it to both `ScrollerBase` and `HorizontalScroller`
|
||||
- Set `HorizontalScroller`'s `height` to `100lvh`
|
||||
- Set `handleScroll` to `false`
|
||||
|
|
@ -366,7 +385,7 @@ When using `HorizontalScroller` with `ScrollerBase` or other scrollers, you must
|
|||
import {
|
||||
HorizontalScroller,
|
||||
ScrollerBase,
|
||||
Block
|
||||
Block,
|
||||
} from '@reuters-graphics/graphics-components';
|
||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||
import { circInOut } from 'svelte/easing';
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 250 KiB |
BIN
src/components/HorizontalScroller/assets/illustrator.png
Normal file
|
After Width: | Height: | Size: 574 KiB |
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
function handleScroll() {
|
||||
if (pngLayer) {
|
||||
pngLayer.style.transform = `translateX(${map(progress, 0, 1, -400, 400)}px)`;
|
||||
pngLayer.style.transform = `scale(1.5) translateX(${map(progress, 0, 1, -15, 85)}%)`;
|
||||
}
|
||||
|
||||
if (captions?.length) {
|
||||
|
|
@ -51,6 +51,9 @@
|
|||
window.addEventListener('scroll', handleScroll, {
|
||||
passive: true,
|
||||
});
|
||||
|
||||
// to translate overlay layer on initial load
|
||||
handleScroll();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -68,7 +71,6 @@
|
|||
>
|
||||
<Demo
|
||||
{onArtboardChange}
|
||||
debugTaggedText
|
||||
taggedText={{
|
||||
htext: {
|
||||
captions: {
|
||||
|
|
@ -93,8 +95,9 @@
|
|||
:global(.scroller-caption) {
|
||||
padding: 1rem;
|
||||
margin: 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
filter: drop-shadow(0px 2px 16px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<script lang="ts">
|
||||
<script>
|
||||
// For demo purposes only, hard-wiring img paths from Vite
|
||||
// @ts-ignore img
|
||||
import imageXl from '../imgs/demo-xl.jpg';
|
||||
|
|
@ -6,8 +6,11 @@
|
|||
import imageLg from '../imgs/demo-lg.jpg';
|
||||
// @ts-ignore img
|
||||
import imagePngOverlayXl from '../imgs/layer-overlay-xl.png';
|
||||
// @ts-ignore img
|
||||
import imagePngOverlayLg from '../imgs/layer-overlay-lg.png';
|
||||
|
||||
let {
|
||||
assetsPath = '/',
|
||||
onAiMounted = () => {},
|
||||
onArtboardChange = () => {},
|
||||
taggedText = { text: {}, htext: {} },
|
||||
|
|
@ -15,15 +18,15 @@
|
|||
artboardWidth = $bindable(undefined),
|
||||
} = $props();
|
||||
import { onMount, untrack } from 'svelte';
|
||||
let aiBox: HTMLDivElement | undefined = $state(undefined);
|
||||
let aiBox;
|
||||
let screenWidth = $state(0);
|
||||
let aiBoxWidth = $derived(artboardWidth ?? screenWidth);
|
||||
let activeArtboard: Element | undefined = $state(undefined);
|
||||
let activeArtboard = $state(undefined);
|
||||
onMount(() => {
|
||||
onAiMounted();
|
||||
});
|
||||
$effect(() => {
|
||||
if (aiBoxWidth && aiBox) {
|
||||
if (aiBoxWidth) {
|
||||
const currentArtboard = aiBox.querySelectorAll('.g-artboard')[0];
|
||||
if (currentArtboard?.id !== activeArtboard?.id) {
|
||||
activeArtboard = untrack(() => currentArtboard);
|
||||
|
|
@ -40,47 +43,61 @@
|
|||
class="ai2svelte"
|
||||
bind:this={aiBox}
|
||||
style:--debug-tagged-text={debugTaggedText ? 'visible' : 'hidden'}
|
||||
style:--debug-stroke={debugTaggedText ? '2px' : '0px'}
|
||||
>
|
||||
<!-- Artboard: lg -->
|
||||
{#if aiBoxWidth && aiBoxWidth >= 0 && aiBoxWidth < 800}
|
||||
{#if aiBoxWidth && aiBoxWidth >= 0 && aiBoxWidth < 1200}
|
||||
<div
|
||||
id="g-demo-lg"
|
||||
class="g-artboard"
|
||||
style="max-width: 799px;aspect-ratio: 2.75483870967742;"
|
||||
style="max-width: 1199px;aspect-ratio: 2.75483870967742;"
|
||||
data-aspect-ratio="2.755"
|
||||
data-min-width="0"
|
||||
data-max-width="799"
|
||||
data-max-width="1199"
|
||||
>
|
||||
<div
|
||||
id="g-demo-lg-img"
|
||||
class="g-demo-lg-img g-aiImg"
|
||||
alt=""
|
||||
style="background-image: url({imageLg});"
|
||||
loading="lazy"
|
||||
></div>
|
||||
<div
|
||||
id="g-png-layer-overlay-lg"
|
||||
class="g-png-layer-overlay g-aiImg"
|
||||
alt=""
|
||||
style="opacity:1;;background-image: url({imagePngOverlayLg});"
|
||||
loading="lazy"
|
||||
></div>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Artboard: xl -->
|
||||
{#if aiBoxWidth && aiBoxWidth >= 800}
|
||||
{#if aiBoxWidth && aiBoxWidth >= 1200}
|
||||
<div
|
||||
id="g-demo-xl"
|
||||
class="g-artboard"
|
||||
style="min-width: 800px;aspect-ratio: 6.6758064516129;"
|
||||
data-aspect-ratio="6.676"
|
||||
data-min-width="800"
|
||||
style="min-width: 1200px;aspect-ratio: 4.80806451612903;"
|
||||
data-aspect-ratio="4.808"
|
||||
data-min-width="1200"
|
||||
>
|
||||
<div
|
||||
id="g-demo-xl-img"
|
||||
class="g-demo-xl-img g-aiImg"
|
||||
alt=""
|
||||
style="background-image: url({imageXl});"
|
||||
loading="lazy"
|
||||
></div>
|
||||
<div
|
||||
id="g-png-layer-overlay-xl"
|
||||
class="g-png-layer-overlay g-aiImg"
|
||||
alt=""
|
||||
style="opacity:1;;background-image: url({imagePngOverlayXl});"
|
||||
loading="lazy"
|
||||
></div>
|
||||
<div
|
||||
id="g-caption2"
|
||||
class="g-captions g-aiAbs"
|
||||
style="top:38.5484%;left:23.6715%;width:5.2428%;"
|
||||
style="top:14.3548%;left:34.8126%;width:7.2794%;"
|
||||
>
|
||||
<p
|
||||
class="g-pstyle0 g-taggedText g-htext"
|
||||
|
|
@ -93,7 +110,7 @@
|
|||
<div
|
||||
id="g-caption3"
|
||||
class="g-captions g-aiAbs"
|
||||
style="top:38.5484%;left:49.4749%;width:5.2428%;"
|
||||
style="top:14.3548%;left:60.6764%;width:7.2794%;"
|
||||
>
|
||||
<p
|
||||
class="g-pstyle0 g-taggedText g-htext"
|
||||
|
|
@ -106,7 +123,7 @@
|
|||
<div
|
||||
id="g-caption4"
|
||||
class="g-captions g-aiAbs"
|
||||
style="top:38.5484%;left:83.976%;width:5.2428%;"
|
||||
style="top:14.3548%;left:84.0914%;width:7.2794%;"
|
||||
>
|
||||
<p
|
||||
class="g-pstyle0 g-taggedText g-htext"
|
||||
|
|
@ -119,7 +136,7 @@
|
|||
<div
|
||||
id="g-caption1"
|
||||
class="g-captions g-aiAbs"
|
||||
style="top:38.5484%;left:2.966%;width:3.4791%;"
|
||||
style="top:14.3548%;left:4.1182%;width:4.8306%;"
|
||||
>
|
||||
<p
|
||||
class="g-pstyle0 g-taggedText g-htext"
|
||||
|
|
@ -137,7 +154,7 @@
|
|||
|
||||
TAGGED TEXT PROPS
|
||||
|
||||
taggedText={{
|
||||
taggedText={
|
||||
{
|
||||
"text": {
|
||||
|
||||
|
|
@ -151,12 +168,12 @@ taggedText={{
|
|||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
-->
|
||||
<!-- End ai2svelte - 2026-01-07 11:23 -->
|
||||
<!-- End ai2svelte - 2026-01-13 11:12 -->
|
||||
|
||||
<!-- Generated by ai2svelte v1.0.3 - 2026-01-07 11:23 -->
|
||||
<!-- Generated by ai2svelte v1.0.3 - 2026-01-13 11:12 -->
|
||||
<!-- ai file: demo.ai -->
|
||||
<style lang="scss">
|
||||
#g-demo-box,
|
||||
|
|
@ -187,6 +204,13 @@ taggedText={{
|
|||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#g-demo-box .g-aiSymbol {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#g-demo-box .g-aiPointText p {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#g-demo-box {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -225,8 +249,9 @@ taggedText={{
|
|||
content: attr(data-tagged-type);
|
||||
padding: 0px 4px;
|
||||
font-size: 0.6rem;
|
||||
font-style: normal;
|
||||
color: #fff;
|
||||
background-color: black;
|
||||
background-color: #ee0000;
|
||||
display: block;
|
||||
font-weight: 800;
|
||||
visibility: var(--debug-tagged-text, hidden);
|
||||
|
|
@ -236,14 +261,34 @@ taggedText={{
|
|||
content: attr(data-tagged-prop);
|
||||
padding: 0px 4px;
|
||||
font-size: 0.8rem;
|
||||
font-style: normal;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
visibility: var(--debug-tagged-text, hidden);
|
||||
}
|
||||
|
||||
.g-taggedText:empty {
|
||||
background-color: #00000088;
|
||||
outline: 2px solid black;
|
||||
background-color: #440000;
|
||||
outline: 2px solid #ee0000;
|
||||
visibility: var(--debug-tagged-text, hidden);
|
||||
}
|
||||
|
||||
.g-taggedText:not(:empty)::before {
|
||||
content: attr(data-tagged-type);
|
||||
position: absolute;
|
||||
width: calc(100% + 4px);
|
||||
transform: translateY(-100%) translateX(-2px);
|
||||
padding: 0px 4px;
|
||||
font-size: 0.6rem;
|
||||
font-style: normal;
|
||||
color: #fff;
|
||||
background-color: black;
|
||||
display: block;
|
||||
font-weight: 800;
|
||||
visibility: var(--debug-tagged-text, hidden);
|
||||
}
|
||||
|
||||
.g-taggedText {
|
||||
outline: var(--debug-stroke, 0px) solid black;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1 MiB After Width: | Height: | Size: 881 KiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 1.2 MiB |