|
*****************************************************************************************************************
*****************************************************************************************************************
1. 자주사용하는 레이어타입 정리
WMS의 장단점을 고려해 WFS를 사용할거면 요즘 벡터타일을 많이 사용하라고 권장합니다.
아래는 벡터타일 이외의 레이어 타입에 따른 문제점을 정리해봅니다. 용도에 맞는 타입선택이 중요합니다.
* 왜 벡터 타일을 사용합니까? (Why use vector tiles?) - 렌더링은 서버가 아닌 클라이언트 (예 : OpenLayers)에 의해 수행됩니다. 이를 통해 다른 맵 / 애플리케이션이 GeoServer를 재구성하지 않고도 맵의 스타일을 다르게 지정할 수 있습니다. - 벡터 타일의 크기는 일반적으로 이미지 타일보다 작 으므로 데이터 전송 속도가 빨라지고 대역폭 사용량이 줄어 듭니다. - GeoServer에 내장 된 GeoWebCache는 벡터 타일 데이터를 효율적으로 저장합니다. 스타일링은 서버가 아닌 클라이언트가 수행하므로 GeoWebCache는 모든 다른 스타일에 대해 하나의 타일 만 저장하면됩니다 . - 벡터 데이터는 클라이언트에서 사용할 수 있으므로 대역폭을 늘리지 않고도 매우 높은 해상도의 맵을 그릴 수 있습니다 . - 클라이언트는 실제 기능 정보 (속성 및 지오메트리)에 기본적으로 액세스 할 수 있으므로 매우 정교한 렌더링이 가능합니다. - 반면, 벡터 타일의 주요 단점은 클라이언트가 필요한 도면을 수행 할 수 있도록 지리 데이터를 사전 처리해야 할 수 있다는 것입니다 (이미지 맵의 전처리 데이터와 유사). 이를 염두에두고 벡터 타일은 렌더링에만 사용해야합니다 . |
//1. 타일맵(이미지) 레이어에서 사용하는 형식들 타일 레이어를 사용할경우에는 기존 만들어진 포털 타일맵을 사용하거나, 데이터 갱신이 적은 참조 데이터를 속도를 위해 미리 타일맵으로 만들어 사용할때 사용되어야합니다. - 포털 사이트들의 TMS을 사용하는 레이어로 XYZ소스를 사용한다. 또는 TMS형식으로 자체구축한 타일이미지. XYZ 형식의 URL을 가진 타일 이미지로 서비스되는 데이터를 표현한다. new ol.layer.Tile({ source: new ol.source.XYZ({ }) }); - 타일 그리드로 분할 된 이미지 데이터로 타 서버의 타일형식을 읽어올때 사용한다. 예로 슈퍼맵의 타일맵 등. new ol.layer.Tile({ source: new ol.source.TileImage({ }) }); - WMTS 서버의 타일 데이터. 예로 GeoServer에서 GeoWebCache 등을 발행할때 유용하다. new ol.layer.Tile({ source: new ol.source.WMTS({ }) }); ////////////////////////////////////////////////////////// //2. WMS 레이어에서 사용하는 형식들 대용량의 벡터객체를 WMS형식으로 서버에 요청하므로써 줌레벨에 따른 속도문제를 해소할 수 있습니다. 다만, 레이어의 스타일을 서버에 설정하거나 클라이언트에 파라메터로 수많은 코딩의 XML처리를 해야합니다. 그리고 클라이언트에서도 액티브한 공각객체 표현의 제한을 가져올 수 있습니다. 물론, 이미지만 가져오므로 객체의 공각/속성은 표현할 수는 없지만 마우스클릭이나 연산시 WFS를 사용하여 동적 처리로 액티브하게 구현할 수도 있습니다. - WMS레이어로 통상적으로 사용하는 형식입니다. 아래 타일식 WMS보다는 속도면에서 느리고 대기하는 시간은 있으며, 서로 장점이 단점이 되는 방법입니다. new ol.layer.Image({ source: new ol.source.ImageWMS({ }) }); - WMS를 타일식으로 서버에서 받으므로 체감 속도면에서 좋으나, 라벨링의 반복/중복과 타일간의 사이에 심볼/스타일의 깨짐 현상이 있습니다. 따라서 라벨링과 특히 마커 데이터 표현은 사용하지 않는게 좋습니다. new ol.layer.Tile({ source: new ol.source.TileWMS({ }) }); ////////////////////////////////////////////////////////// //3. 벡터 레이어에서 사용하는 형식들 대용량의 벡터객체는 위 WMS보다는 속도가 떨어집니다. 따라서 통상적으로 줌레벨에 따라 보여지는것을 잘 설정하여 사용해야합니다. 위 WMS단점으로 말한것처럼 공간객체의 액티브한 효과를 줄 수 있고, 스타일 등 클라이언트에서 제어가 쉽습니다. 그리고 로딩한 객체에 코드값이나 속성값 등 제어가 쉽습니다. WMS와 Vector를 절충하기 위해 벡터타일레이어와 strategy옵션으도 처리하고 있습니다. - 통상적으로 사용하는 형식으로 기본 방식 : 대용량이나 복잡한 도형을 넓은 소축척으로 보여주는것을 지양해야합니다. new ol.layer.Vector({ source: new ol.source.Vector({ }) }); - 통상적으로 사용하는 형식에 타일식으로 나누어 로딩하는 방식 : 위 기본방식의 대용량/소축척 처리를 다소 해결. new ol.layer.Vector({ source: new ol.source.Vector({ strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ tileSize: 256 })) }) }); - 벡터레이어를 타일식으로 로딩하고 그리는 방식으로 대용량이나 복잡한 도형을 넓은 소축척으로 보여줍니다. 다만, 위 기본 Vector에서 ol.loadingstrategy.tile와 비슷하나 타일식으로 먼저 디스플레이하므로 체감 속도는 좋습니다. 그러나 타일간의 사이에 심볼/스타일의 깨짐 현상이 있습니다. 따라서 라벨링과 특히 마커 데이터 표현은 사용하지 않는게 좋습니다. new ol.layer.VectorTile({ source: new ol.source.VectorTile({ }) }); ////////////////////////////////////////////////////////// //4. 기타 레이어에서 사용하는 형식들 Heatmap, AnimatedCluster 등 기본제공과 확장 등 여러레이어 형식을 만들 수도 있습니다. 오픈레이어즈의 레이어/소스 형식은 서버의 여러타입인 JSON, PDF, tiff 등 다양한 구현을 위해 제공하고 있습니다. 레이어 형식과 소스 형식을 조합하여 다양한 구현을 가능 하도록 합니다. 그중에 예로 Raster는 위 이미지 레이어의 operation로 절대좌표/픽셀의 색상값으로 다양한 처리를 할 수있게 합니다. new ol.layer.Image({ source: new ol.source.Raster({ sources: [new ol.source.XYZ({ })], operationType: 'image', operation: }) }); |
2. AnimatedCluster 응용2번째로 가로와 세로별로 거리제한을 사용하기
- 기존 1번째 AnimatedCluster팁에선 심볼선택시 방사형으로하되 중심으로 원형으로 펼치는것을 실제 위치로 펼치는
것으로 응용해보았습니다( https://cafe.naver.com/gisapplication/1000 )
- 기존 Cluster의 거리제한을 하나의 숫자로 하므로, 심볼의 가로와 세로별로 거리제한을 사용한 ClusterEx로
확장 개발하여 과도한 클러스터링을 낮출 수 있다.
- 클러스터링된 계측기들의 각 센서값을 자동으로 슬라이딩하여 순차적으로 겹친 계측기들의 정보를 시각화함
- OL의 기본적인 Cluster는 클러스터 간 최소거리(픽셀)값을 하나만 있어서, 가로/세로의 격차가 심할경우 비효율
그리고, 클러스터링된 객체간에도 심볼크기에 따라 겹치는 문제(구글링에서도 최적방안이 없다고 한다)
이미 클러스터링된 하나의 객체에 여러 계측기값 표현 아이디어 필요.
- Cluster을 응용 => ClusterEx.js
*클러스터 간 최소거리(픽셀)값을 X/Y(가로/세로)의 옵션 파라메터값을 적용. ol.source.ClusterEx.prototype.cluster = function() { if (this.resolution === undefined || !this.source) { return; } const extent = ol.extent.createEmpty(); const mapDistance = [this.distance[0] * this.resolution, this.distance[1] * this.resolution]; const features = this.source.getFeatures(); const ClusterExed = {}; for (let i = 0, ii = features.length; i < ii; i++) { const feature = features[i]; if (!(ol.util.getUid(feature) in ClusterExed)) { const geometry = this.geometryFunction(feature); if (geometry) { const coordinates = geometry.getCoordinates(); this.createOrUpdateFromCoordinate(coordinates, extent); var _DistX = mapDistance[0]; var _DistY = mapDistance[1]; extent[0] -= _DistX; extent[1] -= _DistY; extent[2] += _DistX; extent[3] += _DistY; let neighbors = this.source.getFeaturesInExtent(extent); neighbors = neighbors.filter(function (neighbor) { const uid = ol.util.getUid(neighbor); if (!(uid in ClusterExed)) { ClusterExed[uid] = true; return true; } else { return false; } }); this.features.push(this.createcluster(neighbors, extent)); } } }} *클러스터링된 객체끼리의 겹치는 문제해결로 객체들의 중심점이 아닌 클러스터한 MBR중심에 생성. ol.source.ClusterEx.prototype.createcluster = function(features, _extent) { var centroid = [ (_extent[0]+_extent[2])/2, (_extent[1]+_extent[3])/2]; const ClusterEx = new ol.Feature(new ol.geom.Point(centroid)); ClusterEx.set('features', features); return ClusterEx; } |
3. 줌인후 이동시 타일맵 깨짐화면(잔상) 제거하기
참조 소스 : https://cafe.naver.com/gisapplication/1056
- OpenLayers로 구현하다보면 지도를 줌인(Zoom In)한후 화면을 이동하면,
새로운 영역에 기존 줌의 타일 이미지가 캐시되어 보여주고 있다.
- 사용자에 따라 깨진화면처럼 성가시게 느끼는 분들이 많다.
- 그래서 이러한 캐시된 이미지를 제거해보았습니다. 너무 제거하면 빈 백지타일이 많아지므로 적절하게 삭제함.
- 순수 타일 이미지 TMS뿐만아니라 박터타일(VectorTile)도 마찬가지로 tileCache를 삭제합니다.
* map의 줌변환시 이벤트에 브이월드 등 타일레이어의 캐시를 삭제하도록 함수를 호출합니다. 지도를 확대할 경우(이전 줌레벨 보다 클때) 호출한다. 지도 줌이 변환한후 2초후 실행한다.(이것은 부드럽고, 인터넷 속도 등 너무 심하게하지 않게 조절) map.getView().on('change:resolution', function(evt){ var _level = Math.floor(map.getView().getZoom()); if(Vwordmap_layer.getVisible() && org_Maplevel < _level){ if(ClearTileCacheTimer)clearTimeout(ClearTileCacheTimer); ClearTileCacheTimer = setTimeout(function(){ ClearTileCache(); }, 2000); } org_Maplevel = _level; }); |
* 브이월드 등 타일레이어의 소스에는 "tileCache"메소드에 타일이미지가 쌓여 속도와 깜빡임을 줄여줍니다. 그런데 줌인후 이동시 깨진것처럼 눈에 성가십니다. "entries_"오브젝트에 쌓인것중 현재의 줌레벨과 다른 놈들은 삭제해버립니다. 위의것이랑 연결되어, 현재 캐시를 줌아웃할때는 그대로 남기고, 이동시 현 레벨을 남겨 부드럽고 속도를 내며, 단지 줌인시만 서서히 2초후 백그라운드에서 지우는 기능입니다. var org_Maplevel = -1; var ClearTileCacheTimer; function ClearTileCache(){ try{ var _level = Math.floor(map.getView().getZoom()); var str_level = _level.toString(); var _tileCache = Vwordmap_layer.getSource().tileCache; for (var _key in _tileCache.entries_){ if(!(_key.substr(0, str_level.length) == str_level)){ delete _tileCache.entries_[_key]; } } }catch (e){ } |
비교화면
4. 마스크 필터 사용시 폴리곤 객체아래 객체들 이벤트 부여 하기
- OL에선 마스크 레이어라기 보다는 마스크 필터식으로 사용한다고 생각합니다.
마스크레이어에는 기존 벡터레이어라서 마스크할 폴리곤 객체가 보이지 않게하여도 존재하므로,
그 아래의 다른 벡터레이어의 마우스 이벤트에 영향을 줍니다.
- 마스크필터에도 마스크할 폴리곤을 파라메터로 넣는데 소스를 보니 캔퍼스에 실재 그리는 용도로 사용합니다
(OL은 무조건 캔퍼스에 그리는걸 잘하면된다. 이건 옛날 도스나 초창기 개발도 아니고 Html짜증...)
- 그러면 마스크레이어엔 실제 폴리곤 객체를 넣을 필요가 없다. 따라서 일단 폴리라인으로 바꿔서 넣으면
마스크는 잘 표시되고, 폴리곤 하위 객체 들 마우스오버나 선택 등 이벤트에 영향이 없었다.
원본 var new_source = new ol.source.Vector(); new_source.addFeatures(_features); maskLayer_bottom.setSource(new_source); map.getView().fit(new_source.getExtent() , map.getSize()); maskLayer_removeFilter(maskLayer_bottom); var maskLayer_mask = new ol.filter.Mask({ 'feature': New_feature, inner:false, fill: new ol.style.Fill({ color:[255,255,255,0.7] }) }); maskLayer_bottom.addFilter(maskLayer_mask); |
수정 var new_source = new ol.source.Vector(); //new_source.addFeatures(_features); var _Style = new ol.style.Style({ stroke: new ol.style.Stroke({ color: "rgba(0,0,0,0)", width: 0 }) }); for(var i=0; i< _features.length; i++) { var _feature = _features[i]; var _geometry = _feature.getGeometry(); var _Coordinates = _geometry.getCoordinates(); var New_geometry; if(_geometry.getType() == 'MultiPolygon'){ var _LinearRingS = []; for(var j=0; j< _Coordinates.length; j++) for(var k=0; k< _Coordinates[j].length; k++) _LinearRingS.push(new ol.geom.LineString(_Coordinates[j][k])); New_geometry = new ol.geom.MultiLineString(_LinearRingS); }else{ New_geometry = new ol.geom.LineString(_Coordinates[0]); } _feature.setGeometry(New_geometry); _feature.setStyle(_Style); new_source.addFeature(_feature); } // maskLayer_bottom.setSource(new_source); map.getView().fit(new_source.getExtent() , map.getSize()); maskLayer_removeFilter(maskLayer_bottom); var maskLayer_mask = new ol.filter.Mask({ 'feature': New_feature, inner:false, fill: new ol.style.Fill({ color:[255,255,255,0.7] }) }); maskLayer_bottom.addFilter(maskLayer_mask); |
5. 레이어 갱신
(1) layer.getSource().updateParams({"time": Date.now()});
지난 게시글에서 "[OpenLayers] 객체편집기능v2.0" 객체편집후 WMS/WFS 등 다시 서버로 부터 새로운 쿼리로
레이어를 갱신할때 사용합니다.
(2) layer.getSource().dispatchEvent('change');
체인지 이벤트를 발생시킨 후 심볼펑션만 받아 스타일만 바꿀때 용이합니다.
|