지난 게시물에서 함수 컴포넌트를 이용해 맵을 표출했다.
이제 표출된 맵에 원하는 객체를 그려보자. (점, 선, 다각형, 원)
객체를 그리고 수정할 때 필요한 모듈(Draw, Snap, Modify)과 객체의 스타일을 지정할 모듈(Style, Circle, Fill, Stroke)을 import한다.
// MapTest.jsx
import React, { useEffect, useRef } from "react";
import { Map as OlMap, View } from "ol";
import { defaults as defaultControls } from "ol/control";
import { fromLonLat, get as getProjection } from "ol/proj";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
// +++
import { Style, Circle as CircleStyle, Fill, Stroke } from "ol/style";
import { Draw, Snap, Modify } from "ol/interaction";
// +++
import "ol/ol.css";
객체의 타입을 선택할 select를 추가하고 객체를 그리는 함수 등을 추가했다.
// 객체가 그려질 레이어(점, 선, 도형)
// +++ 기존에 컴포넌트 안에 선언했던 initVectorLayer을 밖으로 꺼냄
const initVectorLayer = new VectorLayer({
source: new VectorSource(),
style: new Style({
fill: new Fill({
color: "rgba(0, 0, 0, 0.2)",
}),
stroke: new Stroke({
color: "red",
width: 2,
}),
image: new CircleStyle({
radius: 7,
fill: new Fill({
color: "red",
}),
}),
}),
});
// +++
export default function MapTest() {
// +++
const [gisMap, setGisMap] = useState({});
const [featuresLayer, setFeaturesLayer] = useState(null);
// interaction을 해제하기 위해
const [drawSnapObj, setDrawSnapObj] = useState<any>({});
// +++
const mapContent = useRef(null);
// +++
const typeSelect = useRef(null);
// select 값이 바뀌면 interaction 해제 뒤 addDrawSnap 호출.
const onChangeHandler = () => {
gisMap.removeInteraction(drawSnapObj.draw);
gisMap.removeInteraction(drawSnapObj.snap);
addDrawSnap();
};
// 객체 그리기 함수
const addDrawSnap = () => {
// select 값이 None일 때는 리턴
if (typeSelect.current.value === "None") {
return false;
}
const draw = new Draw({
source: featuresLayer.getSource(),
type: typeSelect.current.value,
});
gisMap.addInteraction(draw);
const snap = new Snap({ source: featuresLayer.getSource() });
gisMap.addInteraction(snap);
// interaction을 해제하기 위해 담아 놓기.
setDrawSnapObj({ draw, snap });
};
// +++
useEffect(() => {
if (!mapContent.current) {
return;
}
const map = new OlMap({
controls: defaultControls({ zoom: false, rotate: false }).extend([]),
layers: [
new TileLayer({
source: new XYZ({ url: "http://xdworld.vworld.kr:8080/2d/Base/202002/{z}/{x}/{y}.png" }),
}),
initVectorLayer,
],
view: new View({
projection: getProjection("EPSG:3857"),
center: fromLonLat([127.296364, 37.503429]),
zoom: 15,
minZoom: 7,
maxZoom: 20,
}),
target: mapContent.current,
});
// +++ map과 initVectorLayer를 set한다. 추후 다른 함수에 이용. (추가, 수정 등)
setGisMap(map);
setFeaturesLayer(initVectorLayer);
// +++
return () => map.setTarget(undefined);
}, []);
// +++ gisMap이 있으면 addDrawSnap 호출.
useEffect(() => {
// gisMap에 map 존재 여부를 객체의 키의 길이로 판단.
if (Object.keys(gisMap).length > 0) {
addDrawSnap();
// 그려진 객체 수정.
const modify = new Modify({ source: initVectorLayer.getSource() });
gisMap.addInteraction(modify);
}
return () => {};
}, [addDrawSnap, gisMap, featuresLayer]);
// +++
return (
<div className="gis-map-wrap">
{/* +++ 객체 타입 선택 */}
<select ref={typeSelect} defaultValue="None" onChange={() => onChangeHandler(e)}>
<option value="None">선택</option>
<option value="Point">점</option>
<option value="LineString">선</option>
<option value="Polygon">다각형</option>
<option value="Circle">원형</option>
</select>
{/* +++ */}
<div ref={mapContent}></div>
</div>
);
}
쨔쟌 타입을 지정해 객체를 그리고 수정도 가능하다.
그려진 객체를 GeoJSON 형태로 변환하자.