我也花了一些时间来解决这个问题。但最终它实际上并没有那么复杂。他们的关键步骤是决定哪个库负责哪个责任。
D3 只是与 Svelte 重叠,因为它也在屏幕上呈现内容。但是如果你仔细想想,如果你已经有了 Svelte,你就真的不需要渲染器了。一旦有了渲染器,关于图表的复杂部分实际上就是定位。这就是 D3 真正 的亮点所在。如果您从两个世界中“挑选”最好的,您实际上最终会获得出色的开发体验。
但是,唉,您也可以将渲染留给 D3。但是,您需要尽可能避免 Svelte。
基本上你有两个选择都很好:
- Svelte 仅渲染容器 DOM,然后交给 D3 进行计算和渲染。您仅在 onMount 和 onDestroy 期间在两个世界之间进行交互
- Svelte 呈现整个 DOM,D3 提供图表位置。
关于画笔功能:
我发现最好创建一个带有插槽的 ChartContainer(本质上只是一个 SVG),然后在其中放置一个 Brush 组件。
<script>
import { createEventDispatcher } from "svelte";
export let minX;
export let maxX;
export let dX = 0;
export let height;
const dispatch = createEventDispatcher();
let startX,
endX,
mouseDown = false,
brushArea;
function onMouseDown(event) {
if (mouseDown) return;
mouseDown = true;
brushArea.removeEventListener("mousemove", onMouseMove);
brushArea.removeEventListener("mouseup", onMouseUp);
brushArea.addEventListener("mousemove", onMouseMove);
brushArea.addEventListener("mouseup", onMouseUp);
brushArea.style.cursor = "ew-resize";
startX = Math.max(event.offsetX - dX, minX);
endX = null;
}
function onMouseMove(event) {
endX = Math.min(event.offsetX - dX, maxX);
}
function onMouseUp(event) {
mouseDown = false;
if (!endX) startX = null;
brushArea.style.cursor = null;
brushArea.removeEventListener("mousemove", onMouseMove);
brushArea.removeEventListener("mouseup", onMouseUp);
const active = !!startX;
dispatch("brush", {active, startX, endX, clear});
}
function clear() {
startX = null;
endX = null;
}
</script>
<rect class="ui--chart__brush_area"
bind:this={brushArea}
x={minX}
y="0"
height={height}
width={maxX-minX}
on:mousedown={onMouseDown}
/>
{#if endX != null}
<rect class="ui--chart__brush"
x={startX < endX ? startX : endX}
y="0"
height={height}
width={startX < endX ? endX-startX : startX-endX}
/>
{/if}
dX 属性用于考虑左边距。在您的用例中可能需要也可能不需要(取决于您如何设置图表)。关键是能够从鼠标事件中使用 offsetX,以便您知道鼠标事件触发的 SVG 边框有多远。
那么,你就
- 监听画笔事件
- 提取坐标
- 使用 yourScale.invert(coordinate) 将它们转换为值
- 使用这些值,例如更新您的图表
像这样:
function onBrush(event) {
const {active, startX, endX, clear} = event.detail;
if (active) {
const startDate = scaleX.invert(startX);
const endDate = scaleX.invert(endX);
dispatch("brush", {active, startX, endX, startDate, endDate, clear});
}
}
希望这可以帮助其他为此苦苦挣扎的人。祝你好运!