从SVG文件调用JavaScript函数

4
我有一个SVG文件和一个JavaScript文件。
在我的SVG文件中,我有一些代码,但我想知道的是这个小代码量:
<g id="zoomButton">
    <g onclick="zoom()" transform="scale(x,y)">
         <rect x="640" y="20" width="140" height="40"
               style="fill:white;stroke:red;stroke-width:2" />
         <text x="710" y="49"
               style="fill:red;font-size:25px;text-anchor:middle">Zoom</text>
    </g>
</g>

你看到我想要在点击这个按钮时调用函数zoom()

现在,在我的JavaScript文件中,我有这个名为zoom()的函数:

function zoom() {
    alert("heyho");
}

然而,当我按下在SVG文件中创建的按钮时,此函数并未被触发。我只收到了错误信息:

Uncaught ReferenceError: zoom is not defined

我只想在按下这个按钮时调用该JavaScript函数。

此外,由于这是一个缩放功能,我想进行一些缩放,如何从JavaScript文件中访问SVG文件中transform="scale(x,y)中的x和y?

编辑:

SVG文件(game.svg)中的完整代码如下:

<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="600px"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xhtml="http://www.w3.org/1999/xhtml"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     xmlns:a="http://www.adobe.com/svg10-extensions" a:timeline="independent"
     onload="top.load(evt)">

  <defs>
    <clipPath id="gameareaclip">
      <rect x="20" y="20" width="600" height="560"/>
    </clipPath>
    <pattern id="background_pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
      <rect width="20" height="20" style="fill:purple"/>
      <circle cx="10" cy="10" r="8" style="fill:black"/>
    </pattern>
    <radialGradient id="player_color">
      <stop offset="0.0" style="stop-color:yellow;stop-opacity:1"/>
      <stop offset="0.8" style="stop-color:yellow;stop-opacity:1"/>
      <stop offset="1.0" style="stop-color:orange;stop-opacity:1"/>
    </radialGradient>
  </defs>

  <rect width="100%" height="100%" style="fill:url(#background_pattern);stroke:orange;stroke-width:4" />

  <rect x="20" y="20" width="600" height="560" style="fill:black;stroke:red;stroke-width:5" />

  <!-- Add your button here -->

  <g id="zoomKnapp">
  <g onclick="zoom()" transform="scale(x,y)">
    <rect x="640" y="20" width="140" height="40"
          style="fill:white;stroke:red;stroke-width:2" />
    <text x="710" y="49"
          style="fill:red;font-size:25px;text-anchor:middle">Zoom</text>
  </g>
</g>

  <g style="clip-path:url(#gameareaclip)">
    <g transform="translate(20,20)">
      <g id="gamearea" transform="translate(0,0)" width="600" height="560">
        <rect x="0" y="0" width="600" height="560" style="fill:lightgrey" />

        <g id="platforms">

          <!-- Add your platforms here -->

  <rect id="svg_37" height="20" width="300" y="100" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
  <rect id="svg_38" height="20" width="300" y="170" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
  <rect id="svg_39" height="20" width="300" y="240" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
  <rect id="svg_40" height="20" width="300" y="310" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
  <rect id="svg_41" height="20" width="300" y="380" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
  <rect id="svg_42" height="20" width="300" y="450" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>

        </g>

        <g id="player">
          <circle cx="20" cy="20" r="20" style="fill:url(#player_color);stroke:black;stroke-width:2"/>
          <ellipse cx="15" cy="15" rx="3" ry="6" style="fill:black"/>
          <ellipse cx="25" cy="15" rx="3" ry="6" style="fill:black"/>
          <path d="M10,25 l20,0 q0,8 -10,8 t-10,-8" style="fill:orange;stroke:black;stroke-black:2"/>
        </g>
      </g>
    </g>
  </g>
</svg>

HTML文件(game.html):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>SVG Game</title>
  <script language="JavaScript" src="game.js"></script>
</head>

<body style="text-align: center">
    <embed src="game.svg" type="image/svg+xml" width="800" height="600" />
</body>

</html>

JavaScript(game.js)代码:

// The point and size class used in this program
function Point(x, y) {
    this.x = (x)? parseFloat(x) : 0.0;
    this.y = (y)? parseFloat(y) : 0.0;
}

function Size(w, h) {
    this.w = (w)? parseFloat(w) : 0.0;
    this.h = (h)? parseFloat(h) : 0.0;
}

// Helper function for checking intersection between two rectangles
function intersect(pos1, size1, pos2, size2) {
    return (pos1.x < pos2.x + size2.w && pos1.x + size1.w > pos2.x &&
            pos1.y < pos2.y + size2.h && pos1.y + size1.h > pos2.y);
}


function zoom() {
    alert("heiho");
}

// The player class used in this program
function Player() {
    this.node = svgdoc.getElementById("player");
    this.position = PLAYER_INIT_POS;
    this.motion = motionType.NONE;
    this.verticalSpeed = 0;
}

Player.prototype.isOnPlatform = function() {
    var platforms = svgdoc.getElementById("platforms");
    for (var i = 0; i < platforms.childNodes.length; i++) {
        var node = platforms.childNodes.item(i);
        if (node.nodeName != "rect") continue;

        var x = parseFloat(node.getAttribute("x"));
        var y = parseFloat(node.getAttribute("y"));
        var w = parseFloat(node.getAttribute("width"));
        var h = parseFloat(node.getAttribute("height"));

        if (((this.position.x + PLAYER_SIZE.w > x && this.position.x < x + w) ||
             ((this.position.x + PLAYER_SIZE.w) == x && this.motion == motionType.RIGHT) ||
             (this.position.x == (x + w) && this.motion == motionType.LEFT)) &&
            this.position.y + PLAYER_SIZE.h == y) return true;
    }
    if (this.position.y + PLAYER_SIZE.h == SCREEN_SIZE.h) return true;

    return false;
}

Player.prototype.collidePlatform = function(position) {
    var platforms = svgdoc.getElementById("platforms");
    for (var i = 0; i < platforms.childNodes.length; i++) {
        var node = platforms.childNodes.item(i);
        if (node.nodeName != "rect") continue;

        var x = parseFloat(node.getAttribute("x"));
        var y = parseFloat(node.getAttribute("y"));
        var w = parseFloat(node.getAttribute("width"));
        var h = parseFloat(node.getAttribute("height"));
        var pos = new Point(x, y);
        var size = new Size(w, h);

        if (intersect(position, PLAYER_SIZE, pos, size)) {
            position.x = this.position.x;
            if (intersect(position, PLAYER_SIZE, pos, size)) {
                if (this.position.y >= y + h)
                    position.y = y + h;
                else
                    position.y = y - PLAYER_SIZE.h;
                this.verticalSpeed = 0;
            }
        }
    }
}

Player.prototype.collideScreen = function(position) {
    if (position.x < 0) position.x = 0;
    if (position.x + PLAYER_SIZE.w > SCREEN_SIZE.w) position.x = SCREEN_SIZE.w - PLAYER_SIZE.w;
    if (position.y < 0) {
        position.y = 0;
        this.verticalSpeed = 0;
    }
    if (position.y + PLAYER_SIZE.h > SCREEN_SIZE.h) {
        position.y = SCREEN_SIZE.h - PLAYER_SIZE.h;
        this.verticalSpeed = 0;
    }
}


//
// Below are constants used in the game
//
var PLAYER_SIZE = new Size(40, 40);         // The size of the player
var SCREEN_SIZE = new Size(600, 560);       // The size of the game screen
var PLAYER_INIT_POS  = new Point(0, 0);     // The initial position of the player

var MOVE_DISPLACEMENT = 5;                  // The speed of the player in motion
var JUMP_SPEED = 15;                        // The speed of the player jumping
var VERTICAL_DISPLACEMENT = 1;              // The displacement of vertical speed

var GAME_INTERVAL = 25;                     // The time interval of running the game


//
// Variables in the game
//
var motionType = {NONE:0, LEFT:1, RIGHT:2}; // Motion enum

var svgdoc = null;                          // SVG root document node
var player = null;                          // The player object
var gameInterval = null;                    // The interval
var zoom = 1.0;                             // The zoom level of the screen


//
// The load function for the SVG document
//
function load(evt) {
    // Set the root node to the global variable
    svgdoc = evt.target.ownerDocument;

    // Attach keyboard events
    svgdoc.documentElement.addEventListener("keydown", keydown, false);
    svgdoc.documentElement.addEventListener("keyup", keyup, false);

    // Remove text nodes in the 'platforms' group
    cleanUpGroup("platforms", true);

    // Create the player
    player = new Player();

    // Start the game interval
    gameInterval = setInterval("gamePlay()", GAME_INTERVAL);
}


//
// This function removes all/certain nodes under a group
//
function cleanUpGroup(id, textOnly) {
    var node, next;
    var group = svgdoc.getElementById(id);
    node = group.firstChild;
    while (node != null) {
        next = node.nextSibling;
        if (!textOnly || node.nodeType == 3) // A text node
            group.removeChild(node);
        node = next;
    }
}


//
// This is the keydown handling function for the SVG document
//
function keydown(evt) {
    var keyCode = (evt.keyCode)? evt.keyCode : evt.getKeyCode();

    switch (keyCode) {
        case "N".charCodeAt(0):
            player.motion = motionType.LEFT;
            break;

        case "M".charCodeAt(0):
            player.motion = motionType.RIGHT;
            break;


        // Add your code here
        case "Z".charCodeAt(0):
        if (player.isOnPlatform()) {
          //Jump
          player.verticalSpeed = JUMP_SPEED;
        }
            break;


    }
}


//
// This is the keyup handling function for the SVG document
//
function keyup(evt) {
    // Get the key code
    var keyCode = (evt.keyCode)? evt.keyCode : evt.getKeyCode();

    switch (keyCode) {
        case "N".charCodeAt(0):
            if (player.motion == motionType.LEFT) player.motion = motionType.NONE;
            break;

        case "M".charCodeAt(0):
            if (player.motion == motionType.RIGHT) player.motion = motionType.NONE;
            break;
    }
}


//
// This function updates the position and motion of the player in the system
//
function gamePlay() {
    // Check whether the player is on a platform
    var isOnPlatform = player.isOnPlatform();

    // Update player position
    var displacement = new Point();

    // Move left or right
    if (player.motion == motionType.LEFT)
        displacement.x = -MOVE_DISPLACEMENT;
    if (player.motion == motionType.RIGHT)
        displacement.x = MOVE_DISPLACEMENT;

    // Fall
    if (!isOnPlatform && player.verticalSpeed <= 0) {
        displacement.y = -player.verticalSpeed;
        player.verticalSpeed -= VERTICAL_DISPLACEMENT;
    }

    // Jump
    if (player.verticalSpeed > 0) {
        displacement.y = -player.verticalSpeed;
        player.verticalSpeed -= VERTICAL_DISPLACEMENT;
        if (player.verticalSpeed <= 0)
            player.verticalSpeed = 0;
    }

    // Get the new position of the player
    var position = new Point();
    position.x = player.position.x + displacement.x;
    position.y = player.position.y + displacement.y;

    // Check collision with platforms and screen
    player.collidePlatform(position);
    player.collideScreen(position);

    // Set the location back to the player object (before update the screen)
    player.position = position;

    updateScreen();
}


//
// This function updates the position of the player's SVG object and
// set the appropriate translation of the game screen relative to the
// the position of the player
//
function updateScreen() {
    // Transform the player
    player.node.setAttribute("transform", "translate(" + player.position.x + "," + player.position.y + ")");

    // Calculate the scaling and translation factors

    // Add your code here

}

你是如何将JavaScript文件链接到SVG文件的? - Robert Longson
请查看以下链接:http://stackoverflow.com/questions/21456304/calling-javascript-function-from-svg-file - Mukesh Prajapat
我其实对网页开发很新,大部分代码都是从我的教授那里得到的。我在SVG文件中看到的唯一链接到JavaScript文件的是<svg>标签中的onload="top.load(evt)"。在JavaScript文件中,SVG文件与var svgdoc = evt.target.ownerDocument相关联。 - Jurge92
可能是重复的问题,参见如何从嵌入的SVG中调用父HTML文档中的函数 - Asons
1个回答

2
脚本标签需要放在SVG文件(game.svg)中,而不是HTML文件中。请注意,SVG script标签使用xlink:href而不是src作为保存脚本源的属性。
 <script xlink:href="game.js"></script>

您还应该将根<svg>元素中的onload="top.load(evt)"更改为onload="load(evt)"
您的第三个和主要问题是,您在第114行有一个名为zoom()的函数和一个名为zoom的变量。移除未使用的变量,这样zoom方法就会被调用。

将该行添加到SVG文件似乎没有任何帮助。仍然收到相同的错误消息。尝试在HTML文件中保留<script language="JavaScript" src="game.js"></script>和不保留两种方式。没有区别。 - Jurge92
这就是错误所在,看看我的更新答案。 - Robert Longson
非常感谢,现在它正在工作!但同时我需要问一下,top.load(evt)和load(evt)之间有什么区别? - Jurge92
top 意味着在容器中查找函数(即脚本需要在 HTML 文件中),否则脚本需要在 SVG 文件中。 - Robert Longson
啊,好的,我明白了。再次感谢您的帮助和解释,非常感激 :) - Jurge92

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接