OpenLayers 3

지도 표출 예제

OpenLayers에서는 벡터 타일 레이어에 대해 별도의 스타일 지원을 제공하지 않습니다. 대신, 각 레이어의 피처 속성(properties)을 통해 직접 필터링하고 스타일을 적용해야 합니다. 이 가이드에서는 벡터 타일 레이어를 설정하고, 피처 속성을 사용하여 스타일을 다르게 적용하는 방법을 설명합니다. 레이어 및 레이어 별 properties 문서는 추후 별도로 첨부될 예정입니다.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>OpenLayers 예제</title>
  <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.5.0/css/ol.css">
  <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.5.0/build/ol.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>

<body>
  <div id="map" class="map"></div>
  <script>
    // 기본 지도 설정
    const map = new ol.Map({
      target: 'map',
      view: new ol.View({
        center: ol.proj.fromLonLat([126.82861822721662, 37.20462651463613]),
        zoom: 14
      })
    });

    // 배경색 설정
    document.getElementById('map').style.backgroundColor = 'hsl(0, 0%, 10%)';

    // 줌 레벨에 따른 선 너비 계산 함수
    function getLineWidth(stops, zoom) {
      for (let i = 0; i < stops.length - 1; i++) {
        if (zoom >= stops[i][0] && zoom < stops[i + 1][0]) {
          const z1 = stops[i][0], w1 = stops[i][1];
          const z2 = stops[i + 1][0], w2 = stops[i + 1][1];
          const ratio = (zoom - z1) / (z2 - z1);
          return w1 + (w2 - w1) * ratio;
        }
      }
      if (zoom >= stops[stops.length - 1][0]) {
        return stops[stops.length - 1][1];
      }
      return stops[0][1];
    }


    // HD Map 소스
    const hdmapSource = new ol.source.VectorTile({
      format: new ol.format.MVT(),
      url: 'https://dashboard.mqnicrnd5.com/tiles/data/hdmap/{z}/{x}/{y}.pbf'
    });

    // HD Map 레이어 - Mapbox 스타일 순서대로 구현
    const hdmapLayer = new ol.layer.VectorTile({
      source: hdmapSource,
      renderMode: 'vector',
      style: function (feature, resolution) {
        const layer = feature.get('layer');
        const zoom = map.getView().getZoom();
        const styles = [];

        // 1. road_belt_element_link (roadbeltelementlink)
        if (layer === 'roadbeltelementlink' && zoom >= 14) {
          const stops = [[14, 5], [15, 10], [16, 15], [17, 20], [18, 40], [19, 70], [20, 140], [21, 360], [22, 620]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#283042',
              width: getLineWidth(stops, zoom),
              lineCap: 'round'
            }),
            zIndex: 1
          }));
        }

        // 2. lanebeltelementlink_base (베이스)
        if (layer === 'lanebeltelementlink' && zoom >= 14) {
          const stops = [[14, 3], [15, 6], [16, 10], [17, 14], [18, 28], [19, 50], [20, 100], [21, 250], [22, 430]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#283042',
              width: getLineWidth(stops, zoom),
              lineCap: 'round'
            }),
            zIndex: 2
          }));
        }

        // 3. lanebeltsideline_base
        if (layer === 'lanebeltsideline' && zoom >= 14) {
          const stops = [[14, 3], [15, 6], [16, 10], [17, 14], [18, 28], [19, 50], [20, 100], [21, 250], [22, 430]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#283042',
              width: getLineWidth(stops, zoom),
              lineCap: 'round'
            }),
            zIndex: 3
          }));
        }

        // 4. roadcentremarking_base
        if (layer === 'roadcentremarking' && zoom >= 14) {
          const stops = [[14, 3], [15, 6], [16, 10], [17, 14], [18, 28], [19, 50], [20, 100], [21, 250], [22, 430]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#283042',
              width: getLineWidth(stops, zoom),
              lineCap: 'round'
            }),
            zIndex: 4
          }));
        }

        // 5. lane_belt_element_link (상위 레이어)
        if (layer === 'lanebeltelementlink') {
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#4863a3',
              width: 1.5
            }),
            zIndex: 5
          }));
        }

        // 6. road_belt_terminal_line
        if (layer === 'roadbeltterminalline' && zoom >= 16) {
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#777',
              width: 1.5
            }),
            zIndex: 6
          }));
        }

        // 7. lane_belt_terminal_line
        if (layer === 'lanebeltterminalline' && zoom >= 16) {
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: 'rgba(106, 141, 193, 0.7)',
              width: 0.5
            }),
            zIndex: 7
          }));
        }

        // 8. bridge
        if (layer === 'bridge' && zoom >= 15) {
          styles.push(new ol.style.Style({
            fill: new ol.style.Fill({
              color: 'rgba(155, 131, 101, 0.35)'
            }),
            zIndex: 8
          }));
        }

        // 9. tunnel
        if (layer === 'tunnel' && zoom >= 15) {
          styles.push(new ol.style.Style({
            fill: new ol.style.Fill({
              color: 'rgba(69, 69, 85, 0.4)'
            }),
            zIndex: 9
          }));
        }

        // 10. wall
        if (layer === 'wall' && zoom >= 16) {
          const stops = [[16, 1.5], [18, 2], [20, 3]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#5a6a7f',
              width: getLineWidth(stops, zoom)
            }),
            zIndex: 10
          }));
        }

        // 11. fence
        if (layer === 'fence' && zoom >= 17) {
          const stops = [[17, 0.8], [18, 1], [20, 1.5]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#9b9b9b',
              width: getLineWidth(stops, zoom)
            }),
            zIndex: 11
          }));
        }

        // 12. traffic_island_marking
        if (layer === 'trafficislandmarking' && zoom >= 16) {
          const stops = [[16, 1.5], [18, 2], [20, 3]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#ffd54f',
              width: getLineWidth(stops, zoom)
            }),
            zIndex: 12
          }));
        }

        // 13. kerb
        if (layer === 'kerb' && zoom >= 17) {
          const stops = [[17, 1.2], [18, 1.8], [20, 2.5]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#6a7a8f',
              width: getLineWidth(stops, zoom)
            }),
            zIndex: 13
          }));
        }

        // 14. guardrail
        if (layer === 'guardrail' && zoom >= 16) {
          const stops = [[16, 1.5], [18, 2], [20, 2.5]];
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: '#8b9baf',
              width: getLineWidth(stops, zoom)
            }),
            zIndex: 14
          }));
        }

        // 15. road_centre_marking (상위 레이어)
        if (layer === 'roadcentremarking') {
          const linecolour = feature.get('linecolour');
          const colorMap = {
            2: '#444e68',
            3: '#3b39a8',
            4: '#216317',
            5: '#5a5444',
            6: '#631a10',
            7: '#000000'
          };
          styles.push(new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: colorMap[linecolour] || '#444e68',
              width: 2
            }),
            zIndex: 15
          }));
        }

        // 16. lane_edge_marking_dot (점선)
        if (layer === 'laneedgemarking') {
          const linestyle = feature.get('linestyle');
          const linecolour = feature.get('linecolour');
          const colorMap = {
            2: '#444e68',
            3: '#4863a3',
            4: '#216317',
            5: '#5a5444',
            6: '#631a10',
            7: '#000000'
          };

          if (linestyle === 'brokenLine') {
            styles.push(new ol.style.Style({
              stroke: new ol.style.Stroke({
                color: colorMap[linecolour] || '#444e68',
                width: 2,
                lineDash: [6, 5]
              }),
              zIndex: 16
            }));
          }
          // 17. lane_edge_marking_solid (실선)
          else if (linestyle === 1) {
            styles.push(new ol.style.Style({
              stroke: new ol.style.Stroke({
                color: colorMap[linecolour] || '#444e68',
                width: 2
              }),
              zIndex: 17
            }));
          }
        }

        return styles.length > 0 ? styles : null;
      }
    });

    // 레이어 추가
    map.addLayer(hdmapLayer);

  </script>
</body>

</html>

Last updated