Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [JS,SVG] Dołączenie skryptu do svg z pliku
Forum PHP.pl > Forum > Po stronie przeglądarki
Berkovits
Mam plik kolo.svg, proba.js oraz proba.html. W pliku kolo.svg jest koło id="koloSVG", którego kliknięcie powinno uruchomić funkcję zawartą w pliku proba.js.
Oczywiście podane tutaj pliki są uproszczone, by łatwiej znaleźć problem.
Próbuję to zrobić na różne sposoby, ale nic nie wychodzi. Oba pliki mają znajdować się lokalnie na dysku użytkownika.

plik kolo.svg
  1. <?xml version="1.0"?>
  2. <svg width="160" height="160" xmlns="http://www.w3.org/2000/svg" xlinkns="http://www.w3.org/1999/xlink">
  3. <g> <ellipse ry="50" rx="50" id="koloSVG" cy="70" cx="70" stroke-width="5" stroke="#003300" fill="#66ff66"/>
  4. </g>
  5. <script>
  6. function klik1(){alert('klik1');}
  7.  
  8. var e=document.getElementById('koloSVG');
  9. //e.addEventListener("click",klik1,false); //(a)
  10. //e.addEventListener("click",top.klik2,false); //(b)
  11. //e.addEventListener("click",parent.klik2,false); //(c)
  12. </script>
  13. </svg>

plik proba.html
  1. <!doctype html>
  2. <meta charset="utf-8">
  3. <script src="proba.js"></script>
  4. </head>
  5. <div id="mydiv"></div>
  6. <iframe id="frame" src="kolo.svg"></iframe>
  7. <embed id="embed" src="kolo.svg" type="image/svg+xml" />
  8. <object id="object" type="image/svg+xml" data="kolo.svg"></object>
  9. </body>
  10. </html>


plik proba.js
  1.  
  2. function klik2(){ //funkcja, która ma być wywołana przy kliknięciu na koło s pliku .svg
  3. alert('klik2');
  4. }
  5.  
  6. function loadSVG() //próba załadowania pliku kolo.svg poprzez XMLHttpRequest
  7. {
  8. var SVGFile="kolo.svg";
  9. var loadXML = new XMLHttpRequest;
  10. function handler()
  11. {
  12. if(loadXML.readyState == 4)
  13. {
  14. if (loadXML.status == 200)
  15. {
  16. var xmlString=loadXML.responseText;
  17. document.getElementById('mydiv').innerHTML=xmlString;
  18. }
  19. }
  20. }
  21. if (loadXML != null)
  22. {
  23. loadXML.open("GET", SVGFile, true);
  24. loadXML.onreadystatechange = handler;
  25. loadXML.send(); //(*)
  26. }
  27. }
  28.  
  29.  
  30. window.addEventListener("load",loadDocument,false);
  31.  
  32. function loadDocument(){
  33. //loadSVG(); (d)
  34.  
  35. //addEventToSVG('embed'); // (e)
  36. //addEventToSVG('frame'); // (f)
  37. //addEventToSVG('object'); // (g)
  38. //addEventToSVG2('frame'); // (h)
  39. //addEventToSVG2('object'); // (i)
  40. //addEventToSVG2('embed'); // (j)
  41. }
  42.  
  43. function addEventToSVG(elementID){ //próba dotarcia do elementu id="koloSVG"
  44. var svgdoc=document.getElementById(elementID).getSVGDocument(); //(**)
  45. var e=svgdoc.getElementById('koloSVG');
  46. e.addEventListener("click",klik2,false);
  47. }
  48.  
  49. function addEventToSVG2(elementID){ //kolejna próba dotarcia do elementu id="koloSVG"
  50. var svgdoc=document.getElementById(elementID).contentDocument(); //(***)
  51. var e=svgdoc.getElementById('koloSVG');
  52. e.addEventListener("click",klik2,false);
  53. }
  54.  


Jeśli w pliku kolo.svg odkomentuję odpowiednie linijki, to będzie następujące działanie:

( a ) : Wszystko ok, ale ja chcę wywołać funkcję spoza pliku svg, czyli klik2.
( b ) - ( c ) : Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match. (3 razy, bo 3 obrazki) Linijka powodująca błąd to kolejno ( b ) i ( c ).

Jeśli w pliku proba.js odkomentuję odpowiednie linijki, to będzie następujące działanie:

( d - czyli chcę załadować obrazek poprzez XMLHttpRequest) : XMLHttpRequest cannot load file:///G:/.../kolo.svg. Cross origin requests are only supported for HTTP.
oraz: Uncaught NetworkError: A network error occurred.

( e ) - ( g ) : Uncaught SecurityError: Failed to execute 'getSVGDocument' on 'HTMLEmbedElement': Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match. Linijka powodująca błąd to (*)
( h ) - ( i ) : Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match. Linijka powodująca błąd to (**)
( j ) : Uncaught TypeError: Object #<HTMLEmbedElement> has no method 'contentDocument'. Linijka powodująca błąd to (**)

Odpalałem to na Google Chrome 33.0.1750.154 m

Nie mam pojęcia, jak to w takim razie zrobić. Szukałem tych błędów w google i zdaje się, że problem jest z tym, że plik svg jest umiejscowiony lokalnie (gdybym mógł dać link w postaci http://..., to by niby poszło), ale nie wiem, czy dobrze zrozumiałem i dlaczego to miałby być problem. Gdzieś znalazłem różne dywagacje na temat ,,same origin policy", ale przecież te dwa pliki są w jednym źródle.

Nie chodzi mi też o to, by w pliku svg zasysać plik proba.js, bo kliknięcie musi operować na danych, które są zewnętrzne wobec pliku svg.
trueblue
Obiekt XMLHttpRequest nie operuje na protokole file://
Dla testów możesz uruchamiać Chrome z przełącznikiem:
--allow-file-access
On ChromeOS, file:// access is disabled except for certain whitelisted directories. This switch re-enables file:// for testing.

Idąc dalej, kolo.svg ładuje się po protokole http:// poprawnie, ale nie wiem dlaczego zdarzenia dołączasz do trzech pozostałych elementów, a nie próbujesz do SVG wczytanego do diva.
Berkovits
Do trueblue: Dzięki za odpowiedź.

Wpisałem tyle prób, bo szukam dobrego rozwiązania. Żadna z tych prób nie zadziałała.
Nie chodzi mi o przełączanie ustawień do testów, ponieważ w założeniu ten program ma działać na plikach zapisanych lokalnie (nie w internecie).
Ponieważ nie ładuje mi się do diva, próbuję dalej z object, iframe, embed. Nic nie działa.

Dziwi mnie to, że nie można zrobić tak, jak z javascript. Jeśli mam js w osobnym pliku, to dołączam go bez problemu. Niestety, nie można zrobić czegoś takiego:
<svg src="kolo.svg"></svg>.
trueblue
  1.  
  2. function klik2(){ //funkcja, która ma być wywołana przy kliknięciu na koło s pliku .svg
  3. alert('klik2');
  4. }
  5.  
  6. function loadSVG() //próba załadowania pliku kolo.svg poprzez XMLHttpRequest
  7. {
  8. var SVGFile="kolo.svg";
  9. var loadXML = new XMLHttpRequest;
  10. function handler()
  11. {
  12. if(loadXML.readyState == 4)
  13. {
  14. if (loadXML.status == 200)
  15. {
  16. var xmlString=loadXML.responseText;
  17. document.getElementById('mydiv').innerHTML=xmlString;
  18. addEventToSVG2('mydiv'); //musisz tu dodać zdarzenie, bo tu jesteś pewien, że żądanie ajax się zakończyło
  19. }
  20. }
  21. }
  22. if (loadXML != null)
  23. {
  24. loadXML.open("GET", SVGFile, true);
  25. loadXML.onreadystatechange = handler;
  26. loadXML.send(); //(*)
  27. }
  28. }
  29.  
  30.  
  31. window.addEventListener("load",loadDocument,false);
  32.  
  33. function loadDocument(){
  34. loadSVG();
  35. //tu nie można dodać zdarzenia, bo być może obiekt jeszcze nie istnieje
  36. }
  37. function addEventToSVG2(elementID){
  38. var svgdoc=document.getElementById(elementID).getElementsByTagName('svg')[0];
  39. var e=svgdoc.getElementById('koloSVG');
  40. e.addEventListener("click",klik2,false);
  41. }

Powyżej jest przeróbka kodu, działa, ale po protokole http://
Nie musisz publikować w internecie, postaw sobie na komputerze serwer http (http://pl.wikipedia.org/wiki/XAMPP)
Berkovits
Do trueblue: Wcześniej nie mogłem odpisać.

Dzięki za pomoc. Będę się musiał pogodzić, że nie da się tego zrobić offline bez serwera. Muszę przyznać, że jestem tym rozczarowany. Piszę grę dla córki z rozpoznawaniem państw, flagi, itd. Chciałem, by składała się z kilku plików, które można uruchomić na swoim komputerze. Chciałem móc przekazać innym znajomym rodzicom, by i oni mogli sobie uruchamiać bez stawiania serwera. Ale trudno, choć jestem tym bardzo zdziwiony. Oczywiście mogę wrzucić svg do pliku html, ale to po pierwsze masakra (bo to duży plik), a ponadto nie ma możliwości wyboru mapy.
A tak w ogóle, to na starej instalacji Opery zadziałała opcja (e), czyli załadowanie do <embed> i odwołanie się do zawartości poprzez getSVGDocument(). Chrome wyświetla security error.
trueblue
Wraz z plikami gry dołącz skrót do wywołania Chrome z przełącznikiem, o którym pisałem.
TheR2d2
Witam.

Zastanawiałem się nad Twoim problemem wczoraj przed snem i doszedłem do wniosku że jeśli nie potrzebujesz bardzo koniecznie używać svg to można to zrobić troszeczkę inaczej.

Z pomocą może tutaj przyjść dawna "zabawka" Microsoft, która aktualnie jest wspierana wraz z Internet Explorer.
Mowa o rozszerzeniu hta (mshta.exe)

<!DOCTYPE html>
<html>
<head>
<title>Czater</title>
<meta http-equiv="X-UA-Compatible" content="IE=8"/> // 8 to minimum jak ktoś używa ie9 to można wpisać 9 //
<meta charset="utf-8" />

<HTA:APPLICATION id="id aplikacji"
applicationName="Nazwa dla aplikacji (indywidualna) "
border="thin"
borderStyle="normal"
caption="yes"
icon="favicon.ico" // mozna ustawić ionkę dla 'programu' //
maximizeButton="yes"
minimizeButton="yes"
showInTaskbar="yes"
windowState="normal"
innerBorder="no"
navigable="no"
scroll="no"
scrollFlat="yes"
singleInstance="no"
sysMenu="yes"
contextMenu="no"
selection="yes"
version="wersja aplikacji" />
<script> duuuuuuuuuuużo javascript'u </script>
<body>

elementy html z których będzie zbudowana aplikacja

</body>
</html>



To taki prosty schemat, można też użyć elementów svg ale wtedy wymagany jest IE9 minimum zainstalowany w systemie.
W takiej aplikacji śmiało można zastosować bibliotekę JQuery a nawet bootstrap'y jak html kickstarter np.

Odnośnie zapisywania postępów gry np można użyć zwyczajnych cookies smile.gif w trakcie używania aplikacji a do zapisu w finale zastosować zapis do pliku testowego przez ActiveX.

Odnośnie Twoich kółeczek biggrin.gif można to zrealizować za pomocą <map>

<map name="a">
<area shape="circle" coords="200,250,25" onclick="wywołanie skryptu z parametrem" />
<area shape="rect" coords="25,25,75,75" onclick="wywołanie skryptu z parametrem" />
</map>
<img usemap="#a" src="image.png">
Mapa globu z rejonami do klikania smile.gif

Myślę że to może być nie głupie rozwiązanie smile.gif

Pozdrawiam
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.