Javascript 尝试移动SVG矩形时raphaelJS的奇怪行为

Javascript 尝试移动SVG矩形时raphaelJS的奇怪行为,javascript,jquery,jquery-plugins,svg,raphael,Javascript,Jquery,Jquery Plugins,Svg,Raphael,我正在使用RaphaelJS和jQuery.SVG进行图形演示。现在,我有一个动态创建的8x8矩形网格,用户可以单击选择。一旦选择了两个矩形,那么所选的矩形就应该彼此交换位置(就像在Bejeweled中一样) 我已经到了可以让矩形互换的地步,但是它们没有在正确的位置结束。根据代码,我在动画函数中交换每个选定矩形的x和y坐标。在测试中,RECT总是“脱离网格”。视觉效果很好,但我真的希望矩形保持对齐 我正在构建的调试字符串告诉我rect的位置没有改变。显然那不是真的…这里发生了什么 以下是此问

我正在使用RaphaelJS和jQuery.SVG进行图形演示。现在,我有一个动态创建的8x8矩形网格,用户可以单击选择。一旦选择了两个矩形,那么所选的矩形就应该彼此交换位置(就像在Bejeweled中一样)

我已经到了可以让矩形互换的地步,但是它们没有在正确的位置结束。根据代码,我在动画函数中交换每个选定矩形的x和y坐标。在测试中,RECT总是“脱离网格”。视觉效果很好,但我真的希望矩形保持对齐

我正在构建的调试字符串告诉我rect的位置没有改变。显然那不是真的…这里发生了什么

以下是此问题的相关代码:

        // swapTiles
/*

Swaps two tiles on the board that have been set to 'selected' with an animation.    

*/
function swapTiles(toSwap) {

    var holdX = $(toSwap[0]).attr('x');
    var holdY = $(toSwap[0]).attr('y');

    // Pre-swap debugging
    statusString += "<br><b>BEFORE SWAP</b><br>";
    statusString += "<br>First cell: " + selectedCellNames[0];
    statusString += "<br>2nd cell: " + selectedCellNames[1];
    statusString += "<br>$(toSwap[0]).attr('x'): " + $(toSwap[0]).attr('x').toString();
    statusString += "<br>$(toSwap[0]).attr('y'): " + $(toSwap[0]).attr('y').toString();
    statusString += "<br>$(toSwap[1]).attr('x'): " + $(toSwap[1]).attr('x').toString();
    statusString += "<br>$(toSwap[1]).attr('y'): " + $(toSwap[1]).attr('y').toString();
    statusString += "<br>";

    /*
    This line is using jQuery SVG to grab the DOM elements. This is being used because trying to grab the elements through
    raphael was returning undefined errors. There seems to be some DOM scope issue that is causing me to use this and the temp.node 
    workarounds in order to reference SVG objects created through raphael.

    What did not work:

    $(toSwap[0]).animate({ x: 50, y: 100, 'stroke-width': 3 }, 250, '<'); --raphael animate function
    $(toSwap[0]).node.animate({ x: 50, y: 100, 'stroke-width': 3 }, 250, '<'); 

    When I tried to access the tiles using jQuery and the cellName user-defined attribute, I got '0' added to my debug output.        

    */
    $(toSwap[0]).animate({ svgX: $(toSwap[1]).attr('x'), svgY: $(toSwap[1]).attr('y'), svgStrokeWidth: 2, svgStroke: "#000" }, 250);
    $(toSwap[1]).animate({ svgX: holdX, svgY: holdY, svgStrokeWidth: 2, svgStroke: "#000" }, 250);

    // Post-swap debugging
    statusString += "<br><b>SWAP COMPLETE</b><br>";        
    statusString += "<br>$(toSwap[0]).attr('x'): " + $(toSwap[0]).attr('x').toString();
    statusString += "<br>$(toSwap[0]).attr('y'): " + $(toSwap[0]).attr('y').toString();
    statusString += "<br>$(toSwap[1]).attr('x'): " + $(toSwap[1]).attr('x').toString();
    statusString += "<br>$(toSwap[1]).attr('y'): " + $(toSwap[1]).attr('y').toString();
    statusString += "<br>";

}

// drawRect
/*

returns a Raphael rectangle object with the inputted options
color = the value that the color attr will be set to for this rect
x, y = x & y position of the top-left corner of the rect
w, h = width and height of the rect
corner = radius for the rounded corners

*/
function drawRect(color, x, y, w, h, corner) {

    var temp = canvas.rect(x, y, w, h, corner);
    temp.attr("fill", color);
    temp.node.setAttribute("selected", "false"); // Will be used to check for selected tiles in main loop    
    temp.node.setAttribute("cellName", cellName); // Give this rect a name

    // Add the mouseover/hover events
    temp.node.onmouseover = function () {

        temp.animate({ scale: 1.5, stroke: "#FFF", 'stroke-width': 3 }, 250, 'bounce').toFront();

    }; // end temp.node.onmouseover

    temp.node.onmouseout = function () {

        if (temp.node.getAttribute("selected") == "true") {

            temp.animate({ scale: 1, stroke: "#FFF", 'stroke-width': 4 }, 250, 'elastic').toFront();

        }
        else {

            temp.animate({ scale: 1, stroke: "#000", 'stroke-width': 2 }, 250, 'elastic').toBack();

        }

        // Update the status debugging
        statusString += "<br>(x: " + x.toString() + ", y: " + y.toString() + ") temp.node.getAttribute('selected') after .node.onmouseout = " + temp.node.getAttribute("selected");
        statusString += "<br>selectedCount = " + selectedCount.toString();
        statusString += "<br>cellName = " + temp.node.getAttribute("cellName");
        statusString += "<br>selectedCells[0] = " + selectedCells[0].toString();
        statusString += "<br>selectedCells[1] = " + selectedCells[1].toString();
        $("#status").html(statusString);
        statusString = "";

    }; // end temp.node.onmouseout

    // Toggle between selected / not-selected
    temp.node.onclick = function () {

        // if not selected yet 
        if (temp.node.getAttribute("selected") != "true") {

            temp.animate({ scale: 1, stroke: "#FFF", 'stroke-width': 4 }, 250, 'elastic').toFront();
            temp.node.setAttribute("selected", "true");
            selectedCount += 1;

            // Place the current cell into our array
            if (selectedCount == 1) {

                selectedCells[0] = temp.node;
                selectedCellNames[0] = temp.node.getAttribute("cellName");

            }
            // We have two cells selected: time to swap
            else if (selectedCount == 2) {

                selectedCells[1] = temp.node;
                selectedCellNames[1] = temp.node.getAttribute("cellName");

                swapTiles(selectedCells);

                // Clean up selectedCells and the selected attributes
                /*

                Since selectedCells already contains references to the temp.nodes of each SVG object, 
                use this format to set the attributes. No jQuery SVG call or additional .node is needed.

                */
                selectedCells[0].setAttribute("selected", "false");
                selectedCells[1].setAttribute("selected", "false");

                selectedCells[0] = "";
                selectedCells[1] = "";

                selectedCellNames[0] = "";
                selectedCellNames[1] = "";

                selectedCount = 0;

            }
            else {
                // Something went wrong
                statusString += "<br><b>ERROR: selectedCells out of range!</b>";
            }


        }
        // if already selected de-select
        else {

            temp.animate({ scale: 1, stroke: "#000", 'stroke-width': 2 }, 250, 'elastic').toBack();
            temp.node.setAttribute("selected", "false");
            selectedCount -= 1;

            // Remove the current cell name from our array
            if (selectedCount == 0) {

                selectedCells[0] = "";
                selectedCellNames[0] = "";

            }
            else if (selectedCount == 1) {

                selectedCells[1] = "";
                selectedCellNames[1] = "";

            }
            else {
                // Something went wrong
                statusString += "<br><b>ERROR: selectedCells out of range!</b>";
            }

        }

        // Update the status debugging
        statusString += "<br>(x: " + x.toString() + ", y: " + y.toString() + ") temp.node.getAttribute('selected') after .node.onclick = " + temp.node.getAttribute("selected");
        statusString += "<br>selectedCount = " + selectedCount.toString();
        statusString += "<br>selectedCells[0] = " + selectedCells[0].toString();
        statusString += "<br>selectedCells[1] = " + selectedCells[1].toString();
        $("#status").html(statusString);
        statusString = "";

    }; // end temp.node.onclick        

    return temp;

    /*

    NOTES:

    temp.node.[function] - the node raphael property lets me directly access the DOM element that I just created

    I will need to add all of my onclick and other direct access events for my tiles in this function.
    I will get errors if I try to reference the DOM elements from another part of this program, probably because it is only
    in this function that I actually create the DOM object. Once this function finishes, then the temp object reference is passed 
    back into my initialization loop, where at that point I cannot add any more DOM elements. 

    .animate - Raphael's animation function. Note that the properties that are animated are defined in the first argument,
    between a set of {}. The second argument is the time in milliseconds that the animation will take.

    .toFront() & .toBack() - These functions move the object to the top or bottom of the drawing stack. In other words, if I use 
    toFront on an object, it should be drawn on top of everything else, and vice-versa. This eliminates a graphical issue where the 
    tiles overrlap while expanded.

    .node.setAttribute / .getAttribute(key, value) - These are the DOM functions to set and get attributes of specific DOM elements.
    I am using these instead of .attr(attr, value) because I can't perform jQuery operations on the DOM elements at this point in the script.

    */

} // end drawRect

// Initialize the grid of rectangles
for (var i = 0; i < grid.length; i++) {

    for (var j = 0; j < grid[i].length; j++) {

        cellName = "cell " + i + ":" + j;

        // drawRect(color, x, y, width, height, corner radius)
        grid[i][j] = drawRect(colors[Math.floor(Math.random() * colors.length)], startx + (width * j), starty + (height * i), width, height, cornerRadius);

        // used for debugging
        debugString += "<br>grid[" + i + "][" + j + "] x: " + (startx + (width * j)) + " y: " + (starty + (height * i));

    } // end inner for loop


} // end outer for loop
//交换选项
/*
交换板上已设置为“已选定”的两个平铺(带有动画)。
*/
功能交换选项(toSwap){
var holdX=$(toSwap[0]).attr('x');
var holdY=$(toSwap[0]).attr('y');
//交换前调试
交换前的状态字符串+=“
”; statusString+=”
第一个单元格:“+selectedCellNames[0]; statusString+=”
第二个单元格:“+selectedCellNames[1]; statusString+=“
$(toSwap[0]).attr('x'):”+$(toSwap[0]).attr('x').toString(); statusString+=“
$(toSwap[0]).attr('y'):”+$(toSwap[0]).attr('y').toString(); statusString+=“
$(toSwap[1]).attr('x'):”+$(toSwap[1]).attr('x').toString(); statusString+=“
$(toSwap[1]).attr('y'):”+$(toSwap[1]).attr('y').toString(); statusString+=“
”; /* 这一行使用jQuery SVG获取DOM元素。之所以使用这一行,是因为试图通过 raphael返回了未定义的错误。似乎有一些DOM作用域问题导致我使用这个和temp.node 解决方法是引用通过raphael创建的SVG对象。 什么不起作用:
$(toSwap[0]).animate({x:50,y:100,'笔划宽度':3},250,'绘图变厚:我动态生成的Raphael/SVG对象的“x”和“y”属性在每次单击时都会发生非常小的变化。我不知道为什么会发生这种情况(肯定没有我编写的代码可以做到这一点!)这一定是某种拉斐尔错误。此外,如果我试图访问单元格的“x”或“y”属性,比如说,通过使用[code]debugString++=“
grid[“+I+]”][“+j+”]x:++$(grid[I][j]).attr(“x”)+“y:++$(grid[I][j]).attr(“y”);[/code]我的debugString将打印出“x:undefined y:undefined”因此,我无法在drawRect函数之外访问x或y属性。我不明白为什么我无法获取Raphael对象的x和y属性:a.单击它们时保持不变b.在声明它们的函数之外定义。c.正确更改值(参见上面的第二个屏幕截图)有人能在这方面提供帮助吗?这里是这个项目的完整源文件。我希望有人能在这方面指导我正确的方向,因为我真的被卡住了。你解决了这个问题吗…我正在尝试实现一个类似的交换功能,但被卡住了