svelte 中可拖动的 d3 世界地球仪

发布于 2025-01-10 21:24:05 字数 4396 浏览 0 评论 0原文

我有下一个问题,我正在尝试在 svelte 应用程序中使用 d3 创建一个可拖动的世界地球仪,我遇到的问题是当尝试拖动地球仪时,拖动操作很滞后我认为我的问题与可拖动组件中的内存泄漏我不知道这是否是这种滞后行为的主要原因。地球仪是用 svg 绘制的,

这是应用程序链接: https://codesandbox.io/s/cocky-benz-2mk5bs

可拖动组件

<script>
    import { onMount, onDestroy, afterUpdate } from 'svelte';

    import { mouseAdjusted } from '../lib/Utilities';

    onMount(() => console.log('mounted'));

    afterUpdate(() => {
        //console.log('Destroyed');
    });

    export let mouseX;
    export let mouseY;
    let offset;

    let isMove = false;
    const start = (e) => {
        isMove = true;
        const element = e.target;
        const target = e.target.parentElement.parentElement.getScreenCTM();

        // get the mouse position in the svg shape
        offset = mouseAdjusted(e.clientX, e.clientY, target);
        // rest the shape mouse posicion from the shape x y coordinates
        offset[1] -= +element.getAttributeNS(null, 'y');
        offset[0] -= +element.getAttributeNS(null, 'x');
    };
    const move = (e) => {
        if (isMove) {
            const target = e.target.parentElement.parentElement.getScreenCTM();
            const [x, y] = mouseAdjusted(e.clientX, e.clientY, target);
            mouseX = offset[0] - x;
            mouseY = offset[1] - y;
        }
    };
    const end = () => {
        isMove = false;
        offset = null;
    };
</script>

<svelte:window
    on:mousemove|preventDefault|stopPropagation={move}
    on:mouseup|preventDefault|stopPropagation={end}
/>
<g class="draggable" on:mousedown|preventDefault|stopPropagation={start}>
    <slot />
</g>

图形组件

<script>
    import { onMount, onDestroy } from "svelte";
    import * as d3 from "d3";
    import * as topojson from "topojson-client";
    import Draggable from "./draggable.svelte";

    let width = 500;
    $: width = width * 0.95;
    let height = 500;
    $: height = height * 0.98;
    let world;
    let x;
    let y;
    let projection;
    let path;
    let ROTATION = [-45, -65, 0];
    // Add topojsom
    onMount(async () => {
      const resp = await d3.json(
        "/src/assets/world-administrative-boundaries.json"
      );
      world = await topojson.feature(resp, "world-administrative-boundaries");
    });

    $: ROTATION = [-x, y, 0];
    $: projection = d3
      .geoOrthographic()
      .fitSize([width, height], world)
      .scale([width / 3])
      .rotate(ROTATION);

    $: path = d3.geoPath(projection);

    const fillScale = d3
      .scaleOrdinal()
      .domain(["", ""])
      .range([" hsl(40, 98%, 47%)", "hsl(9, 64%, 50%)"])
      .unknown("hsl(227, 16%, 42%)");
    const strokeScale = d3
      .scaleOrdinal()
      .domain(["", ""])
      .range([" hsl(40, 98%, 35%)", "hsl(9, 64%, 35%)"])
      .unknown("hsl(227, 16%, 22%)");
    // transform to features
    $: countries = world?.features.map(obj => {
      const { geometry, properties, _ } = obj;
      //const d = path(geometry);
      const fill = fillScale(properties.iso3);
      const stroke = strokeScale(properties.iso3);
      const newProperties = Object.assign({ ...properties }, { fill, stroke });
      return Object.assign({}, { geometry, properties: newProperties });
    });

    //  $: console.log('features', features);
    //$: console.log('first', ROTATION);
</script>

<svelte:window bind:innerWidth={width} bind:innerHeight={height} />

<svg {width} {height}>
    <Draggable bind:mouseX={x} bind:mouseY={y}>
        {#if countries}
            <path class="sphere" d={path({ type: 'Sphere' })} />
            <g class="countries">
                {#each countries as country}
                    <path
                        d={path(country.geometry)}
                        fill={country.properties.fill}
                        stroke={country.properties.stroke}
                        
                    />
                {/each}
            </g>
        {/if}
    </Draggable>
</svg>

<!-- markup (zero or more items) goes here -->
<style>
    svg {
      border: 1px solid tomato;
    }

    .sphere {
      fill: var(--base-color-2);
    }
</style>

I have the next problem I'm trying to create a draggable world globe with d3 in a svelte app, the problem that i have is when a try to drag the globe the drag action is laggy I think that my problem have someting to do with a memory leak in the draggable component I don't know if this is the main reason of this laggy behaviour. The globe was drew with svg's

This is the App link:
https://codesandbox.io/s/cocky-benz-2mk5bs

Draggable component

<script>
    import { onMount, onDestroy, afterUpdate } from 'svelte';

    import { mouseAdjusted } from '../lib/Utilities';

    onMount(() => console.log('mounted'));

    afterUpdate(() => {
        //console.log('Destroyed');
    });

    export let mouseX;
    export let mouseY;
    let offset;

    let isMove = false;
    const start = (e) => {
        isMove = true;
        const element = e.target;
        const target = e.target.parentElement.parentElement.getScreenCTM();

        // get the mouse position in the svg shape
        offset = mouseAdjusted(e.clientX, e.clientY, target);
        // rest the shape mouse posicion from the shape x y coordinates
        offset[1] -= +element.getAttributeNS(null, 'y');
        offset[0] -= +element.getAttributeNS(null, 'x');
    };
    const move = (e) => {
        if (isMove) {
            const target = e.target.parentElement.parentElement.getScreenCTM();
            const [x, y] = mouseAdjusted(e.clientX, e.clientY, target);
            mouseX = offset[0] - x;
            mouseY = offset[1] - y;
        }
    };
    const end = () => {
        isMove = false;
        offset = null;
    };
</script>

<svelte:window
    on:mousemove|preventDefault|stopPropagation={move}
    on:mouseup|preventDefault|stopPropagation={end}
/>
<g class="draggable" on:mousedown|preventDefault|stopPropagation={start}>
    <slot />
</g>

Graph component

<script>
    import { onMount, onDestroy } from "svelte";
    import * as d3 from "d3";
    import * as topojson from "topojson-client";
    import Draggable from "./draggable.svelte";

    let width = 500;
    $: width = width * 0.95;
    let height = 500;
    $: height = height * 0.98;
    let world;
    let x;
    let y;
    let projection;
    let path;
    let ROTATION = [-45, -65, 0];
    // Add topojsom
    onMount(async () => {
      const resp = await d3.json(
        "/src/assets/world-administrative-boundaries.json"
      );
      world = await topojson.feature(resp, "world-administrative-boundaries");
    });

    $: ROTATION = [-x, y, 0];
    $: projection = d3
      .geoOrthographic()
      .fitSize([width, height], world)
      .scale([width / 3])
      .rotate(ROTATION);

    $: path = d3.geoPath(projection);

    const fillScale = d3
      .scaleOrdinal()
      .domain(["", ""])
      .range([" hsl(40, 98%, 47%)", "hsl(9, 64%, 50%)"])
      .unknown("hsl(227, 16%, 42%)");
    const strokeScale = d3
      .scaleOrdinal()
      .domain(["", ""])
      .range([" hsl(40, 98%, 35%)", "hsl(9, 64%, 35%)"])
      .unknown("hsl(227, 16%, 22%)");
    // transform to features
    $: countries = world?.features.map(obj => {
      const { geometry, properties, _ } = obj;
      //const d = path(geometry);
      const fill = fillScale(properties.iso3);
      const stroke = strokeScale(properties.iso3);
      const newProperties = Object.assign({ ...properties }, { fill, stroke });
      return Object.assign({}, { geometry, properties: newProperties });
    });

    //  $: console.log('features', features);
    //$: console.log('first', ROTATION);
</script>

<svelte:window bind:innerWidth={width} bind:innerHeight={height} />

<svg {width} {height}>
    <Draggable bind:mouseX={x} bind:mouseY={y}>
        {#if countries}
            <path class="sphere" d={path({ type: 'Sphere' })} />
            <g class="countries">
                {#each countries as country}
                    <path
                        d={path(country.geometry)}
                        fill={country.properties.fill}
                        stroke={country.properties.stroke}
                        
                    />
                {/each}
            </g>
        {/if}
    </Draggable>
</svg>

<!-- markup (zero or more items) goes here -->
<style>
    svg {
      border: 1px solid tomato;
    }

    .sphere {
      fill: var(--base-color-2);
    }
</style>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文