Cách truy cập các phần tử SVG bằng Javascript


83

Tôi đang bối rối với SVG và tôi hy vọng mình có thể tạo tệp SVG trong Illustrator và truy cập các phần tử bằng Javascript.

Đây là tệp SVG mà Illustrator khởi động (Có vẻ như nó cũng thêm một lượng rác vào đầu tệp mà tôi đã xóa)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="276.843px" height="233.242px" viewBox="0 0 276.843 233.242" enable-background="new 0 0 276.843 233.242"
     xml:space="preserve">
<path id="delta" fill="#231F20" d="M34.074,86.094L0,185.354l44.444,38.519l80.741-0.74l29.63-25.186l-26.667-37.037
    c0,0-34.815-5.926-37.778-6.667s-13.333-28.889-13.333-28.889l7.407-18.519l31.111-2.963l5.926-21.481l-12.593-38.519l-43.704-5.185
    L34.074,86.094z"/>
<path id="cargo" fill="#DFB800" d="M68.148,32.761l43.704,4.445l14.815,42.963l-7.407,26.667l-33.333,2.963l-4.444,14.074
    l54.074-1.481l22.222,36.296l25.926-3.704l25.926-54.074c0,0-19.259-47.408-21.481-47.408s-31.852-0.741-31.852-0.741
    l-19.259-39.259L92.593,8.316L68.148,32.761z"/>
<polygon id="beta" fill="#35FF1F" points="86.722,128.316 134.593,124.613 158.296,163.872 190.889,155.724 214.593,100.909 
    194.593,52.02 227.186,49.057 246.444,92.02 238.297,140.909 216.074,172.761 197.556,188.316 179.778,169.798 164.963,174.983 
    163.481,197.946 156.815,197.946 134.593,159.428 94.593,151.279 "/>
<path class="monkey" id="alpha" fill="#FD00FF" d="M96.315,4.354l42.963,5.185l18.519,42.222l71.852-8.148l20.74,46.667l-5.926,52.593
    l-24.444,34.074l-25.185,15.555l-14.074-19.259l-8.889,2.964l-1.481,22.222l-14.074,2.963l-25.186,22.963l-74.074,4.444
    l101.481,4.444c0,0,96.297-17.777,109.63-71.852S282.24,53.983,250.389,20.65S96.315,4.354,96.315,4.354z"/>
</svg>

Như bạn có thể thấy, mỗi phần tử có một ID và tôi đã hy vọng có thể truy cập các phần tử riêng lẻ bằng Javascript để tôi có thể thay đổi thuộc tính Fill và phản hồi các sự kiện như nhấp chuột.

HTML cơ bản

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml" id="alphasvg" width="100%" height="100%"></object>

    </body>
</html>

Tôi đoán đây là hai câu hỏi thực sự.

  1. Có thể làm theo cách này không, trái ngược với việc sử dụng một cái gì đó như Raphael hoặc jQuery SVG.

  2. Nếu có thể, kỹ thuật là gì?


CẬP NHẬT

Hiện tại, tôi đã sử dụng Illustrator để tạo tệp SVG và tôi đang sử dụng Raphaël JS để tạo đường dẫn và chỉ cần sao chép dữ liệu điểm từ tệp SVG và dán nó vào path()chức năng. Việc tạo các đường phức tạp chẳng hạn như có thể cần thiết cho một bản đồ, bằng cách mã hóa dữ liệu điểm theo cách thủ công (theo hiểu biết của tôi) là cực kỳ phức tạp.

Câu trả lời:


113

Có thể làm theo cách này, thay vì sử dụng một cái gì đó như Raphael hoặc jQuery SVG?

Chắc chắn.

Nếu có thể, kỹ thuật là gì?

Đoạn mã được chú thích này hoạt động:

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml"
         id="alphasvg" width="100%" height="100%"></object>

        <script>
            var a = document.getElementById("alphasvg");

            // It's important to add an load event listener to the object,
            // as it will load the svg doc asynchronously
            a.addEventListener("load",function(){

                // get the inner DOM of alpha.svg
                var svgDoc = a.contentDocument;
                // get the inner element by id
                var delta = svgDoc.getElementById("delta");
                // add behaviour
                delta.addEventListener("mousedown",function(){
                        alert('hello world!')
                }, false);
            }, false);
        </script>
    </body>
</html>

Lưu ý rằng một hạn chế của kỹ thuật này là nó bị hạn chế bởi chính sách nguồn gốc, do đó alpha.svgphải được lưu trữ trên cùng một miền với .htmltệp, nếu không, DOM bên trong của đối tượng sẽ không thể truy cập được.

Điều quan trọng để chạy HTML này, bạn cần có tệp HTML lưu trữ trên máy chủ web như IIS, Tomcat


4
lưu ý trên ghi chú của @ jbeard4: trong một số trình duyệt, chính sách cùng nguồn gốc này dẫn đến yêu cầu sử dụng máy chủ (ngay cả khi bạn viết mã chỉ sử dụng html và js [serveride]), chính sách truy cập sẽ ngăn truy cập vào svg.
Michael

1
Điều quan trọng để chạy HTML này, bạn cần có tệp HTML lưu trữ trên máy chủ web như IIS, Tomcat
Hien Nguyen

Như @HienNguyen đã đề cập, trước khi chạy nó trên máy chủ web, Nó không hoạt động. Giá trị được trả về document.getElementById("alphasvg").contentDocumentnull.
am.rez

TL; DR: contentDocumentcầu nối từ ngữ cảnh HTML sang ngữ cảnh SVG
Abdull

19

Trong trường hợp bạn sử dụng jQuery, bạn cần phải đợi $(window).loadvì tài liệu SVG được nhúng có thể chưa được tải tại$(document).ready

$(window).load(function () {

    //alert("Document loaded, including graphics and embedded documents (like SVG)");
    var a = document.getElementById("alphasvg");

    //get the inner DOM of alpha.svg
    var svgDoc = a.contentDocument;

    //get the inner element by id
    var delta = svgDoc.getElementById("delta");
    delta.addEventListener("mousedown", function(){ alert('hello world!')}, false);
});

3
Trong khi sử dụng mã này, câu trả lời khác này có thể là một sự bổ sung hữu ích: stackoverflow.com/a/5990945/1515819
Stéphane BRUCKERT

trong trường hợp jQuery, tốt hơn bạn nên sử dụng $('#alphasvg').loadthay vì $(window).load. Điều này sẽ cho phép bạn thay đổi thuộc tính datanhanh chóng
vkabachenko

Lưu ý rằng mặc dù bạn có thể sử dụng jQuery để truy cập các phần tử trong svg, nhưng bạn không thể sử dụng nó để nối các phần tử vào một svg. Xem stackoverflow.com/questions/3642035/… để biết lý do.
hrabinowitz

4

Nếu bạn đang sử dụng <img>thẻ cho SVG, thì bạn không thể thao tác nội dung của nó (theo như tôi biết).

Như câu trả lời được chấp nhận cho thấy, sử dụng <object>là một tùy chọn.

Tôi đã cần nó gần đây và đã sử dụng gulp-injecttrong quá trình xây dựng gulp của mình để đưa nội dung của tệp SVG trực tiếp vào tài liệu HTML dưới dạng một <svg>phần tử, sau đó rất dễ làm việc với việc sử dụng các bộ chọn CSS và querySelector/ getElementBy*.


imgthẻ này hữu ích với tải SVG lớn ... Để sử dụng SVG phức tạp (và tương tác!), tốt hơn nên sử dụng D3js , giống như jQuery nhỏ gọn , chuyên về thao tác dữ liệu SVG + DOM +.
Peter Krauss
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.