在本教程中,我们将创建一个线图Svelte组件,我们可以在Svelte应用程序中使用。我们将使用HTML的可扩展矢量图形(SVG)。借助SVG的帮助,我们可以使用几行代码创建线条图。我们还将使用Svelte的反应性变量来使线图交互。
我们还将使用CSS / SCSS样式。在下面,您将看到我们今天将创建的内容。
在组件中,我们将将给定的数据分配到一个范围内以适合图表。这种行为对您来说可能无济于事,因此您的主要收获可能是SVG令人难以置信,以及使用它创建图形的容易。
首先,我们将创建线图组件。然后,我们将在Svelte应用程序中使用它。
让我们开始。
您会找到完成代码here的演示。
线图组件
该组件由脚本标签,带有SVG的DIV容器和样式标签组成。
列表组件的脚本
在我们的line-diagram.svelte
文件中,我们首先导出name
和values
属性。 name
属性将用作图的标题,并且values
属性将用于绘制图表。 values
属性是数字的数组。
接下来,我们定义了图的高度,宽度和垂直填充;这些数字主要选择适合图表。因为后来,我们将在此范围内适合所有数据。
此外,我们将获得数据集的最高和最低值,并计算我们所需的范围和数据范围之间的比例。这将用于扩展数据以符合图表。
这一切听起来都很复杂,但是在这里忍受我。
<script lang="ts">
export let name : string = ''
export let values : number[]
// These values are arbitrarily chosen to fit the Diagram
let height = 50;
let width = 100;
let padding = 5;
$: highestValue = values.reduce((a, b) => Math.max(a, b))
$: lowestValue = values.reduce((a, b) => Math.min(a, b))
$: multiplier = ( height - 2 * padding ) / (highestValue - lowestValue);
...
</script>
最后,在脚本标签中,我们将定义一个反应变量path
,该变量将用于绘制图表。然后,我们使用一个反应块来计算路径。该路径是一个包含SVG Path commands绘制图表的字符串。
let path = ''
$: {
path = "M0 " + (height);
for (let i = 0; i < values.length; i++) {
let yValue = height - (((values[i] - lowestValue) * multiplier) + padding) ;
let xValue = i / (values.length - 1) * width;
path += " L " + xValue + " " + yValue;
}
path += " L" + width + " " + height;
path += " L 0 " + height;
path += " Z";
}
线图组件的HTML
接下来,我们将为组件创建HTML,由带有SVG的DIV容器组成。 SVG具有定义SVG大小的视图框。 ViewBox是一个字符串,其中包含左上角的X和Y位置以及SVG的宽度和高度。我们将使用前面定义的宽度和高度变量。
我们还将preserveAspectRatio
属性设置为none
,以便SVG扩展以适合容器。
<div class="container">
<svg
class="diagramm_svg"
viewBox={"0 0 " + width + " " + height}
preserveAspectRatio="none"
>
<!-- More to Come -->
</svg>
</div>
我们首先定义SVG中的koude9标签。 defs
标签用于定义SVG元素,可以在SVG中重复使用。在我们的情况下,我们将定义一个线性梯度,我们将使用该梯度填充图表。
之后,我们使用path
元素创建此行。该路径由我们前面定义的path
变量定义。此路径元素通过在填充属性中通过ID引用其ID来使用梯度。
<defs>
<linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
<stop stop-color="hsl(200 100% 50%)" offset="0%" />
<stop stop-color="hsl(200 100% 20% / 0.2)" offset="100%"/>
</linearGradient>
</defs>
<path d={path} class="line" fill="url(#gradient)"/>
最后,我们将文本标签添加到我们的图中。注意text-anchor
和dominant-baseline
属性。
<!-- Show Labels -->
<text x={width - 2.5} y={height - padding} class="label_text" text-anchor="end" dominant-baseline="middle">{ Math.round(lowestValue) }</text>
<line x1={width - 2} y1={height - padding} x2={width} y2={height - padding} class="label_line"></line>
<text x={width - 2.5} y={padding} class="label_text" text-anchor="end" dominant-baseline="middle">{ Math.round(highestValue) }</text>
<line x1={width - 2} y1={padding} x2={width} y2={padding} class="label_line"></line>
<text x="2" y={padding} class="title_text">{ name }</text>
线图组件的CSS
最后,我们在组件中添加了一些CSS。我们将使用SCSS。我们首先定义容器和SVG。我们还向SVG添加边框,以便我们可以看到它的大小。我不会浏览它,但是您会看到下面的代码。
.container {
background-color: hsl(200 50% 20%);
background: linear-gradient(150deg, hsl(200 50% 20%), hsl(200 50% 10%));
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
.diagramm_svg {
width: 100%;
height: 100%;
.label_line {
stroke-width: 0.3px;
stroke: hsl(200 0% 100% / 0.3);
}
.title_text {
font-size: 3px;
fill: white;
font-weight: 600;
}
.label_text {
font-size: 2px;
fill: white;
text-align: right;
}
}
}
使用线图组件
现在我们如何使用此组件?为了证明这一点,我将使用我在this article中使用的天气API来制作一个简单的图表。
我们首先获取API URL并获得JSON。然后,我们可以将这些数据放入WeatherDataPromise变量中。
async function getWeatherData() {
const response = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m`)
return await response.json()
}
let weatherDataPromise = getWeatherData()
最后,我们使用Svelte等待障碍物等待解决的承诺解决。然后,我们将数据传递给我们的lineiagram组件。
<div class="container">
<h2>My Cool Line Diagram</h2>
<br>
<div class="weather_container">
<!-- Await -->
{#await weatherDataPromise}
<p>Waiting for weather data...</p>
{:then data}
<LineDiagram values={data.hourly.temperature_2m} name="Weather Data"/>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
</div>
</div>
结论
就是这样;我希望您有一个愉快的读物,并学到了一些新知识。如您所见,当正确和动态使用时,SVG是强大的。例如,您可以做一个Responsive Dog。