PerfectVector
Bởi Irene Kim

Biểu tượng SVG MapLibre: pixel và kích thước ký hiệu

Giải mã hình SVG tùy chỉnh cho lớp ký hiệu MapLibre, kiểm soát mật độ ảnh và kích thước biểu tượng, đồng thời giữ bản chính chỉnh sửa được. Xác minh hình và khoảng trống hiển thị.

11 phút đọc
Trên trang này

Để dùng ảnh biểu tượng SVG trong MapLibre GL JS, giải mã SVG bằng Image của trình duyệt, truyền ảnh đó cho addImage và tham chiếu ID của nó trong icon-image của lớp ký hiệu. Giữ SVG nguồn riêng: ảnh kiểu đã đăng ký cung cấp pixel để kết xuất thay vì các đối tượng đường dẫn SVG có thể chỉnh sửa.

Ví dụ ký hiệu SVG chính thức hiện tại minh họa cách giải mã này. Một khẳng định chung rằng MapLibre không thể hiển thị hình SVG sẽ bỏ sót cách đó. Ví dụ của chúng tôi cố định 6.12.0 và thử biểu trưng rỗng gốc trong bản đồ trống không cần token.

Giữ nguồn và ảnh đã đăng ký riêng biệt

Nguồn được giữ lại chứa một đường dẫn hình thoi phức hợp với khoảng trống bên trong. viewBox giữ ở 0 0 64 64. Chúng tôi tạo hai bản sao có chiều rộng và chiều cao tường minh là 64 hoặc 128; dữ liệu đường dẫn giữ giống hệt.

Giải mã bằng trình duyệt biến mỗi bản sao thành ảnh ở kích thước được khai báo. API addImage của MapLibre nhận các đối tượng ảnh như HTMLImageElement và ImageData. Nó không nhận đường dẫn SVG làm chỉ dẫn hình học ký hiệu.

Sự phân biệt này quan trọng khi đổi màu hay đường bao. Chỉnh sửa bản chính SVG, giải mã ảnh đã sửa và cập nhật ảnh của bản đồ qua API phù hợp. Kiểm tra các pixel đã đăng ký không khôi phục cấu trúc đường dẫn gốc. Hướng dẫn SVG có raster nhúng giải thích khác biệt rộng hơn giữa vùng chứa SVG và hình học có thể chỉnh sửa.

Hình nguồn và màu tô ký hiệu
Minh họa khái niệm biểu trưng hình thoi rỗng dưới dạng đường bao có thể chỉnh sửa và các bản sao hiển thị dựa trên pixel
Minh họa: giữ SVG có thể chỉnh sửa trong khi kiểm soát kích thước hiển thị của ảnh đã giải mã. Các phép đo WebGL bên dưới đến từ những mẫu trình duyệt được tạo riêng.

Chọn mật độ ảnh và kích thước biểu tượng cùng nhau

Hai thiết lập ảnh hưởng đến khung ảnh danh nghĩa của ký hiệu. pixelRatio của ảnh mô tả mật độ; icon-size của lớp co giãn biểu tượng kết quả. Xem siêu dữ liệu ảnh kiểu và đặc tả bố cục ký hiệu hiện tại.

Với ký hiệu căn giữa, không xoay và không co vừa theo văn bản của chúng tôi, khung danh nghĩa là:

logical width = decoded width / image pixelRatio * icon-size
logical height = decoded height / image pixelRatio * icon-size

Ảnh 128×128 được đăng ký ở tỷ lệ 2 cho cùng khung danh nghĩa 64×64 như ảnh 64×64 ở tỷ lệ 1 khi icon-size bằng 1. Đổi tỷ lệ đầu tiên thành 1 sẽ tăng gấp đôi khung. Tăng icon-size lên 1,5 biến khung ảnh logic 64×64 thành 96×96.

Khung này chứa cả khoảng trắng nguồn. Nếu biểu trưng bên trong trông quá nhỏ, kiểm tra phạm vi SVG trước khi tăng kích thước mọi ký hiệu. Ảnh giải mã lớn hơn với cùng tỷ lệ cũng làm ký hiệu lớn hơn; chỉ kích thước đầu vào không phải chiến lược mật độ.

Vùng vẽ bản đồ có tỷ lệ pixel riêng. Nó khác với tỷ lệ truyền cho addImage. Mẫu đo của chúng tôi đặt tỷ lệ vùng vẽ tường minh thành 1 bằng các tùy chọn Map được tài liệu mô tả; tỷ lệ pixel thiết bị của trình duyệt là 2. Điều này cô lập các phép so sánh sau thay vì xem pixel thiết bị của ảnh chụp là kích thước CSS.

So sánh phạm vi thực sự được tô

Chúng tôi kết xuất năm trường hợp ký hiệu trong Chrome với WebGL 2. Mỗi bản đồ có một điểm, cùng nền sáng, không có ô bản đồ và không có token. Cả hai nguồn SVG có một đường dẫn giống hệt và không có ảnh nhúng.

Để đo hình màu đất nung, phép đọc của chúng tôi quét các pixel WebGL thực tìm màu trội đỏ: đỏ lớn hơn 1,35 lần xanh lá và 1,6 lần xanh lam. Chúng tôi chia kích thước hộp bao được phát hiện cho tỷ lệ bộ đệm nền so với CSS của vùng vẽ. Phép đo này đo vùng tô theo ngưỡng, không phải toàn bộ khung ảnh.

Ảnh đã giải mãTỷ lệ ảnhicon-sizeKhung danh nghĩaPhạm vi tô quan sát được
64×641164×6462×62 px CSS
128×12811128×128126×126 px CSS
128×1282164×6462×62 px CSS
64×6411.596×9694×94 px CSS
128×12821.596×9694×94 px CSS

Không phải mọi pixel cạnh đều vượt ngưỡng màu đó, nên phạm vi tô đo được nhỏ hơn khung danh nghĩa. Các cặp cho thấy quan hệ kích thước dự kiến trong mẫu này; chúng không chứng minh chất lượng pixel giống hệt ở mọi mật độ hay mức phóng đại.

Alpha ở giữa ảnh đã đăng ký bằng 0 trong mọi trường hợp. Trong bản đồ đã kết xuất, vị trí đó hiển thị màu nền (244, 242, 232) với alpha 255 vì bản thân lớp nền đục. Thấy các pixel bản đồ đục qua khoảng trống không có nghĩa biểu tượng mất độ trong suốt.

Đây là các quan sát có giới hạn về nguồn, trình duyệt, thiết lập vùng vẽ và ngưỡng của chúng tôi. Kiểm thử hình bàn giao ở kích thước hiển thị dự kiến, đặc biệt khi có nét mảnh hoặc khoảng trống nhỏ.

Sao chép mã khởi đầu ký hiệu không cần token

Lưu HTML hoàn chỉnh này và phục vụ từ máy chủ web cục bộ. Cần internet cho thư viện cố định phiên bản và CSS; bản đồ không dùng dịch vụ ô bản đồ hay khóa API. SVG được nhúng dưới dạng văn bản và mã hóa thành data URL.

Ví dụ chờ image.decode(), nên việc đăng ký diễn ra sau khi giải mã thành công. Nó đăng ký ảnh đã biết sau khi kiểu được tải; không cần bộ xử lý ảnh thiếu của ví dụ chính thức cho một biểu trưng cố định này.

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>MapLibre decoded SVG symbol</title>
<link rel="stylesheet"
      href="https://unpkg.com/maplibre-gl@6.12.0/dist/maplibre-gl.css">
<style>#map { width: 360px; height: 280px; }</style>
<div id="map"></div>
<pre id="status">Loading…</pre>
<script type="module">
import * as ml from
  'https://unpkg.com/maplibre-gl@6.12.0/dist/maplibre-gl.mjs';
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 64 64"><path fill="#c45b39" fill-rule="evenodd" d="M32 0 L64 32 L32 64 L0 32 Z M32 16 L16 32 L32 48 L48 32 Z"/></svg>`;
const image = new Image();
image.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
try {
  await image.decode();
  const ratio = 2;
  const iconSize = 1;
  const map = new ml.Map({
    container: 'map', center: [0, 0], zoom: 2, interactive: false,
    attributionControl: false, fadeDuration: 0,
    style: { version: 8, sources: {}, layers: [{
      id: 'background', type: 'background',
      paint: { 'background-color': '#f4f2e8' }
    }] }
  });
  map.on('error', e => {
    document.querySelector('#status').textContent = e.error.message;
  });
  await map.once('load');
  map.addImage('emblem', image, { pixelRatio: ratio });
  map.addSource('point', { type: 'geojson', data: {
    type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] },
    properties: {}
  } });
  map.addLayer({ id: 'emblem', type: 'symbol', source: 'point', layout: {
    'icon-image': 'emblem', 'icon-size': iconSize, 'icon-overlap': 'always'
  } });
  await map.once('idle');
  const registered = map.getImage('emblem');
  document.querySelector('#status').textContent = JSON.stringify({
    version: ml.getVersion(),
    decoded: [image.naturalWidth, image.naturalHeight],
    registered: [registered.data.width, registered.data.height],
    imagePixelRatio: registered.pixelRatio,
    logicalFrame: [image.naturalWidth / ratio * iconSize,
                   image.naturalHeight / ratio * iconSize]
  }, null, 2);
} catch (error) {
  document.querySelector('#status').textContent = String(error);
}
</script>
</html>

Trạng thái phải hiện kích thước đã giải mã và đăng ký là [128, 128], tỷ lệ ảnh 2 và khung logic [64, 64]. Trạng thái này báo khung danh nghĩa, không phải hộp bao tô được đo. Đổi iconSize thành 1,5 để có khung 96×96. Để so sánh đầu vào mật độ thấp, đổi chiều rộng và chiều cao SVG thành 64 và ratio thành 1 trong khi giữ cùng đường dẫn và viewBox.

Giữ icon-image bằng ID đã đăng ký. Nếu biểu tượng không xuất hiện, xác nhận giải mã và đăng ký thành công, rồi kiểm tra nguồn, lớp, khả năng hiển thị và thiết lập vị trí. Ví dụ một điểm dùng icon-overlap: 'always' để phép so sánh độc lập với va chạm ký hiệu khác. Kiểu dùng thực tế có thể cần hành vi va chạm khác.

Dùng marker DOM khi đó là mô hình bàn giao

MapLibre cũng mô tả biểu tượng tùy chỉnh với DOM Markers. Cách đó bao một phần tử HTML thay vì đăng ký ảnh kiểu. Chọn nó khi quy trình marker dựa trên phần tử phù hợp ứng dụng, rồi kiểm tra kiểu trình duyệt và vị trí riêng.

Đừng chuyển các khẳng định từ tính năng biểu tượng vector của Mapbox Studio hay ví dụ MapTiler SDK sang chuỗi ảnh kiểu MapLibre này. Ảnh SVG đủ màu thông thường cũng không trở thành trường khoảng cách có dấu chỉ bằng cách đổi cờ sdf. Thiết lập mật độ kiểm soát cách ảnh được diễn giải và hiển thị; chúng không biến pixel thành đường bao có thể chỉnh sửa.

Nếu đích cần tệp PNG, hướng dẫn kết xuất SVG bằng Sharp trình bày cách chuẩn bị bản sao raster để bàn giao. Giữ bản chính SVG thông thường để sửa; SVG nội tuyến và bàn giao qua ảnh cũng có các mô hình tương tác khác nhau.

Nếu biểu tượng chỉ tồn tại dưới dạng PNG hoặc JPG và bạn cần hình có thể chỉnh sửa, hãy khôi phục đường bao SVG bằng PerfectVector, kiểm tra hình ngoài và khoảng trống, rồi giữ bản chính trước khi giải mã ảnh bản đồ. Mã bản đồ vẫn kiểm soát mật độ, kích thước ký hiệu và vị trí địa lý. SVG sạch có sẵn có thể đi thẳng qua quy trình giải mã; hướng dẫn vector hóa giải thích khi nào chuyển raster hữu ích.

Câu hỏi thường gặp

MapLibre GL JS có thể hiển thị hình SVG làm ký hiệu không? Có. Ví dụ chính thức hiện tại giải mã văn bản SVG bằng Image của trình duyệt và đăng ký ảnh đó cho lớp ký hiệu. Giữ SVG gốc riêng với ảnh đã đăng ký.

Tại sao đầu vào lớn hơn làm biểu tượng lớn hơn? Tăng kích thước giải mã trong khi giữ cùng tỷ lệ pixel ảnh và icon-size sẽ tăng khung danh nghĩa. Chủ đích kết hợp mật độ ảnh và tỷ lệ hiển thị.

pixelRatio có giữ đường dẫn SVG chỉnh sửa được trong ký hiệu không? Không. Nó mô tả mật độ ảnh. Giữ và sửa SVG nguồn, rồi giải mã hình đã sửa cho bản đồ.

Tại sao pixel bản đồ trong lỗ của biểu tượng lại đục? Lớp nền đục có thể hiện qua khoảng trống trong suốt của biểu tượng. Kiểm tra alpha của ảnh đã đăng ký riêng với vùng vẽ bản đồ đã tổng hợp đầy đủ.

Nguồn tham khảo

  1. MapLibre — Hiển thị ký hiệu SVG từ xa — Cách dùng văn bản SVG, ảnh trình duyệt và addImage hiện tại.
  2. MapLibre — API Map — Các đối tượng ảnh được nhận và đăng ký ảnh khi chạy.
  3. MapLibre — StyleImageMetadata — Mật độ ảnh và siêu dữ liệu diễn giải SDF.
  4. MapLibre — Đặc tả bố cục ký hiệu — Co giãn biểu tượng và hành vi va chạm.
  5. MapLibre — MapOptions — Các tùy chọn vùng vẽ dùng để kiểm soát mẫu đo.
  6. MDN — HTMLImageElement.decode — Chờ giải mã ảnh trình duyệt và xử lý thất bại.
  7. MapLibre — Thêm biểu tượng tùy chỉnh bằng Markers — Quy trình marker phần tử HTML riêng.

Thêm từ blog

PerfectVector

Bắt đầu với SVG gọn sạch hơn
và dễ chỉnh sửa hơn

Không cần thẻ tín dụng