layout-umd

An improved UMD build of layout

目前为 2025-02-22 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/527730/1541454/layout-umd.js

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.layout = factory());
  5. })(this, (() => {
  6. const binpack = (() => {
  7. class GrowingPacker {
  8. constructor() { }
  9. fit(blocks) {
  10. var n, node, block, len = blocks.length, fit;
  11. var width = len > 0 ? blocks[0].width : 0;
  12. var height = len > 0 ? blocks[0].height : 0;
  13. this.root = { x: 0, y: 0, width: width, height: height };
  14. for (n = 0; n < len; n++) {
  15. block = blocks[n];
  16. if (node = this.findNode(this.root, block.width, block.height)) {
  17. fit = this.splitNode(node, block.width, block.height);
  18. block.x = fit.x;
  19. block.y = fit.y;
  20. }
  21. else {
  22. fit = this.growNode(block.width, block.height);
  23. block.x = fit.x;
  24. block.y = fit.y;
  25. }
  26. }
  27. }
  28. findNode(root, width, height) {
  29. if (root.used)
  30. return this.findNode(root.right, width, height) || this.findNode(root.down, width, height);
  31. else if ((width <= root.width) && (height <= root.height))
  32. return root;
  33. else
  34. return null;
  35. }
  36. splitNode(node, width, height) {
  37. node.used = true;
  38. node.down = { x: node.x, y: node.y + height, width: node.width, height: node.height - height };
  39. node.right = { x: node.x + width, y: node.y, width: node.width - width, height: height };
  40. return node;
  41. }
  42. growNode(width, height) {
  43. var canGrowDown = (width <= this.root.width);
  44. var canGrowRight = (height <= this.root.height);
  45. var shouldGrowRight = canGrowRight && (this.root.height >= (this.root.width + width)); // attempt to keep square-ish by growing right when height is much greater than width
  46. var shouldGrowDown = canGrowDown && (this.root.width >= (this.root.height + height)); // attempt to keep square-ish by growing down when width is much greater than height
  47. if (shouldGrowRight)
  48. return this.growRight(width, height);
  49. else if (shouldGrowDown)
  50. return this.growDown(width, height);
  51. else if (canGrowRight)
  52. return this.growRight(width, height);
  53. else if (canGrowDown)
  54. return this.growDown(width, height);
  55. else
  56. return null; // need to ensure sensible root starting size to avoid this happening
  57. }
  58. growRight(width, height) {
  59. this.root = {
  60. used: true,
  61. x: 0,
  62. y: 0,
  63. width: this.root.width + width,
  64. height: this.root.height,
  65. down: this.root,
  66. right: { x: this.root.width, y: 0, width: width, height: this.root.height }
  67. };
  68. var node;
  69. if (node = this.findNode(this.root, width, height))
  70. return this.splitNode(node, width, height);
  71. else
  72. return null;
  73. }
  74. growDown(width, height) {
  75. this.root = {
  76. used: true,
  77. x: 0,
  78. y: 0,
  79. width: this.root.width,
  80. height: this.root.height + height,
  81. down: { x: 0, y: this.root.height, width: this.root.width, height: height },
  82. right: this.root
  83. };
  84. var node;
  85. if (node = this.findNode(this.root, width, height))
  86. return this.splitNode(node, width, height);
  87. else
  88. return null;
  89. }
  90. }
  91. return (items, options) => {
  92. options = options || {};
  93. var packer = new GrowingPacker();
  94. var inPlace = options.inPlace || false;
  95. var newItems = items.map(item => inPlace ? item : { width: item.width, height: item.height, item: item });
  96. newItems = newItems.toSorted((a, b) => (b.width * b.height) - (a.width * a.height));
  97. packer.fit(newItems);
  98. const ret = {
  99. width: newItems.reduce((curr, item) => Math.max(curr, item.x + item.width), 0),
  100. height: newItems.reduce((curr, item) => Math.max(curr, item.y + item.height), 0)
  101. };
  102. if (!inPlace) {
  103. ret.items = newItems;
  104. }
  105. return ret;
  106. };
  107. })();
  108. const algorithms = {
  109. 'top-down': {
  110. sort: items => items.toSorted((a, b) => a.height - b.height),
  111. placeItems: items => {
  112. let y = 0;
  113. items.forEach(item => {
  114. item.x = 0;
  115. item.y = y;
  116. y += item.height;
  117. });
  118. return items;
  119. }
  120. },
  121. 'left-right': {
  122. sort: items => items.toSorted((a, b) => a.width - b.width),
  123. placeItems: items => {
  124. var x = 0;
  125. items.forEach(item => {
  126. item.x = x;
  127. item.y = 0;
  128. x += item.width;
  129. });
  130. return items;
  131. }
  132. },
  133. diagonal: {
  134. sort: items => items.toSorted((a, b) => {
  135. const aDiag = Math.sqrt(Math.pow(a.height, 2) + Math.pow(a.width, 2));
  136. const bDiag = Math.sqrt(Math.pow(b.height, 2) + Math.pow(b.width, 2));
  137. return aDiag - bDiag;
  138. }),
  139. placeItems: items => {
  140. let x = 0;
  141. let y = 0;
  142. items.forEach(item => {
  143. item.x = x;
  144. item.y = y;
  145. x += item.width;
  146. y += item.height;
  147. });
  148. }
  149. },
  150. 'alt-diagonal': {
  151. sort: items => items.toSorted((a, b) => {
  152. const aDiag = Math.sqrt(Math.pow(a.height, 2) + Math.pow(a.width, 2));
  153. const bDiag = Math.sqrt(Math.pow(b.height, 2) + Math.pow(b.width, 2));
  154. return aDiag - bDiag;
  155. }),
  156. placeItems: items => {
  157. let x = 0;
  158. let y = 0;
  159. items.forEach(item => {
  160. item.x = x - item.width;
  161. item.y = y;
  162. x += item.width;
  163. y += item.height;
  164. });
  165. }
  166. },
  167. 'binary-tree': {
  168. sort: items => items,
  169. placeItems: items => {
  170. binpack(items, {inPlace: true});
  171. return items
  172. }
  173. }
  174. };
  175. class PackingSmith {
  176. constructor(algorithm, options) {
  177. this.items = [];
  178. this.algorithm = algorithm;
  179. options = options || {};
  180. var sort = options.sort !== undefined ? options.sort : true;
  181. this.sort = sort;
  182. }
  183. addItem(item) {
  184. this.items.push(item);
  185. }
  186. normalizeCoordinates() {
  187. var items = this.items;
  188. var minX = Infinity;
  189. var minY = Infinity;
  190. items.forEach(item => {
  191. var coords = item;
  192. minX = Math.min(minX, coords.x);
  193. minY = Math.min(minY, coords.y);
  194. });
  195. items.forEach(item => {
  196. var coords = item;
  197. coords.x -= minX;
  198. coords.y -= minY;
  199. });
  200. }
  201. getStats() {
  202. const { x, y } = this.items.reduce((acc, item) => {
  203. acc.x.min.push(item.x);
  204. acc.y.min.push(item.y);
  205. acc.x.max.push(item.x + item.width);
  206. acc.y.max.push(item.y + item.height);
  207. return acc;
  208. }, {
  209. x: { min: [], max: [] },
  210. y: { min: [], max: [] }
  211. });
  212. return {
  213. minX: Math.max(...x.min),
  214. maxX: Math.max(...x.max),
  215. maxY: Math.max(...y.max),
  216. minY: Math.max(...y.min)
  217. }
  218. }
  219. getItems() {
  220. return this.items;
  221. }
  222. processItems() {
  223. var items = this.items;
  224. if (this.sort) {
  225. items = this.algorithm.sort(items);
  226. }
  227. items = this.algorithm.placeItems(items);
  228. this.items = items;
  229. return items;
  230. }
  231. exportItems() {
  232. this.processItems();
  233. this.normalizeCoordinates();
  234. return this.items;
  235. }
  236. export() {
  237. var items = this.exportItems();
  238. var stats = this.getStats();
  239. var retObj = {
  240. 'height': stats.maxY,
  241. 'width': stats.maxX,
  242. 'items': items
  243. };
  244. return retObj;
  245. }
  246. }
  247. function Layout(algorithmName, options) {
  248. var algorithm = algorithmName || 'top-down';
  249. if (typeof algorithm === 'string') {
  250. algorithm = algorithms[algorithmName];
  251. }
  252. var retSmith = new PackingSmith(algorithm, options);
  253. return retSmith;
  254. }
  255. Layout.PackingSmith = PackingSmith;
  256. function addAlgorithm(name, algorithm) {
  257. algorithms[name] = algorithm;
  258. }
  259. Layout.addAlgorithm = addAlgorithm;
  260. Layout.algorithms = algorithms;
  261. return Layout;
  262. }));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址