首页 > 解决方案 > 用于装箱算法的画布到 SVG 的实现

问题描述

我有一个使用画布的装箱实现。我正在尝试将其转换为 svg 输出而不是画布。

我尝试过使用Canvas2SVG,但无法获得任何输出。

以下是画布的正确工作代码。非常感谢任何指针。

我有点困惑是否所有canvas的方法都可以在SVG绘图中使用

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 = new C2S(Parts.el.canvas.width,Parts.el.canvas.height);

Parts.el.size.change(function() {
	Parts.run(blocks)
});
Parts.el.sort.change(function() {
	Parts.run(blocks)
});

var mySerializedSVG = Parts.el.canvas.getSerializedSvg();

alert(mySerializedSVG)

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 "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];
  }
}

//var blocks = [{"w":500,"h":200,"name":100000},{"w":250,"h":200,"name":50000},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500},{"w":50,"h":50,"name":2500}]

//$(Parts.init(blocks));


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);
}

function getParts(blocks, last) {
  console.log(last)
  var b = [];
  blocks.forEach(function(a) {
    var c = a.dim.split("*");
    if (c[2]) {
      for (var i = 0; i < c[2]; i++) {
        b.push({
          "w": parseInt(c[0]),
          "h": parseInt(c[1]),
          "area": parseInt(c[0]) * parseInt(c[1]),
          'id': b.length + last,
          'name': a.name
        });
      }
    } else b.push({
      "w": parseInt(c[0]),
      "h": parseInt(c[1]),
      "area": parseInt(c[0]) * parseInt(c[1]),
      'id': b.length + last,
      'name': a.name
    });
  });
  return b;
}


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 = [];
    //document.write(JSON.stringify(blocks))
    //document.write("<br>***************<br>")
    //var packer = new Packer(panelWidth, panelHeight);
    var bb = blocks;
    //var bb = sortAllBlocks(blocks, "max");
    //packer.fit(bb);

    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) {
    //document.write("Some of the parts size exceeds!" + blocks.length);
    count = count + blocks.length;
  }
  return count;
}

function abc(W, D, H, T, SHELF_QTY, DRAWER_QTY, CABINETS_QTY) {
  var p = [];

  for (var i = 0; i < CABINETS_QTY; i++) {
    var last = p.length + 1;
    p = p.concat(getParts([{
        "dim": H + "*" + D,
        "name": "Left Side Panel"
      },
      {
        "dim": H + "*" + D,
        "name": "Right Side Panel"
      },
      {
        "dim": W + "*" + D,
        "name": "Bottom"
      },
      {
        "dim": W + "*" + 100 + "*" + 2,
        "name": "Top"
      },
      {
        "dim": W + "*" + H,
        "name": "Back 1"
      },
      {
        "dim": W + "*" + D + "*" + SHELF_QTY,
        "name": "Shelf"
      }
    ], last));
  }
  //document.write(JSON.stringify(p))
  return p;
}

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(abc(w, d, h, t, shelf_qty, drawer_qty, 3), sheet_dim.w, sheet_dim.h))
#canvas {
  background-color: #FBFBFB;
}

#unsupported {
  border: 1px solid red;
  background-color: #FFFFAD;
  padding: 1em;
  margin: 1em;
}

textarea {
  resize: none;
}

select {
  width: 8em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="packing">

  <div id="canvas"></div>
  <div id="desc"></div>
</div>

标签: javascripthtmlsvgcanvas

解决方案


推荐阅读