이번 포스트에서는 내가 원하는 아이콘을 지도 위에 출력 하는 방법에 대해 정리 해 보고자 한다.
최종 결과물은 아래와 같을 것이다.
png파일을 이용한 marker와 단순한 동그라미 marker를 지도에 출력 해볼 것이다.
만약 그 이전 단계에 대해 모른다면, 지난 포스트들을 참고하자.
지난 포스트에서는 1) OSM 지도를 출력하는 방법, 2) 클릭 이벤트를 등록하는 방법에 대해 정리했었다.
목차는 아래와 같다.
StepbyStep
1. Feature 생성.(Point, LineString, CustomFeature)
2. VectorSource를 생성하여 Feature를 주입.
3. VectorLayer를 만들고, VectorSource를 주입해준다.
4. VectorLayer를 Map 객체에 주입해 준다.
전체 코드
Step by Step
Openlayers에서 Icon 혹은 Marker를 추가하고 싶다면, VectorLayer에 올려 주어야 한다. (공식문서 참고링크)
VectorLayer 타입은 애니메이션 도중에도 가장 정확하게 vector들을 렌더해주는 역할을 해준다.
마커를 만들고, vectorlayer에 올리는 과정은 크게 아래와 같다.
- Feature를 만든다.(Point, LineString, CustomFeature)
- VectorSource를 생성하여 Feature를 주입한다.
- VectorLayer를 만들고, VectorSource를 주입해준다.
- VectorLayer를 Map 객체에 주입해 준다.
1-1. Feature 만들기(Point, LineString, CustomFeature)
앞서 설명 한 것 처럼 가장 먼저 Feature를 만들어 줘야 한다.
참고로 Feature는, 위치정보와 기타 다른 속성들을 가지고 있는 벡터 객체로, GeoJSON과 비슷하다고 할 수 있다.(참고 링크)
쉽게 말하면 내가 지도 위에 올릴 아이콘의 위치 정보, 기타 속성들을 관리하는 객체이다.
만드는 방법은 간단하다. geometry에 위치 정보를 가진 Geometry 타입의 값을 넣어주고, 자신이 원하는 속성을 넣어주면 된다.아래 코드는 Point를 이용하여, geometry 값을 넣어주고, custom 속성으로 type을 넣어 Feature를 생성하는 모습이다.
import Feature from 'ol/Feature.js'
import { Point } from 'ol/geom'
const pointFeature = new Feature({
geometry: new Point(fromLonLat([126.92514158525616,37.53048719896351])),
type: "Point"
})
const carFeature = new Feature({
geometry: new Point(fromLonLat([126.92442914605324,37.53005737995464])),
type: "Car"
})
1-2. Feature에 스타일 적용
위의 Feature들은 위치 정보와, custom property를 가지고 있지만, 어떤 모습으로 지도 위에서 보여 질지에 대한 데이터는 전혀 가지고 있지 않다. 이럴 때 사용되는 것이 바로, Style이다.
Openlayers는 스타일을 적용하기 위해 Style 객체를 사용하도록 하고 있다. (공식 문서)
사용법은 다양하지만, 나는 아래와 같이 하나의 객체로 스타일을 관리하고, vectorLayer단에서 한 번에 적용하는 방식을 추천한다.
참고로, png같은 이미지 파일도 아래에서 PoliceCar를 넣어준 방식처럼 넣어 줄 수 있다.
import PoliceCar from '@/assets/policecar.png'
// 스타일 객체
const styles = {
Point: new Style({
image: new CircleStyle({
radius: 10,
fill: new Fill({ color: [160, 51, 255, 1] }),
stroke: new Stroke({
color: [160, 51, 255, 1],
width: 0.1,
}),
}),
}),
Car: new Style({
image: new Icon({
src: PoliceCar,
offset: [0, 0],
scale: 0.08,
rotation: 3.121592653589793 + +2.523936814256307,
}),
}),
}
// 스타일 적용
const vectorLayer = new VectorLayer({
source: vectorSource,
style: (feature) => styles[feature.getProperties().type]
})
2. VectorSource를 생성하여 Feature를 주입한다.
우리가 생성한 Feature를 아래 방식처럼 VectorSource에 넣어주자.
여기에서 주의 할 점은 반드시 features에는 배열 형식으로 인자를 전달 해 줘야 한다는 것이다.
import VectorSource from 'ol/source/Vector.js';
const vectorSource = new VectorSource({
features: [ pointFeature, carFeature ],
});
3. VectorLayer를 만들고, VectorSource를 주입해준다.
만든 vectorSource 객체를 VectorLayer 에 주입해준다.
이때, style에 콜백함수를 전달 함으로써 한번에 스타일을 적용 할 수 있다.
import {Vector as VectorLayer} from 'ol/layer.js';
const vectorLayer = new VectorLayer({
source: vectorSource,
style: (feature) => styles[feature.getProperties().type]
})
4. VectorLayer를 Map 객체에 주입해 준다.
마지막으로, VectorLayer를 지도 객체에 넣어주자.
참고로 onMounted는 Vue3에서 사용되는 lifeCycle 훅 함수이므로, Vue를 사용하지 않는다면 넘어가도 좋다.
주의 할 점은 layers 역시 features와 마찬가지로 배열 형태로 인자들을 넘겨줘야 한다는 것이다.
onMounted(() => {
olMap = new OlMap({
target: map.value,
controls: defaults({
attribution: false,
zoom: false,
rotate: false,
}),
layers: [new OlLayerTile({ source: new OSM() }), vectorLayer],
view: new OlView({
center: center,
zoom: 17,
}),
})
})
전체 코드
위의 내용을 적용한 전체 코드는 아래와 같을 것이다.
단, HTML과 CSS는 이전 포스팅과 동일 하므로 생략하였다.
//...
<script>
import { fromLonLat } from 'ol/proj.js'
import OlView from 'ol/View.js'
import OlMap from 'ol/Map.js'
import OSM from 'ol/source/OSM'
import OlLayerTile from 'ol/layer/Tile.js'
import { defaults } from 'ol/control.js'
import {Vector as VectorLayer} from 'ol/layer.js';
import VectorSource from 'ol/source/Vector.js';
import Feature from 'ol/Feature.js'
import { Point } from 'ol/geom'
import {
Fill,
Icon,
Stroke,
Style,
Circle as CircleStyle,
} from 'ol/style.js'
import PoliceCar from '@/assets/policecar.png'
import { ref, onMounted } from 'vue'
export default {
name: 'DemoPage',
setup() {
const map = ref(null);
let olMap;
const center = fromLonLat([126.9251405697578, 37.53033241217628])
//1. Feature를 만든다.(Point, LineString, CustomFeature 등 다양한 Feature를 생성 할 수 있다.)
//1-1. PointFeature
const pointFeature = new Feature({geometry: new Point(fromLonLat([126.92514158525616,37.53048719896351])), type: "Point"})
//1-2. png파일을 이용해 만들 CustomFeature
const carFeature = new Feature({geometry: new Point(fromLonLat([126.92442914605324,37.53005737995464])), type: "Car"})
//2. VectorSource를 생성하여 Feature를 주입한다.
const vectorSource = new VectorSource({
features: [ pointFeature, carFeature ],
});
//1-3. 모든 Feature들의 스타일을 모아놓은 객체를 이용해
//VectorLayer에서 한번에 Style 적용이 가능하다.
const styles = {
Point: new Style({
image: new CircleStyle({
radius: 10,
fill: new Fill({ color: [160, 51, 255, 1] }),
stroke: new Stroke({
color: [160, 51, 255, 1],
width: 0.1,
}),
}),
}),
Car: new Style({
image: new Icon({
src: PoliceCar,
offset: [0, 0],
scale: 0.08,
rotation: 3.121592653589793 + +2.523936814256307,
}),
}),
}
//3. VectorLayer를 만들고, VectorSource를 주입해준다.
const vectorLayer = new VectorLayer({
source: vectorSource,
//1-4. style에 콜백 함수를 전달 함으로써 한 번에 Style 적용이 가능하다.
style: (feature) => {
return styles[feature.getProperties().type]
},
})
onMounted(() => {
olMap = new OlMap({
target: map.value,
controls: defaults({
attribution: false,
zoom: false,
rotate: false,
}),
//4. VectorLayer를 Map 객체에 주입해 준다.
layers: [new OlLayerTile({ source: new OSM() }), vectorLayer],
view: new OlView({
center: center,
zoom: 17,
}),
})
})
return { map, olMap, vectorLayer, vectorSource }
},
}
</script>
//...
'Openlayers' 카테고리의 다른 글
[Openlayers] 2 - 지도 클릭 이벤트로 좌표 출력 (1) | 2023.05.15 |
---|---|
[ Openlayers ] 1 - OSM 지도 그리기 (0) | 2023.05.15 |
[ Openlayers ] ESPG:4326 vs ESPG:3857 뭘 써야 할까? (0) | 2023.05.12 |