Yandex 地图 API 2.1。使用 knockoutjs 动态过滤地标
Posted
技术标签:
【中文标题】Yandex 地图 API 2.1。使用 knockoutjs 动态过滤地标【英文标题】:Yandex maps API 2.1. Filter placemarks dynamically using knockoutjs 【发布时间】:2015-07-17 07:04:57 【问题描述】:我有以下问题:
我有几个参数,例如国家、地区、城市、品牌和名称以及 500 多个 yandex 地图地标,通过 ObjectManager (Yandex API 2.0) 添加。我需要按参数过滤地标,但是当我按下“搜索”按钮时,只有一个地标隐藏。请帮助我,了解我做错了什么。谢谢
代码sn-p如下:
var dataFromServer =
directions: [
id: 1, name: 'Commercial',
id: 2, name: 'Agriculture',
id: 3, name: 'Building'
],
brands: [
id: 1, name: 'Iveco',
id: 2, name: 'New Holland Agriculture',
id: 3, name: 'Case Agriculture'
],
countries: [
id: 1, name: 'Russia',
id: 2, name: 'USA',
id: 3, name: 'Germany'
],
regions: [
id: 1, country: 1, name: 'Russia region 1',
id: 2, country: 1, name: 'Russia region 2',
id: 3, country: 2, name: 'USA region 1',
id: 4, country: 2, name: 'USA region 2',
id: 5, country: 3, name: 'Germany region 1',
id: 6, country: 3, name: 'Germany region 2'
],
cities: [
id: 1, region: 1, name: 'Russia region 1 city 1',
id: 2, region: 1, name: 'Russia region 1 city 2',
id: 3, region: 2, name: 'Russia region 2 city 1',
id: 4, region: 2, name: 'Russia region 2 city 2',
id: 5, region: 3, name: 'USA region 1 city 1',
id: 6, region: 3, name: 'USA region 1 city 2',
id: 7, region: 4, name: 'USA region 2 city 1',
id: 8, region: 4, name: 'USA region 2 city 2',
id: 9, region: 5, name: 'Germany region 1 city 1',
id: 10, region: 5, name: 'Germany region 1 city 2',
id: 11, region: 6, name: 'Germany region 2 city 1',
id: 12, region: 6, name: 'Germany region 2 city 2'
]
,
testDealers =
type: "FeatureCollection",
features: [
type: 'Feature',
geometry:
type: 'Point',
coordinates: [55.34954, 37.721587]
,
options:
brand: 1,
direction: 1,
city: 1,
name: "Test"
,
type: 'Feature',
geometry:
type: 'Point',
coordinates: [55.24954, 37.4]
,
options:
brand: 2,
direction: 2,
city: 2,
name: "Test 2"
,
type: 'Feature',
geometry:
type: 'Point',
coordinates: [55.14954, 37.61587]
,
options:
brand: 3,
direction: 1,
city: 3,
name: "Test 3"
]
;
// end testing data
var ViewModel = ko.mapping.fromJS(dataFromServer);
ViewModel.country = ko.observable();
ViewModel.region = ko.observable();
ViewModel.city = ko.observable();
ViewModel.brand = ko.observable();
ViewModel.direction = ko.observable();
ViewModel.name = ko.observable();
ViewModel.computedRegions = ko.computed(function ()
return ko.utils.arrayFilter(ViewModel.regions(), function(item)
return item.country() == ViewModel.country();
);
);
ViewModel.computedCities = ko.computed(function ()
return ko.utils.arrayFilter(ViewModel.cities(), function(item)
return item.region() == ViewModel.region();
);
);
ViewModel.searchQuery = ko.computed(function()
return ko.toJSON(
country: ViewModel.country(),
region: ViewModel.region(),
direction: ViewModel.direction(),
city: ViewModel.city(),
brand: ViewModel.brand(),
name: ViewModel.name()
);
);
ViewModel.busy = ko.observable(false);
ViewModel.search = function()
window.objectManager.setFilter("options.brand == " + ViewModel.brand());
ymaps.ready(function()
window.dealermap = new ymaps.Map('dealermap',
center: [55.30954, 37.721587],
zoom: 8
);
window.objectManager = new ymaps.ObjectManager( clusterize: true );
window.objectManager.add(ko.toJSON(testDealers));
window.dealermap.geoObjects.add(window.objectManager);
window.dealermap.setBounds(objectManager.getBounds());
ko.applyBindings(ViewModel);
);
#dealermap width: 300px; height: 300px; padding: 0; margin: 0; border: 1px solid #000
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<p>Direction:
<select data-bind="options: directions,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: direction,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Country:
<select data-bind="options: countries,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: country,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Region:
<select data-bind="options: computedRegions,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: region,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>City:
<select data-bind="options: computedCities,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: city,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Brand:
<select data-bind="options: brands,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: brand,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Name:
<input type="text" data-bind="value: name, disable: busy" />
</p>
<p>
<button data-bind="click: search, disable: busy">Search</button>
</p>
<script type="text/html" id="dealer-template">
<li><a target="_blank" data-bind="attr: href: link , text: name"></a></li>
</script>
<hr />
<p>
Search query:
<div data-bind="text: searchQuery"></div>
</p>
<div data-bind="if: busy"><img src="http://ukrainianwall.com/wp-content/themes/legatus-theme/images/loading.gif"/></div>
<div data-bind="visible: !busy()">
Map:
<div id="dealermap"></div>
</div>
【问题讨论】:
【参考方案1】:FeatureCollection 中的所有对象都必须有一个唯一的 id,并且 filter 应该是一个函数(而不是字符串)以获得更好的结果。以下是按 BRAND ONLY 过滤的示例。其他过滤器将相同:
var dataFromServer =
directions: [
id: 1, name: 'Commercial',
id: 2, name: 'Agriculture',
id: 3, name: 'Building'
],
brands: [
id: 1, name: 'Iveco',
id: 2, name: 'New Holland Agriculture',
id: 3, name: 'Case Agriculture'
],
countries: [
id: 1, name: 'Russia',
id: 2, name: 'USA',
id: 3, name: 'Germany'
],
regions: [
id: 1, country: 1, name: 'Russia region 1',
id: 2, country: 1, name: 'Russia region 2',
id: 3, country: 2, name: 'USA region 1',
id: 4, country: 2, name: 'USA region 2',
id: 5, country: 3, name: 'Germany region 1',
id: 6, country: 3, name: 'Germany region 2'
],
cities: [
id: 1, region: 1, name: 'Russia region 1 city 1',
id: 2, region: 1, name: 'Russia region 1 city 2',
id: 3, region: 2, name: 'Russia region 2 city 1',
id: 4, region: 2, name: 'Russia region 2 city 2',
id: 5, region: 3, name: 'USA region 1 city 1',
id: 6, region: 3, name: 'USA region 1 city 2',
id: 7, region: 4, name: 'USA region 2 city 1',
id: 8, region: 4, name: 'USA region 2 city 2',
id: 9, region: 5, name: 'Germany region 1 city 1',
id: 10, region: 5, name: 'Germany region 1 city 2',
id: 11, region: 6, name: 'Germany region 2 city 1',
id: 12, region: 6, name: 'Germany region 2 city 2'
]
,
testDealers =
type: "FeatureCollection",
features: [
type: 'Feature',
id: 0,
geometry:
type: 'Point',
coordinates: [55.34954, 37.721587]
,
options:
brand: 1,
direction: 1,
city: 1,
name: "Test"
,
type: 'Feature',
id: 1,
geometry:
type: 'Point',
coordinates: [55.24954, 37.4]
,
options:
brand: 2,
direction: 2,
city: 2,
name: "Test 2"
,
type: 'Feature',
id: 2,
geometry:
type: 'Point',
coordinates: [55.14954, 37.61587]
,
options:
brand: 3,
direction: 1,
city: 3,
name: "Test 3"
]
;
// end testing data
var ViewModel = ko.mapping.fromJS(dataFromServer);
ViewModel.country = ko.observable();
ViewModel.region = ko.observable();
ViewModel.city = ko.observable();
ViewModel.brand = ko.observable();
ViewModel.direction = ko.observable();
ViewModel.name = ko.observable();
ViewModel.computedRegions = ko.computed(function ()
return ko.utils.arrayFilter(ViewModel.regions(), function(item)
return item.country() == ViewModel.country();
);
);
ViewModel.computedCities = ko.computed(function ()
return ko.utils.arrayFilter(ViewModel.cities(), function(item)
return item.region() == ViewModel.region();
);
);
ViewModel.searchQuery = ko.computed(function()
return ko.toJSON(
country: ViewModel.country(),
region: ViewModel.region(),
direction: ViewModel.direction(),
city: ViewModel.city(),
brand: ViewModel.brand(),
name: ViewModel.name()
);
);
ViewModel.busy = ko.observable(false);
ViewModel.search = function()
window.objectManager.setFilter(function(object)
return object.options.brand == ViewModel.brand();
);
window.dealermap.setBounds(objectManager.getBounds());
ymaps.ready(function()
window.dealermap = new ymaps.Map('dealermap',
center: [55.30954, 37.721587],
zoom: 8
, maxZoom: 15, minZoom: 3 );
window.objectManager = new ymaps.ObjectManager( clusterize: true );
window.objectManager.add(ko.toJSON(testDealers));
window.dealermap.geoObjects.add(window.objectManager);
window.dealermap.setBounds(objectManager.getBounds());
ko.applyBindings(ViewModel);
);
#dealermap width: 300px; height: 300px; padding: 0; margin: 0; border: 1px solid #000
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<p>Direction:
<select data-bind="options: directions,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: direction,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Country:
<select data-bind="options: countries,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: country,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Region:
<select data-bind="options: computedRegions,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: region,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>City:
<select data-bind="options: computedCities,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: city,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Brand:
<select data-bind="options: brands,
disable: busy,
optionsText: 'name',
optionsValue: 'id',
value: brand,
optionsCaption: 'Not selected...'">
</select>
</p>
<p>Name:
<input type="text" data-bind="value: name, disable: busy" />
</p>
<p>
<button data-bind="click: search, disable: busy">Search</button>
</p>
<script type="text/html" id="dealer-template">
<li><a target="_blank" data-bind="attr: href: link , text: name"></a></li>
</script>
<hr />
<p>
Search query:
<div data-bind="text: searchQuery"></div>
</p>
<div data-bind="if: busy"><img src="http://ukrainianwall.com/wp-content/themes/legatus-theme/images/loading.gif"/></div>
<div data-bind="visible: !busy()">
Map:
<div id="dealermap"></div>
</div>
【讨论】:
以上是关于Yandex 地图 API 2.1。使用 knockoutjs 动态过滤地标的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 react-yandex-maps 在 yandex 地图上构建路线