关于 SVG 的事情是它只是 XML。您可以将 SVG 加载到 XML 解析器中并仅获取所需的部分,然后将它们添加到画布或以其他方式独立操作。
我只是为自己当前的项目这样做。该图像是一个简单的国际象棋套装,但我可以将整个国际象棋套装放在一个文件中,包括白色和黑色棋子,然后单独解析它们,这样我就可以调整它们的大小甚至更改它们的颜色。这个 JavaScript 可以使用一些重构,但它应该能让您很好地了解您需要做什么。
loadPieces("images/SimpleStaunton.svg");
loadPieces(fileName) // the file name is a relative path
{
var request = new XMLHttpRequest();
request.open("GET", fileName);
request.setRequestHeader("Content-Type", "image/svg+xml");
var me = this;
request.addEventListener("load", function(event) {
var response = event.target.responseText;
var doc = new DOMParser();
var xml = doc.parseFromString(response, "image/svg+xml");
me.parseChessSets(xml.children[0]);
});
request.send();
}
parseChessSets(xml)
{
this.baseSet = new ChessSet(xml);
}
为了使下一部分工作,我进入 InkScape 并命名每个单独的对象,这样我就可以确切地知道我从 XML 中提取了 SVG 的哪一部分。 (我包括了一个朝左的骑士和一个朝右的骑士,这就是为什么有两个骑士的原因。)因为它们是 SVG,你可以随意给它们上色,所以我只是拉出路径。您可能想做的还不止这些。将 XML 放入 object 后,您将能够更轻松地了解如何执行此操作。
棘手的部分是whitePiece.getAttribute("d"),或者更确切地说xml.children[0].getAttribute("d"),是SVG的路径,一点也不明显。
class ChessSet
{
white = new ChessPieces();
black = new ChessPieces("#fff", "#000");
pieceNames = ["king", "queen", "bishop", "knightl", "knightr", "rook", "pawn"];
constructor (xml)
{
for (var i = 0; i < this.pieceNames.length; i++)
{
var whitePiece = xml.children["white" + this.pieceNames[i]];
if (!whitePiece)
{
continue;
}
var blackPiece = xml.children["black" + this.pieceNames[i]] || whitePiece;
this.white[this.pieceNames[i]] = new SvgImage(whitePiece.getAttribute("d"), whitePiece.style);
this.black[this.pieceNames[i]] = new SvgImage(blackPiece.getAttribute("d"), blackPiece.style);
}
}
class ChessPieces
{
scalePercent = 100; // percentage to shrink king to 90% height of a square
strokeColor;
fillColor;
king;
queen;
bishop;
knightr;
knightl;
rook;
pawn;
constructor(stroke = "#000", fill = "#fff")
{
this.strokeColor = stroke;
this.fillColor = fill;
}
}
class SvgImage
{
transform = {left: 0, down: 0};
pathElement = null;
name = null;
scaleFactor = 1;
strokeWidth = 1;
constructor(path, style)
{
this.path = path;
this.style = style;
}
}
然后我可以画出单独的路径:
var newElement = this.drawPath(set[this.baseSet.pieceNames[i]].name, set[this.baseSet.pieceNames[i]].path, 1, set.strokeColor, set.fillColor);
this.context.appendChild(newElement);
drawPath(id, textPath, strokeWidth = 1, strokeColor = "#000", fill = "none", opacity = 1)
{
var newpath = document.createElementNS(this.svgns, "path");
newpath.setAttributeNS(null, "id", id);
newpath.setAttributeNS(null, "d", textPath);
newpath.setAttributeNS(null, "stroke", strokeColor);
newpath.setAttributeNS(null, "stroke-width", strokeWidth);
newpath.setAttributeNS(null, "opacity", opacity);
newpath.setAttributeNS(null, "fill", fill);
return newpath;
}
变量this.context 是我正在使用的画布DOM。
现在我可以使用 CSS 变换和对象/变量 piece.scaleFactor 来调整片段的大小。我将piece 作为我们之前解析到SVGImage 类中的单个SVG 发送。我发送给Move 的 X 和 Y 坐标是像素。
transformPiece(piece, left, down)
{
if (piece)
{
piece.transform.left = left;
piece.transform.down = down;
piece.pathElement.style.transform = "scale(" + piece.scaleFactor + ") translate(" + piece.transform.left + "px, " + piece.transform.down + "px)";
}
}
movePiece(piece, x, y)
{
if (piece)
{
var left = x / piece.scaleFactor;
var down = y / piece.scaleFactor;
this.transformPiece(piece, left, down);
}
}
需要注意的是,您需要适应原始图像中 SVG 的偏移量。我最终做的是重写 SVG 路径本身的起始坐标。部分需要注意的是,您必须先将图像绘制到画布上,然后才能弄清楚偏移量是多少,因此您最终必须删除原始图像并将新图像添加到画布中,然后才能调用 @987654336 @ 或 transformPiece 并让它在你期望的地方结束。
fixPath(piece, strokeColor, fillColor)
{
if (piece)
{
var box = piece.pathElement.getBoundingClientRect()
var fragments = piece.path.split(" ");
var coords = fragments[1].split(",");
var x = (coords[0] * 1) - box.x - window.scrollX;
var y = (coords[1] * 1) - box.y - window.scrollY;
fragments[1] = x + "," + y;
piece.path = fragments.join(" ");
this.context.removeChild(piece.pathElement);
piece.pathElement = this.drawPath(piece.name, piece.path, 1, strokeColor, fillColor);
this.context.appendChild(piece.pathElement);
}
}
我只花了一两个星期就弄清楚了这一切,以及所有错误的方法。 ;-)
抱歉,这有点复杂。我简化了一点,但我也留下了一堆object 符号和你不关心的属性。我相信您可以根据您的需要大大简化它。大多数情况下,我只是从我的项目中复制并粘贴它,这样我就知道代码正在运行。