如何在Svelte应用中使用双范围滑块过滤地图上的城市
苏格兰地图Svelte应用城市人口筛选问题修复
问题描述
开发了一个展示苏格兰地图的Svelte应用,地图上标注多个城市。计划通过双范围滑块根据人口数量筛选显示的城市,已添加RangeSlider组件及事件处理器,控制台能正确打印滑块取值,但使用数组filter方法过滤城市数据时未生效。
问题根源
Array.filter()方法不会修改原数组,而是返回新的过滤后数组,当前代码仅调用filter却未将结果赋值给用于渲染的变量。- 模板中始终遍历原始的
cities数组,未关联过滤后的结果,导致滑块变化无法触发视图更新。
修复方案
1. 定义响应式过滤变量
在脚本中添加响应式变量filteredCities,初始化为原始城市数据:
import { cities } from "./cities"; // 新增:存储过滤后的城市列表 let filteredCities = [...cities]; let maxPopSize = 598830; let newValues = [0, maxPopSize];
2. 优化过滤逻辑(两种方式可选)
方式一:使用响应式声明自动触发过滤
利用Svelte的$:响应式特性,当newValues变化时自动重新过滤:
// 响应式过滤:当滑块值变化时自动更新filteredCities $: filteredCities = cities.filter(d => d.population >= newValues[0] && d.population <= newValues[1] ); function handleOnChange(event){ newValues = event.detail.values; }
方式二:在事件处理器中直接赋值
function handleOnChange(event){ newValues = event.detail.values; // 将filter结果赋值给filteredCities filteredCities = cities.filter(d => d.population >= newValues[0] && d.population <= newValues[1] ); }
3. 修改模板渲染逻辑
将遍历的数组从cities改为filteredCities:
{#each filteredCities as city} <circle class="city" cx={$currentProj([city.lon, city.lat])[0]} cy={$currentProj([city.lon, city.lat])[1]} r=5 fill=#000 /> {/each}
修改后的完整App.svelte脚本部分
<script> import { geoAlbers, geoPath, geoProjection } from "d3-geo"; import { geoAlbersUk } from "d3-composite-projections"; import { scaleLinear, scaleSqrt } from "d3-scale"; import { extent } from "d3-array"; import { onMount } from "svelte"; import { feature } from "topojson"; import { tweened } from "svelte/motion"; import { interpolate } from "d3-interpolate"; import Feature from "./Feature.svelte"; import { cities } from "./cities"; import RangeSlider from "svelte-range-slider-pips"; let data = []; let colorScale = () => {}; const width = "960"; const height = "500"; const projectionAlbers = geoAlbers() .rotate([4.4, 0.8]) .center([0, 55.4]) .parallels([50, 60]) .scale(3800) .translate([width / 2, (1.8 * height) / 2]); const projectionAlbersUk = geoAlbersUk() .translate([width / 2, (1.85 * height) / 2]) .scale(5200); const currentProj = tweened(projectionAlbers, { duration: 1000 }); $: path = geoPath().projection($currentProj); const opacity = tweened(0, { duration: 1000 }); onMount(async function() { const response = await fetch( "https://gist.githubusercontent.com/rveciana/27272a581e975835aaa321ddf816d726/raw/c40062a328843322208b8e98c2104dc8f6ad5301/uk-counties.json" ); const json = await response.json(); const topoData = feature(json, json.objects.UK); const land = { ...topoData, features: topoData.features.filter( d => d.properties.NAME_1 === "Scotland" ) }; const namesExtent = extent(land.features, d => d.properties.NAME_2.length); data = land.features; }); let maxPopSize = 598830; let newValues = [0, maxPopSize]; // 初始化过滤后的城市列表 let filteredCities = [...cities]; // 响应式过滤逻辑 $: filteredCities = cities.filter(d => d.population >= newValues[0] && d.population <= newValues[1] ); function handleOnChange(event){ newValues = event.detail.values; } </script>
内容的提问来源于stack exchange,提问作者sprucegoose
相关产品推荐
相关产品推荐

