Ảnh SVG cho nút Cytoscape.js: độ vừa và khoảng đệm
Đặt hình SVG tùy chỉnh vừa trong nút Cytoscape.js với ví dụ chạy được. So sánh khoảng trắng nguồn, contain và cover, rồi kiểm tra việc tải và vị trí nhãn.
Trên trang này
Dùng URL ảnh SVG trong kiểu background-image của nút, rồi chọn cách co vừa cho hình bạn muốn hiển thị. Nếu biểu trưng tải được nhưng trông nhỏ xíu, hãy kiểm tra khoảng trống trong khung nhìn SVG trước khi phóng to nút đồ thị. Nếu các đầu bị mất, so sánh tỷ lệ ảnh với nút và kiểm tra việc cắt xén.
Cytoscape.js có tài liệu về nền nút SVG, gồm các cách co vừa contain, cover và none. Hướng dẫn này dùng biểu trưng gốc gồm một đường dẫn để tách ranh giới nguồn khỏi định kiểu đồ thị. Giữ bản chính hình có thể chỉnh sửa cạnh cấu hình đồ thị.
Tách ảnh nguồn khỏi nút đồ thị
Có ba hộp cần kiểm tra: phạm vi phần hình được vẽ, khung nhìn của ảnh SVG và thân nút. SVG viewBox xác định hình chữ nhật tọa độ nguồn được ánh xạ vào khung nhìn. Nó có thể chứa nhiều khoảng trống hơn hẳn phần hình nhìn thấy.
Nguồn có ranh giới sát của chúng tôi là 120 × 60, với biểu trưng màu san hô trải từ x=6 đến x=114 và y=6 đến y=54. Khoảng trống giữa là một phần của cùng đường dẫn:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg>
<svg xmlns="http://www.w3.org/2000/svg"
width="120" height="60" viewBox="0 0 120 60">
<path fill="#f36f59" fill-rule="evenodd"
d="M6 30L30 6H90L114 30L90 54H30Z M50 20H70V40H50Z"/>
</svg>Biến thể có khoảng đệm chỉ đổi kích thước SVG ngoài và viewBox:
<svg xmlns="http://www.w3.org/2000/svg"
width="200" height="140" viewBox="-40 -40 200 140">Giữ nguyên phần đầu, đường dẫn và thẻ đóng. Hai tệp đều vẽ các tọa độ đường dẫn giống hệt. Tệp thứ hai bao quanh chúng bằng nhiều khoảng trống nguồn hơn. Khoảng trống đó co giãn cùng ảnh, nên thay cách co vừa nền không thể đáng tin cậy thay cho việc chọn ranh giới nguồn phù hợp. Hướng dẫn hộp bao SVG giúp xử lý khi khung nhìn của tệp không khớp với hình nhìn thấy.
Chạy ví dụ bốn trường hợp
Chúng tôi kiểm thử Cytoscape.js 3.34.3 với gói trình duyệt chính thức được cố định phiên bản và phục vụ cục bộ. Lưu gói từ thẻ phát hành đó thành cytoscape-3.34.3.min.js cạnh example.html bên dưới. Phục vụ thư mục qua HTTP cục bộ, chẳng hạn bằng python3 -m http.server 8000, rồi mở http://localhost:8000/example.html.
Ví dụ mã hóa SVG gốc thành data URI. encodeURIComponent() mã hóa thoát các ký tự URI, gồm # trong màu tô của chúng tôi. Hướng dẫn SVG của thư viện khuyến nghị cách mã hóa này thay Base64, cùng phần đầu XML được thể hiện ở đây. Đây là một biểu trưng độc lập không có phông chữ hay ảnh bên ngoài.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>SVG node fit comparison</title>
<style>
body { font: 16px system-ui; margin: 20px; }
#cy { width: 1100px; height: 250px; border: 1px solid #ddd; }
#status { white-space: pre-wrap; }
</style>
<div id="cy"></div>
<pre id="status">Loading images</pre>
<script src="cytoscape-3.34.3.min.js"></script>
<script>
const header = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg>';
const path = 'M6 30L30 6H90L114 30L90 54H30Z M50 20H70V40H50Z';
function artwork(padded) {
const width = padded ? 200 : 120;
const height = padded ? 140 : 60;
const viewBox = padded ? '-40 -40 200 140' : '0 0 120 60';
return header + `<svg xmlns="http://www.w3.org/2000/svg"
width="${width}" height="${height}" viewBox="${viewBox}">
<path fill="#f36f59" fill-rule="evenodd" d="${path}"/></svg>`;
}
const cases = [
['tight contain', false, 'contain'],
['tight cover', false, 'cover'],
['padded contain', true, 'contain'],
['padded cover', true, 'cover']
].map(([label, padded, fit]) => ({
label, fit,
image: 'data:image/svg+xml;utf8,' + encodeURIComponent(artwork(padded))
}));
Promise.all(cases.map(item => new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve({
label: item.label,
width: image.naturalWidth,
height: image.naturalHeight
});
image.onerror = () => reject(new Error(item.label + ' failed to load'));
image.src = item.image;
}))).then(loaded => {
cytoscape({
container: document.getElementById('cy'),
elements: cases.map((item, index) => ({
data: { id: 'n' + index, ...item },
position: { x: 110 + index * 260, y: 95 }
})),
style: [{ selector: 'node', style: {
width: 120, height: 80, padding: 0, shape: 'rectangle',
'background-color': '#f1f3f5',
'background-image': 'data(image)',
'background-fit': node => node.data('fit'),
'background-width': 'auto', 'background-height': 'auto',
'background-width-relative-to': 'inner',
'background-height-relative-to': 'inner',
'background-position-x': '50%', 'background-position-y': '50%',
'background-repeat': 'no-repeat', 'background-clip': 'node',
'border-width': 1, 'border-color': '#222',
label: 'data(label)', 'text-valign': 'bottom',
'text-halign': 'center', 'text-margin-y': 10, 'font-size': 12
}}],
layout: { name: 'preset', fit: false },
zoom: 1, pan: { x: 0, y: 0 },
userZoomingEnabled: false, userPanningEnabled: false,
boxSelectionEnabled: false
});
document.getElementById('status').textContent =
'Cytoscape ' + cytoscape.version + '\n' +
JSON.stringify(loaded, null, 2);
}).catch(error => {
document.getElementById('status').textContent = error.message;
});
</script>
</html>Khối trạng thái báo kích thước các ảnh được tải trước khi khởi tạo đồ thị. naturalWidth đọc chiều rộng nội tại của ảnh, đã hiệu chỉnh theo mật độ, bằng pixel CSS như MDN mô tả. Trong mẫu kiểm thử này, các ảnh có ranh giới sát báo 120 × 60, còn các ảnh có khoảng đệm báo 200 × 140. Đó là kích thước ảnh, không phải số đo đường dẫn màu san hô.
So sánh thay đổi ở cùng kích thước nút
Cả bốn nút mô hình đều là 120 × 80 với khoảng đệm nút bằng 0. Chúng tôi kiểm tra mẫu gốc trong Chrome ở mức phóng đại đồ thị 1 và 1,5. Kiểu nút vẫn là 120 × 80; kích thước kết xuất được báo thành 180 × 120 ở mức 1,5. Đây là phép so sánh tĩnh trong trình duyệt đó, không phải phép đo tương thích hay hiệu năng phóng đại.
| Nguồn và cách co vừa | Hình thức quan sát trong mẫu này |
|---|---|
| Ranh giới sát, contain | Biểu trưng đầy đủ, thấy các đầu nhọn |
| Ranh giới sát, cover | Biểu trưng lớn hơn với đầu trái và phải bị cắt ở nút |
| Có khoảng đệm, contain | Biểu trưng nhỏ hơn được bao quanh bởi nhiều khoảng trống |
| Có khoảng đệm, cover | Lớn hơn một chút so với bản có khoảng đệm dùng contain, vẫn nhỏ hơn nhiều so với các bản ranh giới sát |
Nguồn có ranh giới sát có tỷ lệ ảnh 2:1, trong khi nút là 1,5:1. Đặt toàn bộ ảnh 120 × 60 vừa bên trong 120 × 80 sẽ để lại khoảng trống dọc. Phủ kín nút đó sẽ co giãn ảnh thành 160 × 80 trước khi cắt, nên các đầu ngang nhô ra ngoài thân nút.
Với nguồn có khoảng đệm, hình chữ nhật ảnh khả dụng chứa thêm 40 đơn vị ở mỗi bên. Với contain, tỷ lệ bị giới hạn bởi 80/140 thay vì 120/200. Vì vậy biểu trưng giữ nguyên chiều rộng 108 đơn vị chiếm khoảng 62 đơn vị mô hình. Con số đó là phép tính từ các kích thước khai báo, không phải số đo pixel của ảnh chụp màn hình.

Chọn cách co vừa sau khi xem ranh giới hình
Bắt đầu với nguồn ranh giới sát và contain khi toàn bộ biểu trưng quan trọng. Giữ đủ lề nguồn cho mọi nét hoặc hiệu ứng phải còn nhìn thấy. Thu khung nhìn quá sát có thể cắt mất phần hình hợp lệ; đây không phải chỉ dẫn xóa mọi lề.
Dùng cover khi thiết kế chấp nhận cắt cạnh. Trong ví dụ của chúng tôi, nó giấu các đầu nhọn nên là lựa chọn kém phù hợp nếu các đầu đó giúp nhận diện biểu trưng. Nút rộng hơn có thể thay tỷ lệ co vừa và làm lộ các đầu, nhưng cũng thay đổi bố cục đồ thị. Tăng cả hai kích thước theo tỷ lệ giữ nguyên cách cắt. Hãy quyết định ràng buộc nào bạn muốn thay đổi.
Giữ background-width và background-height ở auto cho phép so sánh này. Các giá trị tường minh có thể ghi đè kích thước ảnh được dùng để co vừa. padding của nút là một đầu vào riêng khác; thư viện mô tả kích thước nền có tính nó hay dùng phần thân bên trong. Xem tài liệu tham khảo background-image trước khi thêm các tùy chọn đó. Mẫu có khoảng đệm bằng 0 của chúng tôi trước tiên cô lập khoảng trắng nguồn.
Với quyết định meet, slice và căn chỉnh ở cấp SVG, tiếp tục với hướng dẫn preserveAspectRatio. Thay cách co vừa bên trong SVG và thay cách co vừa nền của Cytoscape là hai thao tác riêng.
Chẩn đoán việc tải trước khi chẩn đoán cắt xén
Nếu trạng thái báo tải thất bại, bước tiếp theo không phải đổi contain sang cover. Mở riêng tài nguyên ảnh, kiểm tra URL và kích thước khai báo, rồi rút gọn về biểu trưng độc lập chỉ gồm đường dẫn ở trên. Với data URI, mã hóa toàn bộ chuỗi SVG thay vì ghép mã đánh dấu thô hoặc giá trị màu chưa được mã hóa thoát.
SVG dùng làm ảnh có các hạn chế khác SVG mở như tài liệu. Hướng dẫn SVG làm ảnh của MDN mô tả các hạn chế với tập lệnh và tài nguyên bên ngoài trong ngữ cảnh ảnh. Tệp hình phụ thuộc vào bảng kiểu hoặc phông chữ ngoài cần kiểm thử bàn giao riêng. Ví dụ này tránh những phụ thuộc đó và đặt nhãn đồ thị ngoài SVG.
Nếu ảnh tải được, kiểm tra cách co vừa và cắt xén ở nút bằng một hình rộng rõ ràng. Sau đó thử hình thực tế ở kích thước nút và các môi trường trình duyệt mà ứng dụng hỗ trợ. Tài liệu Cytoscape ghi nhận các điểm cần lưu ý về SVG tùy trình duyệt; quan sát trong Chrome này không giải quyết chúng cho Firefox hay mọi bộ máy khác.
Giữ nhãn và hình có thể chỉnh sửa riêng biệt
Ví dụ dùng label: 'data(label)' cho nhãn đồ thị và không chứa văn bản SVG. Bạn có thể đổi nội dung nhãn mà không dựng lại biểu trưng. Đường dẫn SVG ở trong bản chính nguồn, còn đồ thị quản lý định danh nút, vị trí và quan hệ.
Mẫu được kiểm tra vẽ lên các bề mặt Canvas. Việc thấy nền SVG ở đó không biến các đường dẫn bên trong thành những phần tử đồ thị có thể chỉnh sửa riêng. Giữ bản chính khi cần đổi khoảng trống, dáng bao hoặc màu. Xuất đồ thị là quy trình riêng cần chọn bộ xuất và kiểm thử bàn giao riêng; hướng dẫn này không hứa rằng đồ thị đã xuất sẽ giữ các đường dẫn biểu trưng có thể chỉnh sửa. Hướng dẫn hình Graphviz tìm hiểu việc bàn giao tham chiếu ảnh trong một bộ kết xuất sơ đồ khác.
Nếu biểu trưng tùy chỉnh chỉ có ở dạng PNG hoặc JPG, hãy chuyển nguồn đó thành hình vector, rồi kiểm tra dáng bao, khoảng trống và chi tiết nhỏ trước khi đặt ranh giới SVG. PerfectVector có thể giúp khôi phục hình học nguồn có thể chỉnh sửa. Định kiểu nền, nhãn nút và xuất đồ thị vẫn là các bước riêng. SVG có sẵn phù hợp có thể đi thẳng đến kiểm tra cách co vừa.
Câu hỏi thường gặp
Tại sao ảnh SVG trong nút nhỏ xíu dù dùng cover? Ảnh nguồn có thể chứa nhiều khoảng trống khung nhìn quanh đường dẫn. So sánh một bản sao có ranh giới sát ở cùng kích thước nút trước khi thay bố cục đồ thị.
Tôi nên dùng contain hay cover cho biểu trưng tùy chỉnh? Chọn contain khi toàn bộ biểu trưng quan trọng. Chỉ chọn cover khi phần cạnh bị cắt quan sát được chấp nhận được với thiết kế, và xác minh bằng nguồn cùng hình nút của bạn.
Nền nút SVG có tạo các đường dẫn đồ thị có thể chỉnh sửa không? Mẫu Canvas đã kiểm thử dùng SVG để vẽ ảnh. Giữ bản chính hình để sửa đường dẫn; các đường bao bên trong không phải nút hay cạnh đồ thị riêng trong ví dụ này.
Tôi có thể đặt nhãn trong SVG không? Ví dụ này giữ nhãn trong dữ liệu đồ thị và dùng hình chỉ gồm đường dẫn. Văn bản SVG, phông chữ và các phụ thuộc của ngữ cảnh ảnh cần kiểm tra trình duyệt và bàn giao riêng.
Nguồn tham khảo
- Cytoscape.js — Ảnh nền — định kiểu URL ảnh, co vừa, ghi đè kích thước, mốc tham chiếu khoảng đệm và các điểm cần lưu ý về SVG.
- Cytoscape.js — Bản phát hành v3.34.3 — bản phát hành cố định dùng cho mẫu gốc.
- Cytoscape.js — Gói trình duyệt v3.34.3 — bản triển khai chính thức theo thẻ được phục vụ cục bộ cho kiểm thử trình duyệt.
- MDN — viewBox — hình chữ nhật tọa độ nguồn và ánh xạ khung nhìn.
- MDN — encodeURIComponent — mã hóa thoát thành phần data URI của SVG.
- MDN — naturalWidth — kích thước ảnh đã tải, khác với ranh giới đường dẫn.
- MDN — SVG làm ảnh — hạn chế ngữ cảnh ảnh và kiểm tra phụ thuộc.
Nếu biểu trưng bắt đầu từ raster, hãy tạo bản chính SVG có thể chỉnh sửa, kiểm tra đường bao và ranh giới nguồn, rồi so sánh contain và cover trong bố cục nút của bạn.
Thêm từ blog

Marker SVG Leaflet: căn đầu nhọn bằng iconAnchor
Đặt marker SVG tùy chỉnh trong Leaflet bằng cách ánh xạ đầu nhọn nhìn thấy tới iconAnchor. Tính cả khoảng đệm viewBox, cách co vừa theo tỷ lệ và thay đổi kích thước biểu tượng.

Đo độ dài đường dẫn SVG mà không nhầm tỷ lệ
Đo đường dẫn SVG theo đơn vị người dùng trong trình duyệt, xét biến đổi và kích thước danh nghĩa, phân biệt tổng đường bao với pathLength hoặc hành trình máy.
