Я работаю над графической демонстрацией с использованием RaphaelJS и jQuery.SVG. Прямо сейчас у меня есть динамически созданная сетка прямоугольников 8x8, которую пользователи могут щелкнуть, чтобы выбрать. После того, как два из ритов выбраны, предполагается, что выбранные риты меняются местами друг с другом (как в Bejeweled).
Я дошел до того, что могу получить ректы для обмена, но они не попадают в правильные позиции. Согласно коду, я заменяю координаты x и y каждого выбранного прямоугольника в функции анимации. Ректы всегда заканчиваются тестированием. Визуальный эффект довольно аккуратный, но я действительно хочу, чтобы трюки были в курсе.
http://img407.imageshack.us/img407/2222/raphaelerror.jpg
http://imageshack.us/photo/my-images/593/raphaelerror2.jpg/
Строки отладки, которые я создаю, говорят мне, что положения ректов не изменились. Очевидно, что это не так ... что здесь происходит?
Вот соответствующий код для этой проблемы:
// 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
Я не эксперт по Javascript, поэтому любая помощь будет признательна. Спасибо!