我已经编码了一个画布图像,以下代码能够将这些块包装到各种尺寸的给定面板中。我想使用SVG来实现
我尝试使用SVG.js。我不知道SVG。任何指针都很棒。
使用SVG的动机是将图像缩放到任何分辨率。我实际上是在寻找较小的画布图像,但是如果我更改画布的分辨率会降低图像质量。
SVG.js 用于操纵和动画SVG的轻量级库。
为什么选择SVG.js? SVG.js没有依赖关系,其目标是尽可能小,同时提供接近完整的SVG规范覆盖范围。如果您还不确定,这里有一些重点。
<!DOCTYPE HTML>
<html>
<head>
<style>
#canvas { background-color: #FBFBFB; }
#unsupported { border: 1px solid red; background-color: #FFFFAD; padding: 1em; margin: 1em; }
textarea { resize: none; }
select { width: 8em; }
</style>
</head>
<body>
<div id="packing">
<div id="canvas"></div>
<div id="desc"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.7.1/svg.min.js"></script>
<script src='js/demo.js'> </script>
<script>
Packer = function(w, h) {
this.init(w, h);
};
Packer.prototype = {
init: function(w, h) {
this.root = {
x: 0,
y: 0,
w: w,
h: h
};
},
fit: function(blocks) {
var n, node, block;
for (n = 0; n < blocks.length; n++) {
block = blocks[n];
if (node = this.findNode(this.root, block.w, block.h))
block.fit = this.splitNode(node, block.w, block.h);
}
},
findNode: function(root, w, h) {
if (root.used)
return this.findNode(root.right, w, h) || this.findNode(root.down, w, h);
else if ((w <= root.w) && (h <= root.h))
return root;
else
return null;
},
splitNode: function(node, w, h) {
node.used = true;
node.down = {
x: node.x,
y: node.y + h,
w: node.w,
h: node.h - h
};
node.right = {
x: node.x + w,
y: node.y,
w: node.w - w,
h: h
};
return node;
}
}
function sortAllBlocks(blocks, type) {
var func;
switch (type) {
case 'random':
func = function(a, b) {
return Math.random() - 0.5;
};
break;
case 'w':
func = function(a, b) {
return b.w - a.w;
};
break;
case 'h':
func = function(a, b) {
return b.h - a.h;
};
break;
case 'a':
func = function(a, b) {
return b.w * b.h - a.w * a.h;
};
break;
case 'max':
func = function(a, b) {
return Math.max(b.w, b.h) - Math.max(a.w, a.h);
};
break;
case 'min':
func = function(a, b) {
return Math.min(b.w, b.h) - Math.min(a.w, a.h);
};
break;
}
return blocks.sort(func);
}
Parts = {
init: function(blocks, canvasElement) {
Parts.el = {
canvas: canvasElement,
size: $('#size'),
sort: $('#sort'),
ratio: $('#ratio'),
nofit: $('#nofit')
};
var desc = '';
if (!Parts.el.canvas.getContext)
return false;
Parts.el.draw = Parts.el.canvas.getContext("2d");
//SVG('canvas').size(1200, 2400);
Parts.el.size.change(function() {
Parts.run(blocks)
});
Parts.el.sort.change(function() {
Parts.run(blocks)
});
return ( Parts.run(blocks));
},
//---------------------------------------------------------------------------
run: function(blocks) {
var packer = Parts.packer();
Parts.sort.now(blocks);
packer.fit(blocks);
Parts.canvas.reset(packer.root.w, packer.root.h);
Parts.canvas.blocks(blocks);
Parts.canvas.boundary(packer.root);
return (Parts.report(blocks, packer.root.w, packer.root.h));
},
//---------------------------------------------------------------------------
packer: function() {
var size = "1200x2400";
var dims = size.split("x");
return new Packer(parseInt(dims[0]), parseInt(dims[1]));
},
//---------------------------------------------------------------------------
report: function(blocks, w, h) {
var fit = 0, nofit = [], block, n, len = blocks.length;
for (n = 0 ; n < len ; n++) {
block = blocks[n];
if (block.fit)
{
fit = fit + block.area;
}
else
nofit.push("" + block.w + "x" + block.h);
}
return "<br/><br/>Percentage of area utilized: " + (Math.round(100 * fit / (w * h))) + "%<br/>Total used area: " + fit + " mm<sup>2</sup><br/>Wastage area: " + ((w*h) - fit) + " mm<sup>2</sup><br/>";
//Parts.el.nofit.html("Did not fit (" + nofit.length + ") :<br>" + nofit.join(", ")).toggle(nofit.length > 0);
},
//---------------------------------------------------------------------------
sort: {
random : function (a,b) { return Math.random() - 0.5; },
w : function (a,b) { return b.w - a.w; },
h : function (a,b) { return b.h - a.h; },
a : function (a,b) { return b.w*b.h - a.w*a.h; },
max : function (a,b) { return Math.max(b.w, b.h) - Math.max(a.w, a.h); },
min : function (a,b) { return Math.min(b.w, b.h) - Math.min(a.w, a.h); },
height : function (a,b) { return Parts.sort.msort(a, b, ['h', 'w']); },
width : function (a,b) { return Parts.sort.msort(a, b, ['w', 'h']); },
area : function (a,b) { return Parts.sort.msort(a, b, ['a', 'h', 'w']); },
maxside : function (a,b) { return Parts.sort.msort(a, b, ['max', 'min', 'h', 'w']); },
msort: function(a, b, criteria) { /* sort by multiple criteria */
var diff, n;
for (n = 0 ; n < criteria.length ; n++) {
diff = Parts.sort[criteria[n]](a,b);
if (diff != 0)
return diff;
}
return 0;
},
now: function(blocks) {
var sort = "area";
if (sort != 'none')
blocks.sort(Parts.sort[sort]);
}
},
//---------------------------------------------------------------------------
canvas: {
reset: function(width, height) {
Parts.el.canvas.width = width + 1;
Parts.el.canvas.height = height + 1;
Parts.el.draw.clearRect(0, 0, Parts.el.canvas.width, Parts.el.canvas.height);
var color1 = "#ffffff",
color2 = "#d0d0d0";
var numberOfStripes = width;
for (var i = 0; i < numberOfStripes * 2; i++) {
var thickness = 5;
Parts.el.draw.beginPath();
Parts.el.draw.strokeStyle = i % 2 ? color1 : color2;
Parts.el.draw.lineWidth = thickness;
Parts.el.draw.lineCap = 'round';
Parts.el.draw.moveTo(i * thickness + thickness / 2 - Math.max(height,width), 0);
Parts.el.draw.lineTo(0 + i * thickness + thickness / 2, Math.max(height,width));
Parts.el.draw.stroke();
}
Parts.el.draw.lineWidth = 3;
Parts.el.draw.strokeStyle = "#c0c0c0";
Parts.el.draw.strokeRect(0 + 0.5, 0 + 0.5, width, height);
//Parts.el.draw.fillStyle = "gray";
//Parts.el.draw.fillRect(0 + 0.5, 0 + 0.5, width, height);
},
rect: function(x, y, w, h, color, id, name) {
Parts.el.draw.fillStyle = "White";
Parts.el.draw.fillRect(x + 0.5, y + 0.5, w, h);
//Parts.el.draw.font= (w/10) + "px Comic Sans MS";
Parts.el.draw.font = "12px Roboto";
Parts.el.draw.fillStyle = "black";
Parts.el.draw.textAlign = "center";
//Parts.el.draw.fillText(id + "-" + name + " (" + w + "x" + h + ")", x+w/2, y+h/2);
Parts.el.draw.fillText("#" + id + " " + name, x + w / 2, y + h / 2);
Parts.el.draw.fillText(w + " mm", x + w / 2, y + h - 5);
Parts.el.draw.save();
Parts.el.draw.translate(x - w, y + h / 2);
Parts.el.draw.rotate(-90 * Math.PI / 180);
Parts.el.draw.fillText(h + " mm", 0, 0 + w + 15);
Parts.el.draw.restore();
},
stroke: function(x, y, w, h) {
Parts.el.draw.strokeRect(x + 0.5, y + 0.5, w, h);
},
blocks: function(blocks) {
var n, block;
for (n = 0 ; n < blocks.length ; n++) {
block = blocks[n];
if (block.fit)
Parts.canvas.rect(block.fit.x, block.fit.y, block.w, block.h, Parts.color(n), block.id, block.name);
}
},
boundary: function(node) {
if (node) {
Parts.canvas.stroke(node.x, node.y, node.w, node.h);
Parts.canvas.boundary(node.down);
Parts.canvas.boundary(node.right);
}
}
},
colors: {
pastel: [ "#FFF7A5", "#FFA5E0", "#A5B3FF", "#BFFFA5", "#FFCBA5" ],
basic: [ "silver", "gray", "red", "maroon", "yellow", "olive", "lime", "green", "aqua", "teal", "blue", "navy", "fuchsia", "purple" ],
gray: [ "#111", "#222", "#333", "#444", "#555", "#666", "#777", "#888", "#999", "#AAA", "#BBB", "#CCC", "#DDD", "#EEE" ],
vintage: [ "#EFD279", "#95CBE9", "#024769", "#AFD775", "#2C5700", "#DE9D7F", "#7F9DDE", "#00572C", "#75D7AF", "#694702", "#E9CB95", "#79D2EF" ],
solarized: [ "#b58900", "#cb4b16", "#dc322f", "#d33682", "#6c71c4", "#268bd2", "#2aa198", "#859900" ],
none: [ "transparent" ]
},
color: function(n) {
var cols = Parts.colors["none"];
return cols[n % cols.length];
}
}
function getConsumedPanels(blocks, panelWidth, panelHeight)
{
var leftOver = 0;
var count = 0;
while (blocks.length > 0 && leftOver != blocks.length)
{
var leftOver = blocks.length;
var r = [];
toDelete = [];
var bb=blocks;
var newCanvas = $('<canvas/>',{'class':'canvas'});
$("#canvas").append("<div><br/><br/>Panel:"+(count+1)+ " [material name] " + panelWidth + "x" + panelHeight + "<br/></div>");
$("#canvas").append(newCanvas);
$("#canvas").append(Parts.init(bb, $(".canvas")[count]))
bb.forEach(function(o, i)
{
if (o.fit)
{
toDelete.push(i)
}
else; //document.write("Not fit");
});
for (var x = toDelete.length - 1; x >= 0; x--)
{
blocks.splice(toDelete[x], 1);
}
count++;
}
if (leftOver == blocks.length)
{
count = count + blocks.length;
}
return count;
}
var w = 100;
var d = 200;
var h = 300;
var t = 400;
var shelf_qty = 3;
var drawer_qty = 2;
var sheet_dim = {
'w': 2400,
'h': 1200
};
document.write(getConsumedPanels([{
"w": 740,
"h": 580,
"area": 429200,
"id": 1,
"name": "Left Side Panel"
}, {
"w": 740,
"h": 580,
"area": 429200,
"id": 2,
"name": "Right Side Panel"
}, {
"w": 1200,
"h": 580,
"area": 696000,
"id": 3,
"name": "Bottom"
}, {
"w": 1200,
"h": 100,
"area": 120000,
"id": 4,
"name": "Top"
}, {
"w": 1200,
"h": 100,
"area": 120000,
"id": 5,
"name": "Top"
}, {
"w": 1200,
"h": 740,
"area": 888000,
"id": 6,
"name": "Back 1"
}, {
"w": 1200,
"h": 370,
"area": 444000,
"id": 7,
"name": "Back 2"
}, {
"w": 1200,
"h": 580,
"area": 696000,
"id": 8,
"name": "Shelf"
}], sheet_dim.w, sheet_dim.h))
</script>
</body>
</html>