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 动态过滤地标的主要内容,如果未能解决你的问题,请参考以下文章

在 Yandex Maps API 中设置标记图标

如何获取 Yandex 全景图像

如何通过 react-yandex-maps 在 yandex 地图上构建路线

YANDEX API 打开一个未显示的地理点

api yandex 在 wordpress 网站的不同页面上映射

iOS - 使用路线URL方案启动Yandex地图