畅通无阻
#javascript #前端 #svelte #data

在本教程中,我们将创建一个线图Svelte组件,我们可以在Svelte应用程序中使用。我们将使用HTML的可扩展矢量图形(SVG)。借助SVG的帮助,我们可以使用几行代码创建线条图。我们还将使用Svelte的反应性变量来使线图交互。

我们还将使用CSS / SCSS样式。在下面,您将看到我们今天将创建的内容。

Line Chart with Svelte

在组件中,我们将将给定的数据分配到一个范围内以适合图表。这种行为对您来说可能无济于事,因此您的主要收获可能是SVG令人难以置信,以及使用它创建图形的容易。

首先,我们将创建线图组件。然后,我们将在Svelte应用程序中使用它。

让我们开始。

您会找到完成代码here的演示。

线图组件

该组件由脚本标签,带有SVG的DIV容器和样式标签组成。

列表组件的脚本

在我们的line-diagram.svelte文件中,我们首先导出namevalues属性。 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-anchordominant-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