diff --git a/src/@evoposter/evaluator/test/unit/LayoutSemantics.test.js b/src/@evoposter/evaluator/test/unit/LayoutSemantics.test.js new file mode 100644 index 0000000..bb9ea52 --- /dev/null +++ b/src/@evoposter/evaluator/test/unit/LayoutSemantics.test.js @@ -0,0 +1,110 @@ +import {layoutSemantics} from '../../src/index.mjs' + +const TESTING_PARAMS = [ + { + textboxesHeights: [38,38,35.9,36.95,36.95,35.9,36.95,35.9,38,38], + dist: [[1, ['joy'], 0.65, 0.13], [0, [], 0.1, 0.02], [1, ['anticipation'], 0.62, 0.12], [2, ['joy', 'trust'], 1.69, 0.33], [0, [], 0.1, 0.02], [1, ['joy'], 0.83, 0.16], [0, [], 0.1, 0.02], [0, [], 0.1, 0.02], [1, ['joy'], 0.82, 0.16], [0, [], 0.1, 0.02]], + type: `FIXED`, + genotype: {width :300, height:423, margin:[0.05,0.05,0.05,0.05]}, + res: 0.9197241922773838, + valid: true + }, + { + textboxesHeights: [38,38,35.9,36.95,36.95,35.9,36.95,35.9,38,38], + dist: [[1, ['joy'], 0.65, 0.13], [0, [], 0.1, 0.02], [1, ['anticipation'], 0.62, 0.12], [2, ['joy', 'trust'], 1.69, 0.33], [0, [], 0.1, 0.02], [1, ['joy'], 0.83, 0.16], [0, [], 0.1, 0.02], [0, [], 0.1, 0.02], [1, ['joy'], 0.82, 0.16], [0, [], 0.1, 0.02]], + type: `FIXED`, + genotype: {width :300, height:423, margin:[0.05,0.05,0.05,0.05]}, + res: 1, + valid: false + }, + { + textboxesHeights: [61.95,59.9,59.9,59.9,59.9,60.949999999999996], + dist: [[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[1,["trust"],0.85,0.63]], + type: `FIXED`, + genotype: {"width":300,"height":423,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.8480010506960861, + valid: true + }, + { + textboxesHeights: [61.95,58.85,60.949999999999996,59.9,58.85,60.949999999999996], + dist: [[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[1,["trust"],0.85,0.63]], + type: `FIXED`, + genotype: {"width":300,"height":423,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.8484607302337799, + valid: true + }, + { + textboxesHeights: [61.95,58.85,60.949999999999996,59.9,58.85,60.949999999999996], + dist: [[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[1,["trust"],0.85,0.63]], + type: `FIXED`, + genotype: {"width":300,"height":423,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.5, + valid: false + }, + { + textboxesHeights: [123.85000000000001,122.95,119.8], + dist: [[1,["trust"],0.94,0.82],[0,[],0.1,0.09],[0,[],0.1,0.09]], + type: `FIXED`, + genotype: {"width":300,"height":423,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.6825601961299361, + valid: true + }, + { + textboxesHeights: [85.8,81.8,83.89999999999999], + dist: [[1,["trust"],0.94,0.82],[0,[],0.1,0.09],[0,[],0.1,0.09]], + type: `FIXED`, + genotype: {"width":300,"height":300,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.6880246913580248, + valid: true + }, + { + textboxesHeights: [34.95,35,33.949999999999996], + dist: [[1,["trust"],0.94,0.82],[0,[],0.1,0.09],[0,[],0.1,0.09]], + type: `FIXED`, + genotype: {"width":300,"height":120,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.6817283950617284, + valid: true + }, + { + textboxesHeights: [76,72.85000000000001,74.95,73.9,76], + dist: [[1,["trust"],0.85,0.3],[0,[],0.1,0.04],[0,[],0.1,0.04],[0,[],0.1,0.04]], + type: `RELATIVE`, + genotype: {"width":300,"height":423,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.8575287663901525, + valid: true + }, + { + textboxesHeights: [145.70000000000002,144.95,146,144.95,146], + dist: [[1,["trust"],0.85,0.3],[0,[],0.1,0.04],[0,[],0.1,0.04],[0,[],0.1,0.04]], + type: `RELATIVE`, + genotype: {"width":300,"height":846,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.8061224060940373, + valid: false + }, + { + textboxesHeights: [145.70000000000002,144.95,146,144.95,146], + dist: [[1,["trust"],0.85,0.3],[0,[],0.1,0.04],[0,[],0.1,0.04],[0,[],0.1,0.04]], + type: `RELATIVE`, + genotype: {"width":300,"height":846,"margin":[0.05,0.05,0.05,0.05]}, + res: 0.9, + valid: false + } +] + +describe(`Testing Layout Semantics metric`, () => { + for (let i in TESTING_PARAMS) { + let params = TESTING_PARAMS[i]; + test(`Test ${i}`, async () => { + const res = layoutSemantics( + params.textboxesHeights, params.dist, + params.type, params.genotype + ); + + if (params.valid) { + expect(res).toBe(params.res); + } else { + expect(res).not.toBe(params.res); + } + }); + } +}); diff --git a/src/@evoposter/evaluator/test/unit/VisualSemantics.test.js b/src/@evoposter/evaluator/test/unit/VisualSemantics.test.js new file mode 100644 index 0000000..5c8370b --- /dev/null +++ b/src/@evoposter/evaluator/test/unit/VisualSemantics.test.js @@ -0,0 +1,78 @@ +import {visualSemantics} from '../../src/index.mjs' + +const TESTING_PARAMS = [ + { + textboxes: [{"content":"A friend","weight":188,"font-stretch":312,"alignment":2,"size":57,"typeface":"Barlow","color":"#82f295","uppercase":false},{"content":"is someone","weight":641,"font-stretch":125,"alignment":2,"size":56.14285714285714,"typeface":"Amstelvar","color":"#82f295","uppercase":false},{"content":"who knows","weight":559,"font-stretch":125,"alignment":2,"size":57.14285714285714,"typeface":"Amstelvar","color":"#82f295","uppercase":false},{"content":"all about you","weight":871,"font-stretch":97,"alignment":3,"size":56.14285714285714,"typeface":"Anybody","color":"#82f295","uppercase":false},{"content":"and still","weight":100,"font-stretch":100,"alignment":2,"size":54.14285714285714,"typeface":"Emberly","color":"#82f295","uppercase":false},{"content":"loves you","weight":275,"font-stretch":200,"alignment":1,"size":54.14285714285714,"typeface":"Inconsolata","color":"#82f295","uppercase":false}], + dist: [[1,["trust"],0.85,0.29],[0,[],0.1,0.03],[0,[],0.1,0.03],[0,[],0.1,0.03],[0,[],0.1,0.03],[2,["joy","trust"],1.69,0.57]], + noTypefaces: 8, + res: 0.6198543565131808, + valid: true, + }, + { + textboxes: [{"content":"To live","weight":741,"font-stretch":100,"alignment":3,"size":57,"typeface":"Emberly","color":"#85285c","uppercase":false},{"content":"is the rarest thing","weight":849,"font-stretch":200,"alignment":2,"size":54.14285714285714,"typeface":"Inconsolata","color":"#85285c","uppercase":false},{"content":"in the world.","weight":451,"font-stretch":125,"alignment":2,"size":57.14285714285714,"typeface":"Amstelvar","color":"#85285c","uppercase":false},{"content":"Most people","weight":199,"font-stretch":100,"alignment":2,"size":54.14285714285714,"typeface":"Epilogue","color":"#85285c","uppercase":false},{"content":"exist,","weight":570,"font-stretch":100,"alignment":2,"size":57.14285714285714,"typeface":"Emberly","color":"#85285c","uppercase":false},{"content":"that is all.","weight":128,"font-stretch":100,"alignment":3,"size":55.14285714285714,"typeface":"Cabin","color":"#85285c","uppercase":false}], + dist: [[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17]], + noTypefaces: 8, + res: 0.7999999999999999, + valid: true, + }, + { + textboxes: [{"content":"To live","weight":720,"font-stretch":230,"alignment":2,"size":59,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"is the rarest thing","weight":761,"font-stretch":242,"alignment":1,"size":56.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"in the world.","weight":400,"font-stretch":400,"alignment":3,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"Most people","weight":398,"font-stretch":68,"alignment":2,"size":58.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"exist,","weight":607,"font-stretch":400,"alignment":1,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"that is all.","weight":201,"font-stretch":400,"alignment":1,"size":57.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false}], + dist: [[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17]], + noTypefaces: 1, + res: 0.7, + valid: true, + }, + { + textboxes: [{"content":"To live","weight":720,"font-stretch":230,"alignment":2,"size":59,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"is the rarest thing","weight":761,"font-stretch":242,"alignment":1,"size":56.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"in the world.","weight":400,"font-stretch":400,"alignment":3,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"Most people","weight":398,"font-stretch":68,"alignment":2,"size":58.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"exist,","weight":607,"font-stretch":400,"alignment":1,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"that is all.","weight":201,"font-stretch":400,"alignment":1,"size":57.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false}], + dist: [[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17]], + noTypefaces: 1, + res: 1, + valid: false, + }, + { + textboxes: [{"content":"To live","weight":720,"font-stretch":230,"alignment":2,"size":59,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"is the rarest thing","weight":761,"font-stretch":242,"alignment":1,"size":56.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"in the world.","weight":400,"font-stretch":400,"alignment":3,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"Most people","weight":398,"font-stretch":68,"alignment":2,"size":58.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"exist,","weight":607,"font-stretch":400,"alignment":1,"size":59.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false},{"content":"that is all.","weight":201,"font-stretch":400,"alignment":1,"size":57.047619047619044,"typeface":"Anybody","color":"#f5eeda","uppercase":false}], + dist: [[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17],[0,[],0.1,0.17]], + noTypefaces: 1, + res: 0.7, + valid: true, + }, + { + textboxes: [{"content":"Always forgive","weight":687,"font-stretch":307,"alignment":1,"size":71.38095238095238,"typeface":"Anybody","color":"#4c9ecb","uppercase":false},{"content":"your enemies;","weight":128,"font-stretch":100,"alignment":2,"size":69.42857142857143,"typeface":"Cabin","color":"#4c9ecb","uppercase":false},{"content":"nothing annoys","weight":128,"font-stretch":13,"alignment":3,"size":70.42857142857143,"typeface":"Cabin","color":"#4c9ecb","uppercase":false},{"content":"them","weight":634,"font-stretch":85,"alignment":2,"size":71.42857142857143,"typeface":"IBMPlexSans","color":"#4c9ecb","uppercase":false},{"content":"so much.","weight":488,"font-stretch":100,"alignment":2,"size":68.42857142857143,"typeface":"IBMPlexSans","color":"#4c9ecb","uppercase":false}], + dist: [[1,["trust"],0.65,0.19],[3,["anger","fear","disgust"],1.9600000000000002,0.57],[1,["anger"],0.62,0.18],[0,[],0.1,0.03],[0,[],0.1,0.03]], + noTypefaces: 8, + res: 0.5757079035152126, + valid: true, + }, + { + textboxes: [{"content":"Live as","weight":688,"font-stretch":400,"alignment":2,"size":49.42857142857142,"typeface":"Anybody","color":"#f579f7","uppercase":false},{"content":"if you were","weight":188,"font-stretch":308,"alignment":1,"size":47.52380952380952,"typeface":"Barlow","color":"#f579f7","uppercase":false},{"content":"to die tomorrow.","weight":287,"font-stretch":200,"alignment":2,"size":49.52380952380952,"typeface":"Inconsolata","color":"#f579f7","uppercase":false},{"content":"Learn as if","weight":860,"font-stretch":254,"alignment":3,"size":48.52380952380952,"typeface":"Anybody","color":"#f579f7","uppercase":false},{"content":"you were","weight":700,"font-stretch":100,"alignment":1,"size":48.52380952380952,"typeface":"IBMPlexSans","color":"#f579f7","uppercase":false},{"content":"to live","weight":719,"font-stretch":125,"alignment":3,"size":48.52380952380952,"typeface":"Amstelvar","color":"#f579f7","uppercase":false},{"content":" forever","weight":188,"font-stretch":300,"alignment":3,"size":48.52380952380952,"typeface":"Barlow","color":"#f579f7","uppercase":false}], + dist: [[0,[],0.1,0.07],[0,[],0.1,0.07],[1,["anticipation"],0.75,0.56],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07]], + noTypefaces: 8, + res: 0.6432108843537415, + valid: true, + }, + { + textboxes: [{"content":"Live as","weight":688,"font-stretch":400,"alignment":2,"size":49.42857142857142,"typeface":"Anybody","color":"#f579f7","uppercase":false},{"content":"if you were","weight":188,"font-stretch":308,"alignment":1,"size":47.52380952380952,"typeface":"Barlow","color":"#f579f7","uppercase":false},{"content":"to die tomorrow.","weight":287,"font-stretch":200,"alignment":2,"size":49.52380952380952,"typeface":"Inconsolata","color":"#f579f7","uppercase":false},{"content":"Learn as if","weight":860,"font-stretch":254,"alignment":3,"size":48.52380952380952,"typeface":"Anybody","color":"#f579f7","uppercase":false},{"content":"you were","weight":700,"font-stretch":100,"alignment":1,"size":48.52380952380952,"typeface":"IBMPlexSans","color":"#f579f7","uppercase":false},{"content":"to live","weight":719,"font-stretch":125,"alignment":3,"size":48.52380952380952,"typeface":"Amstelvar","color":"#f579f7","uppercase":false},{"content":" forever","weight":188,"font-stretch":300,"alignment":3,"size":48.52380952380952,"typeface":"Barlow","color":"#f579f7","uppercase":false}], + dist: [[0,[],0.1,0.07],[0,[],0.1,0.07],[1,["anticipation"],0.75,0.56],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07],[0,[],0.1,0.07]], + noTypefaces: 8, + res: 0.8, + valid: false, + } +]; + + +describe(`Testing Visual Semantics metric`, () => { + for (let i in TESTING_PARAMS) { + let params = TESTING_PARAMS[i]; + test(`Test ${i}`, async () => { + const res = visualSemantics( + params.textboxes, params.dist, params.noTypefaces + ); + + if (params.valid) { + expect(res).toBe(params.res); + } else { + expect(res).not.toBe(params.res); + } + }); + } +}); diff --git a/src/client/controllers/Poster.js b/src/client/controllers/Poster.js index 3a1d15b..5f3080e 100644 --- a/src/client/controllers/Poster.js +++ b/src/client/controllers/Poster.js @@ -232,7 +232,13 @@ class Poster { const justification = evaluator.legibility(this.sentencesLenght, this.genotype["grid"].getAvailableWidth(), `JUSTIFY`); // this.fitness = layoutSemantics; - this.fitness = (visualSemantics * 0.3 + layoutSemantics * 0.3 + justification * 0.4); + // this.fitness = (visualSemantics * 0.3 + layoutSemantics * 0.3 + justification * 0.4); + this.fitness = visualSemantics; + + console.group(); + console.log(JSON.stringify(this.genotype["textboxes"]), JSON.stringify(dist), JSON.stringify(noCurrentTypefaces)); + console.log("visualSemantics", visualSemantics); + console.groupEnd(); // constraints const legibility = evaluator.legibility(this.sentencesLenght, this.genotype["grid"].getAvailableWidth(), `OVERSET`); diff --git a/src/public/app.js b/src/public/app.js index 5c66170..30a316b 100644 --- a/src/public/app.js +++ b/src/public/app.js @@ -339,7 +339,7 @@ const ae=2;class le{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,r) `:U}
- `}createRenderRoot(){return this}}customElements.define("header-section",Me);var Te={solid:(e,t)=>{e.background(t)},gradient:(e,t,r)=>{push();const o=e.drawingContext;e.background(t);let s=e.height;const n=o.createLinearGradient(0,0,0,s);n.addColorStop(0,t),n.addColorStop(.25,t),n.addColorStop(.75,r),n.addColorStop(1,r),o.fillStyle=n,o.fillRect(0,0,e.width,s),pop()},triangle:(e,t,r)=>{push(),e.background(t),e.noStroke(),e.fill(r),e.triangle(0,0,0,e.height,e.width,e.height),pop()}};const Ce=(e,t,r,o,s)=>o+(e-t)/(r-t)*(s-o),Ae=(e,t,r)=>Math.min(r,Math.max(t,e)),ke=e=>{const t=e.reduce(((e,t)=>e+t),0);return t/e.length||0},Oe=e=>e.reduce(((e,t)=>e+t),0),Le=e=>Math.max(...e),Pe=e=>Math.min(...e),Re=(e,t)=>Ce(e=(e=e>=0?0:e)<=-t?-t:e,-t,0,1,0),Ie=(e,t)=>(e=Math.abs(e),Ce(e=e>t?t:e,t,0,1,0)),De=(e,t)=>Ie(e=e>=0?e/3:e,t);const Fe=(e,t)=>{const r=t.filter(((e,t,r)=>r.indexOf(e)===t)),o=[];for(let s of r)for(let r=0;ro.indexOf(e)!==t)).length>=1){let n=0;for(let s in t){let i=t[s],a=e[s],l=r.indexOf(i);a!==o[l]&&n++}s=Ce(n,0,e.length,0,1)}return s},Ne=(e,t,r="DIF")=>{"MIN"!==r&&"DIF"!==r&&(r="DIF");const o=Le(e),s=Pe(e);let n=Math.abs(o-s);if(n<50)return 1;const i=Le(t),a=Pe(t);let l=s;if("DIF"===r)for(let r in t)if(t[r]===a){l=e[r];break}const c=t.map((e=>{let t=Ce(e,a,i,0,n);return t=Ae(t,0,n),t})),u=[];for(let t in e){let r=e[t],o=Math.abs(r-l),s=Math.abs(o-c[t]);u.push(s)}let d=Ce(ke(u),0,n,1,0);return Ae(d,0,1)},Ue=(e=[],t,r="OVERSET",o=1)=>{let s=[],n=t*o;for(let o of e){let e=t-o,i=1;switch(r){case"JUSTIFY":i=Ie(e,n);break;case"ATTEMPT_JUSTIFY":i=De(e,n);break;default:i=Re(e,n)}s.push(i)}return ke([...s])},Be=(e,t,r=[],o=[],s={left:0,top:0,right:0,bottom:0})=>{let n=!1,i="",a=Math.abs(s.top)+Math.abs(s.bottom);for(let e of r)a+=parseFloat(e);let l=Math.abs(s.left)+Math.abs(s.right);for(let e of o)l+=parseFloat(e);return l=Math.round(l),a=Math.round(a),a>t?(n=!0,i+=`Grid height is bigger than container (grid:${a}, container:${t}). `):ae?(n=!0,i+=`Grid width is bigger than container (grid:${l}, container:${e}). `):l{"RELATIVE"!==r&&"FIXED"!==r&&(r="RELATIVE");let s=0;"RELATIVE"===r?s=Oe(e):"FIXED"===r&&(s=o.height-(o.height*o.margin[1]+o.height*o.margin[3]));const n=e.map((e=>e/s));let i=[];for(let e in t){const r=Math.abs(t[e][3]-n[e]);i.push(r)}return 1-ke(i)},ze=(e,t,r=1,o=!0,s=[.4,.3,.3])=>{const n=t.map((e=>e[3]));let i,a=[Ne(e.map((e=>e.weight)),n),Ne(e.map((e=>e["font-stretch"])),n),r>1?Fe(e.map((e=>e["font-stretch"])),n):0],l=a.map(((e,t)=>e*s[t]));if(o)i=Oe(l);else{let e=a.map((e=>e>.2)),t=0;for(let r of e)r&&t++;i=Le(a)/t}return i};function Ve(e,t,r){return Math.max(t,Math.min(e,r))}function $e(e){return(e%360+360)%360}function He(e){var t,r;return $e(function(e,t){var r;return e*(null!==(r={rad:180/Math.PI,grad:.9,turn:360}[t.toLowerCase()])&&void 0!==r?r:1)}(parseFloat(e),null!==(r=null===(t=e.match(/deg|rad|grad|turn/i))||void 0===t?void 0:t[0])&&void 0!==r?r:"deg"))}function qe(e){return new RegExp(`^${e.source}$`,e.flags)}function We(e){return e.slice(1).filter((e=>void 0!==e))}const Xe=/[+-]?(?=\.\d|\d)\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/,Ye=/(?=[,\s])\s*(?:,\s*)?/,Ze=/\s*[,\/]\s*/,Je=Xe.source,Qe=Ye.source,Ke=new RegExp(`hsla?\\(\\s*(${Je}(?:deg|rad|grad|turn)?)${Qe}(${Je})%${Qe}(${Je})%(?:${Ze.source}(${Je}%?))?\\s*\\)`,"i");const et={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aqua:"#00FFFF",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blue:"#0000FF",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",fuchsia:"#FF00FF",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",goldenrod:"#DAA520",gold:"#FFD700",gray:"#808080",green:"#008000",greenyellow:"#ADFF2F",grey:"#808080",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavenderblush:"#FFF0F5",lavender:"#E6E6FA",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgray:"#D3D3D3",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",lime:"#00FF00",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",maroon:"#800000",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",navy:"#000080",oldlace:"#FDF5E6",olive:"#808000",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",purple:"#800080",rebeccapurple:"#663399",red:"#FF0000",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",silver:"#C0C0C0",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",teal:"#008080",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",white:"#FFFFFF",whitesmoke:"#F5F5F5",yellow:"#FFFF00",yellowgreen:"#9ACD32"};const tt=/[0-9a-fA-F]/.source,rt=new RegExp(`#(${tt}{2})(${tt}{2})(${tt}{2})(${tt}{2})?`),ot=new RegExp(`#(${tt})(${tt})(${tt})(${tt})?`);const st=Xe.source,nt=Ye.source,it=new RegExp(`rgba?\\(\\s*(${st}%?)${nt}(${st}%?)${nt}(${st}%?)(?:${Ze.source}(${st}%?))?\\s*\\)`,"i");function at(e){return{r:Ve(e.r,0,255),g:Ve(e.g,0,255),b:Ve(e.b,0,255),a:Ve(e.a,0,1)}}function lt(e){if("transparent"===(e=e.trim()).toLowerCase())return{r:0,g:0,b:0,a:0};const t=et[e.toLowerCase()];let r;return t&&(e=t),null!==(r=function(e){var t;const r=null!==(t=qe(rt).exec(e))&&void 0!==t?t:qe(ot).exec(e);return r?We(r):null}(e))?function(e){var t;const r=e.map((e=>(1===e.length&&(e=`${e}${e}`),parseInt(e,16)))),o=(null!==(t=r[3])&&void 0!==t?t:255)/255;return{r:r[0],g:r[1],b:r[2],a:o}}(r):null!==(r=function(e){const t=qe(it).exec(e);return t?We(t):null}(e))?function(e){var t;const r=e.map(((e,t)=>{let r=parseFloat(e);return e.indexOf("%")>-1&&(r*=.01,t<3&&(r*=255)),r}));return at({r:r[0],g:r[1],b:r[2],a:null!==(t=r[3])&&void 0!==t?t:1})}(r):null}function ct(e){return{h:$e(e.h),s:Ve(e.s,0,100),l:Ve(e.l,0,100),a:Ve(e.a,0,1)}}function ut(e){const t=lt(e);return t?function(e){const{r:t,g:r,b:o,a:s}=at(e),n=t/255,i=r/255,a=o/255,l=Math.max(n,i,a),c=Math.min(n,i,a),u=l-c,d=(c+l)/2;let h=NaN,p=0;if(0!==u){switch(p=(l-d)/Math.min(d,1-d),l){case n:h=(i-a)/u+(iparseFloat(e)));let s=null!==(t=o[3])&&void 0!==t?t:1;return(null===(r=e[3])||void 0===r?void 0:r.indexOf("%"))>-1&&(s*=.01),ct({h:He(e[0]),s:o[1],l:o[2],a:s})}(t):null}function ht(e){return`rgba(${(e=function(e){return{r:Math.round(e.r),g:Math.round(e.g),b:Math.round(e.b),a:e.a}}(e)).r}, ${e.g}, ${e.b}, ${e.a})`}function pt(e){const t=function(e){return"number"==typeof e.h&&"number"==typeof e.s&&"number"==typeof e.l&&"number"==typeof e.a}(e)?function(e){const{h:t,s:r,l:o,a:s}=ct(e),n=t||0,i=r/100,a=o/100;function l(e){const t=(e+n/30)%12,r=i*Math.min(a,1-a);return a-r*Math.max(-1,Math.min(t-3,9-t,1))}return{r:255*l(0),g:255*l(8),b:255*l(4),a:s}}(e):at(e);return 1===t.a?function(e){const t=(((255&Math.round(e.r))<<16)+((255&Math.round(e.g))<<8)+(255&Math.round(e.b))).toString(16).toUpperCase();return`#${"000000".substring(t.length)}${t}`}(t):ht(t)}var ft=(e,t)=>{if("number"!=typeof t||0===t)return e;const r=function(e){var t;const r=null!==(t=dt(e))&&void 0!==t?t:ut(e);if(null===r)throw new Error("Invalid color string");return r}(e),o=(r.h+t)%360;return pt(Object.assign(Object.assign({},r),{h:o}))};var mt=(e,t)=>"number"!=typeof t||0===t?e:ft(e,30*t);var yt=(e,t)=>{if("number"!=typeof t||0===t)return e;let r=0,o=t<0?-1:1,s=0;for(;s!==t;)s+=o,r+=s%2!=0?180*o:30*o;return ft(e,r)};const gt=()=>{const e=bt();return vt(e)},vt=e=>{const t=yt(e,1);return{baseColour:e,colorA:t,colorB:mt(t,Math.round(4*Math.random()-2))}},bt=()=>{const e=[Math.round(255*Math.random()),Math.round(255*Math.random()),Math.round(255*Math.random())].map((e=>e.toString(16).padStart(2,"0")));return`#${e.join("")}`};class _t{#d=!1;#h=!1;constructor(e,t,r=null,o=null){this.id=`${t}-${e}`,this.n=e,this.generation=t,this.ready=!1,this.params=JSON.parse(JSON.stringify(r)),this.fitness=1,this.constraint=0,this.metrics={legibility:1,gridAppropriateness:1},this.sentencesLenght=[];const s=null===o?r.size.height:o.size.height;this.maxFontSize=se.typography.maxSize*s,this.minFontSize=se.typography.minSize*s,this.genotype=null===o?this.#p(r):o,this.#d=null!==r&&r.display.grid,this.phenotype=null}copy=()=>{const e=this.genotype.grid,t=new xt(JSON.parse(JSON.stringify(e.size)),JSON.parse(JSON.stringify(e.v)),JSON.parse(JSON.stringify(e.h)),JSON.parse(JSON.stringify(e.defaultMargins)),JSON.parse(JSON.stringify(e.gwper)),JSON.parse(JSON.stringify(e.ghper))),r=JSON.parse(JSON.stringify(this.genotype.size)),o=JSON.parse(JSON.stringify(this.genotype.textboxes));for(let e in o)o[e].color=color(this.genotype.textboxes[e].color);const s=JSON.parse(JSON.stringify(this.genotype.background));s.colors[0]=color(this.genotype.background.colors[0]),s.colors[1]=color(this.genotype.background.colors[1]);let n=[];for(let e of this.genotype.images){const t={scale:e.scale,src:e.src,x:e.x,y:e.y};n.push(t)}const i={grid:t,textboxes:o,size:r,background:s,typography:JSON.parse(JSON.stringify(this.genotype.typography)),images:n};return new _t(this.n,this.generation,this.params,i)};#p=e=>{const t=gt(),r=new xt({width:e.size.width,height:e.size.height,margin:e.size.margin},2,e.sentences.length,JSON.parse(JSON.stringify(e.size.margin))),o=[],s=0===e.typography.verticalAlignment?Math.round(Math.random()*(se.textAlignmentOptions.length-2)+1):e.typography.verticalAlignment;for(let n in e.sentences){const i=e.sentences[n],a=Math.round(Math.random()*(e.typography.typefaces.length-1));let l=e.typography.typefaces[a].stretch;l.map((e=>isNaN(e)?100:parseInt(e))),l.length<2&&l.push(100);let c=e.typography.typefaces[a].weight,u=Math.round(Math.random()*(e.typography.weight.max-e.typography.weight.min)+e.typography.weight.min);u=Math.max(c[0],Math.min(u,c[1]));let d=Math.round(Math.random()*(e.typography.stretch.max-e.typography.stretch.min)+e.typography.stretch.min);d=Math.max(l[0],Math.min(d,l[1]));const h=se.availableTypefacesInfo[se.availableTypefaces[a]].leading;let p=Math.round(r.rows.l[0])/h;p+=Math.round(-p*se.typography.range+Math.random()*(p*se.typography.range)),p=Math.max(Math.round(e.size.height*se.typography.minSize),Math.min(Math.round(e.size.height*se.typography.maxSize),p)),r.defineRow(n,p*h,s);const f=0===e.typography.textAlignment?Math.round(Math.random()*(se.textAlignmentTbOptions.length-2)+1):e.typography.textAlignment;o.push({content:i,weight:u,"font-stretch":d,alignment:f,size:p,typeface:e.typography.typefaces[a].family,color:e.typography.color.random?t.baseColour:color(e.typography.color.value),uppercase:e.typography.uppercase})}const n=[];for(let t of e.images){const r=t.src,o=loadImage(r,(async t=>{await t.resize(0,e.size.height),t.ready=!0}));n.push({x:Math.random(),y:Math.random(),scale:Math.random(),src:o})}return{grid:r,textboxes:o,size:{width:e.size.width,height:e.size.height,margin:e.size.margin},background:{style:0===e.background.style?Math.round(1+Math.random()*(se.background.availableStyles.length-2)):e.background.style,colors:[e.background.color.random?t.colorA:color(e.background.color.valueA),e.background.color.random?t.colorB:color(e.background.color.valueB)]},typography:{verticalAlignment:s},images:n}};draw=async()=>{this.ready=!0,this.phenotype=createGraphics(this.genotype.size.width,this.genotype.size.height),this.phenotype.id=this.n;const e=Object.keys(Te)[this.genotype.background.style-1];return(0,Te[e])(this.phenotype,this.genotype.background.colors[0],this.genotype.background.colors[1]),this.ready=await this.#f(this.phenotype),await this.typeset(this.phenotype),this.#h&&(pg.textSize(10),pg.fill(0),pg.text(`${this.id}+${this.genotype.typography.verticalAlignment}+style=${this.genotype.background.style}\nfitness=${this.fitness}`,20,20)),(this.#d||this.#h)&&this.genotype.grid.display(this.phenotype),this.phenotype};evaluate=async e=>{this.phenotype=await this.draw();const t=this.params.typography.typefaces.length,r=Ge(this.genotype.grid.rows.l,e,"FIXED",this.genotype.size),o=ze(this.genotype.textboxes,e,t),s=Ue(this.sentencesLenght,this.genotype.grid.getAvailableWidth(),"JUSTIFY");this.fitness=.3*o+.3*r+.4*s;const n=Ue(this.sentencesLenght,this.genotype.grid.getAvailableWidth(),"OVERSET"),i=Be(this.genotype.size.width,this.genotype.size.height,this.genotype.grid.rows.l,this.genotype.grid.columns.l,this.genotype.grid.marginsPos);return this.constraint=n+i,this.metrics.legibility=n,this.metrics.gridAppropriateness=i,{fitness:this.fitness,constraints:this.constraint}};typeset=async e=>{this.sentencesLenght=[],e.push(),e.translate(e.width/2,e.height/2);const t=e.drawingContext;for(let r in this.genotype.textboxes){const o=this.genotype.textboxes[r];let s=o.alignment,n=LEFT;2===s?n=CENTER:3===s&&(n=RIGHT),e.textAlign(n,BASELINE);let i=this.genotype.grid.col(s-1,!1),a=this.genotype.grid.row(parseInt(r)+1,!1);e.fill(o.color),t.font=`${o.weight} ${wt(o["font-stretch"])} ${o.size}px ${o.typeface}`,drawingContext.font=`${o.weight} ${wt(o["font-stretch"])} ${o.size}px ${o.typeface}`;let l=!0===o.uppercase?o.content.toUpperCase():o.content;e.text(l,i,a);const c=t.measureText(l).width;this.sentencesLenght.push(c)}e.pop()};#f=async e=>{let t=!0;for(let r of this.genotype.images)if(void 0!==r.src&&r.src.hasOwnProperty("ready")){if(r.src.ready){let t=e.width*r.x,o=e.height*r.y;e.imageMode(CENTER),e.image(r.src,t,o,r.src.width*r.scale,r.src.height*r.scale)}}else t=!1;return t};toggleGrid=(e=null)=>{null===e&&(e=!this.#d),this.#d=e,this.draw()}}const wt=e=>e>-10&&e<=50?"ultra-condensed":e>50&&e<=62.5?"extra-condensed":e>62.5&&e<=75?"condensed":e>75&&e<=87.5?"semi-condensed":e>87.5&&e<=100?"normal":e>100&&e<=112.5?"semi-expanded":e>112.5&&e<=125?"expanded":e>125&&e<=150?"extra-expanded":"ultra-expanded";class xt{constructor(e,t=12,r=24,o,s=.03,n=null){null===n&&(n=s),this.pos=createVector(e.width/2,e.height/2),this.size=JSON.parse(JSON.stringify(e)),this.defaultMargins=o,this.v=t,this.h=r,this.gwper=s,this.ghper=n,this.gapw=this.size.width*this.gwper,this.gaph=this.size.height*this.ghper,this.regular=!0,this.verticalSpace=[],this.marginsPos={},this.columns={},this.columns.y={},this.columns.center={},this.columns.gap={},this.rows={},this.rows.x={},this.rows.center={},this.rows.gap={},this.def()}export=()=>({pos:[this.pos.x,this.pos.y,this.pos.z],size:this.size,defaultMargins:this.defaultMargins,v:this.v,h:this.h,gapw:this.gapw,gaph:this.gaph,marginsPos:this.marginsPos,columns:this.columns,rows:this.rows});copy=()=>new xt(JSON.parse(JSON.stringify(this.size)),JSON.parse(JSON.stringify(this.v)),JSON.parse(JSON.stringify(this.h)),JSON.parse(JSON.stringify(this.defaultMargins)),JSON.parse(JSON.stringify(this.gwper)),JSON.parse(JSON.stringify(this.ghper)));updateMarginsBasedOnSize=(e=0,t=1,r,o=this.size.height)=>{const s=t*r;let n=this.size.height-s;0===e&&(n/=2),(0===e||1===e)&&this.size.margin[1]{0===e&&(t/=2),(0===e||1===e)&&this.size.margin[1]{this.size.margin=this.defaultMargins,this.marginsPos.left=this.size.margin[0]*this.size.width,this.marginsPos.top=this.size.margin[1]*this.size.height,this.marginsPos.right=this.size.margin[2]*this.size.width,this.marginsPos.bottom=this.size.margin[3]*this.size.height,this.def()};def=()=>{this.#m(),this.#y(),this.#g()};update=(e=null,t=null)=>{null!==e&&e!==this.v&&console.log(`grid updated from ${this.v} to ${e}`)};defineRow=(e,t,r)=>{this.regular=!1;const o=this.rows.l[e];this.rows.l[e]=t;let s=this.rows.l[e]-o;s=2===r?s/2:s,this.marginsPos.bottom,this.size.height,r<=2&&(this.size.margin[3]=(this.marginsPos.bottom-s)/this.size.height),r>=2&&(this.size.margin[1]=(this.marginsPos.top-s)/this.size.height),this.def()};#m=()=>{this.marginsPos.left=this.size.margin[0]*this.size.width,this.marginsPos.top=this.size.margin[1]*this.size.height,this.marginsPos.right=this.size.margin[2]*this.size.width,this.marginsPos.bottom=this.size.margin[3]*this.size.height};getSpace=()=>{const e=this.rows.l.reduce(((e,t)=>e+t),0)/this.rows.l.length;return{centre:{col:this.columns.l,row:e},gap:{col:this.columns.l-this.gapw/2,row:e-this.gaph/2}}};#y=()=>{this.columns.y.top=-this.size.height/2+this.marginsPos.top,this.columns.y.bottom=this.size.height/2-this.marginsPos.bottom;const e=(this.size.width-(this.marginsPos.left+this.marginsPos.right))/this.v;let t=[];for(let r=0;r0&&t{this.rows.x.left=-this.size.width/2+this.marginsPos.left,this.rows.x.right=this.size.width/2-this.marginsPos.right;const t=e;this.rows.l=t;let r=-this.size.height/2+this.marginsPos.top;for(let e=0;e0&&e{this.rows.x.left=-this.size.width/2+this.marginsPos.left,this.rows.x.right=this.size.width/2-this.marginsPos.right;const e=(this.size.height-(this.marginsPos.top+this.marginsPos.bottom))/this.h;if(null===this.verticalSpace||this.verticalSpace.length!==this.h||this.regular){this.verticalSpace=[];for(let t=0;tthis.h?r+=parseInt(this.rows.l[e-1]):r+=parseInt(this.rows.l[e]),this.rows.gap[e]={},e>0&&ee=0?t?this.columns.center[e]:this.columns.gap[e].right:(console.error(`this col dod not exists in grid. requested number ${e}`),0);row=(e,t=!1)=>e=0?t?this.rows.center[e]:this.rows.gap[e].top:(console.error(`this row do not exists in grid. requested number ${e}`),0);getAvailableWidth=(e=!0)=>{if(e){return this.size.width-this.size.width*this.size.margin[0]-this.size.width*this.size.margin[2]}return this.size.width};width=(e,t=!1,r=!1)=>e0?t||e===this.v?this.columns.l*e:r?this.columns.l*e-this.gapw/2:this.columns.l*e-this.gapw:(console.error(`side bigger than grid. requested side ${e}`),0);height=(e,t=!1,r=!1)=>e0?t||e===this.h?this.rows.l*e:r?this.rows.l*e-this.gaph/2:this.rows.l*e-this.gaph:(console.error(`side bigger than row grid. requested side ${e}`),0);display=(e,t=!0,r=!0,o=!0)=>{e.push(),e.translate(this.size.width/2,this.size.height/2),r&&this.#v(e),o&&this.#b(e),t&&this.#_(e),e.pop()};#_=(e,t="#0000ff")=>{e.push(),e.stroke(t),e.rectMode(CORNER),e.noFill(),e.rect(this.rows.x.left,this.columns.y.top,this.size.width-(this.marginsPos.left+this.marginsPos.right),this.size.height-(this.marginsPos.top+this.marginsPos.bottom)),e.pop()};#v=(e,t="#ff00ff",r="#009800")=>{e.push(),e.stroke(t);for(let t of Object.keys(this.columns.center)){const r=this.columns.center[t];e.line(r,this.columns.y.top,r,this.columns.y.bottom)}e.stroke(r);for(let t of Object.keys(this.columns.gap)){const r=this.columns.gap[t];"0"!==t&&t!==""+this.v&&(e.line(r.left,this.columns.y.top,r.left,this.columns.y.bottom),e.line(r.right,this.columns.y.top,r.right,this.columns.y.bottom))}e.pop()};#b=(e,t="#ff00ff",r="#009800")=>{e.push(),e.stroke(t);for(let t of Object.keys(this.rows.center)){const r=this.rows.center[t];e.line(this.rows.x.left,r,this.rows.x.right,r)}e.stroke(r);for(let t of Object.keys(this.rows.gap)){t=parseInt(t);const r=this.rows.gap[t];0!==t&&t!==this.h&&(e.text(t,this.rows.x.left+this.rows.x.right/2,r.top),e.line(this.rows.x.left,r.top,this.rows.x.right,r.top),e.line(this.rows.x.left,r.bottom,this.rows.x.right,r.bottom))}e.pop()}}class jt{#w;#x;constructor(e,t){this.size=e.evo.popSize,this.params=e,this.population=[],this.generations=0,this.ready=!1,this.evolving=!1,this.pause=!1,this.#x=t,this.targetSemanticLayout=this.#j(this.#x),console.log("targetSemanticLayout",this.targetSemanticLayout),this.#w=[],this.updated=!0,this.log={config:this.params,generations:[]},this.initialisation()}initialisation=async()=>{this.updated=!0,this.generations=0,this.#S();for(let e=0;ee.typeface));for(const e of r)-1===this.#w.indexOf(e)&&this.#w.push(e)}await this.evaluate(),this.updated=!0};evolve=async()=>{await this.#S(),document.getElementById("generation-number").textContent=this.generations;const e=[],t=parseInt(this.params.evo.eliteSize);for(let r=0;re.fitness)),o=this.population.map((e=>e.constraint));const s=await this.#E(r,o);for(let r=t;r{this.evolve()}),100):(this.evolving=!1,console.group("stats"),console.log(this.log),console.groupEnd())};uniformCrossover=(e,t)=>{const r=e.copy();t=t.copy(),Math.random()>.5&&(r.genotype.typography.verticalAlignment=t.genotype.typography.verticalAlignment);for(const e in r.genotype.textboxes)Math.random()>.5&&(r.genotype.textboxes[e]=t.genotype.textboxes[e]);r.genotype.grid=new xt(this.params.size,2,this.params.sentences.length,this.params.size.margin);for(const e in r.genotype.textboxes){const t=r.genotype.textboxes[e],o=se.availableTypefacesInfo[t.typeface].leading;r.genotype.grid.defineRow(e,t.size*o,r.genotype.typography.verticalAlignment)}if(Math.random()>.5&&(r.genotype.background.style=t.genotype.background.style),Math.random()>.5){r.genotype.background.colors[0]=t.genotype.background.colors[0],r.genotype.background.colors[1]=t.genotype.background.colors[1];for(const e in r.genotype.textboxes)r.genotype.textboxes[e].color=t.genotype.textboxes[e].color}else{let t=e.genotype.textboxes[0].color,o=t.levels?color(t.levels[0],t.levels[1],t.levels[2]):color(t);for(const e in r.genotype.textboxes)r.genotype.textboxes[e].color=o}for(const e in r.genotype.images)Math.random()>.5&&(r.genotype.images[e]=t.genotype.images[e]);return r};mutate=e=>{let t=this.params.evo.mutationProb;if(Math.random()1){const e=Math.round(Math.random()*(this.params.typography.typefaces.length-1));n=e,s.typeface=this.params.typography.typefaces[e].family}if(Math.random(){for(let t of this.population)t.toggleGrid(e);this.updated=!0};evaluate=async()=>{for(let e of this.population)await e.evaluate(this.targetSemanticLayout);await this.#T()};#E=async(e,t,r=.45)=>{let o=this.population.length,s=Array.from(Array(o).keys());for(let n=0;ne[s[i+1]]||t[s[i]]>t[s[i+1]])&&(me(s,i,i+1),n=!1)}if(n)break;n=!0}return s};#T=async()=>{this.population=this.population.sort(((e,t)=>t.fitness-t.constraint-(e.fitness-e.constraint))),console.log("best individual=",this.population[0].fitness,this.population[0].constraint)};copy=e=>JSON.parse(JSON.stringify(e));#M=(e,t=5,r=2,o=2)=>{t=te-t));let i=n.map((e=>o-2*e*(o-1)/(this.population.length-1)));const a=ye(i);i=i.map((e=>e/a)),i=(e=>{for(let t=e.length-1;t>0;t--){const r=Math.floor(Math.random()*(t+1));[e[t],e[r]]=[e[r],e[t]]}return e})(i);for(let e=0;e{for(let e of this.#w){if(!document.fonts.check(`12px ${e}`))return!1}return!0};#S=()=>{document.querySelectorAll("canvas:not(#defaultCanvas0)").forEach((e=>{e.remove()}))};draw=async()=>{this.updated=!1;const e=this.population.length{for(let e in this.population){const t=this.population[e];save(t.phenotype,`${Date.now()}-${this.generations}-${e}`)}};#j=(e,t=.1)=>{let r=[];for(let o of e.lexicon.sentences){let e=o.emotions.data.recognisedEmotions.length,s=o.emotions.data.recognisedEmotions.map((e=>e[0])),n=o.emotions.data.recognisedEmotions.reduce(((e,t)=>e+t[1]),0);n+=t,r.push([e,s,n])}const o=ye(r.map((e=>e[2])));return r=r.map((e=>[e[0],e[1],e[2],Math.round(e[2]/o*100)/100])),r}}window.preload=()=>{},window.setup=()=>{window.app=document.createElement("app-evo"),document.querySelector("main").appendChild(app),noCanvas(),noLoop(),frameRate(25)},window.draw=()=>{if(window.app.screen<3)return null;window.app.population.updated&&(push(),background(window.app.backgroundColor),window.app.population.draw(),pop())},window.windowResized=()=>{if(window.app.screen<2)return null},window.keyPressed=()=>{if(window.app.screen<2)return null};class St extends re{static properties={screen:0,results:{},evolving:!1};constructor(){super(),this.results=null,this.screen=0,this.evolving=!1;const e=this.#A();this.config={evo:{popSize:se.evolution.popSize,noGen:se.evolution.noGen,crossoverProb:se.evolution.crossoverProb,mutationProb:se.evolution.mutationProb,eliteSize:se.evolution.eliteSize},size:{width:se.visualisationGrid.width,height:se.visualisationGrid.height,margin:se.visualisationGrid.posterMargins},images:[],sentences:null,background:{style:0,color:{random:!0,valueA:se.background.defaultColors[0],valueB:se.background.defaultColors[1]},lock:[!1,!1]},typography:{verticalAlignment:0,color:{random:!0,value:se.typography.defaultColor},textAlignment:0,typefaces:e.typefaces,weight:e.weight,stretch:e.stretch,uppercase:!1,texboxAlignment:0,lock:[!1,!1,!1,!1,!1,!1,!1,!1]},display:{grid:!0}},this.population=null,this.errorMessage=new he,this.resultsContainer=new de,this.inputForm=new ie(this.analyse,this.resultsContainer,this.errorMessage),this.header=new Me,this.initPopForm=new Ee(this.config,this.#k,this.population,this.errorMessage),document.getElementById("defaultCanvas0").style.visibility="visible",this.backgroundColor=getComputedStyle(document.documentElement).getPropertyValue("--main-bg-color")}#A=()=>{const e={typefaces:[],weight:{min:Number.MAX_VALUE,max:Number.MIN_VALUE},stretch:{min:Number.MAX_VALUE,max:Number.MIN_VALUE}};for(let t of Array.from(document.fonts))if(se.availableTypefaces.includes(t.family)){let r=t.stretch.replaceAll("%",""),o=[100,100];"normal"!==r&&(o=r.split(" ").map((e=>parseInt(e)))),e.stretch.min>o[0]&&(e.stretch.min=o[0]),e.stretch.maxparseInt(e)));e.weight.min>s[0]&&(e.weight.min=s[0]),e.weight.max{const e=this.inputForm.data();let t=`/${e.shouldDivide?"text":`lines/${e.delimiter}`}/${e.lang}/${e.textContent}`;fetch(t).then((e=>e.json())).then((e=>{this.results=e,!1===e.success&&this.errorMessage.set(e),this.resultsContainer.set(this.results),this.inputForm.dis(),this.screen=1})).catch((e=>{this.errorMessage.set(e)}))};setupEvolution=e=>{e.preventDefault(),this.screen=2,this.config.images=Array.from(document.querySelectorAll("#input-images img")),this.#O(),this.#k()};#k=(e=!1)=>{e&&this.#O(),background(this.backgroundColor),null!==this.results?(null==this.config.sentences&&(this.config.sentences=this.results.sentences),this.population=new jt(this.config,this.results),this.initPopForm.pop=this.population,this.screen=3,this.header.showControls()):this.errorMessage.set({msg:"text input not defined. Not possible to init population"})};#O=()=>{let e=se.visiblePosters,t=Math.ceil(e/Math.floor(windowWidth/this.config.size.width));t*=this.config.size.height+2*se.visualisationGrid.marginY,createCanvas(windowWidth,t),loop()};#L=()=>F` + `}createRenderRoot(){return this}}customElements.define("header-section",Me);var Te={solid:(e,t)=>{e.background(t)},gradient:(e,t,r)=>{push();const o=e.drawingContext;e.background(t);let s=e.height;const n=o.createLinearGradient(0,0,0,s);n.addColorStop(0,t),n.addColorStop(.25,t),n.addColorStop(.75,r),n.addColorStop(1,r),o.fillStyle=n,o.fillRect(0,0,e.width,s),pop()},triangle:(e,t,r)=>{push(),e.background(t),e.noStroke(),e.fill(r),e.triangle(0,0,0,e.height,e.width,e.height),pop()}};const Ce=(e,t,r,o,s)=>o+(e-t)/(r-t)*(s-o),Ae=(e,t,r)=>Math.min(r,Math.max(t,e)),ke=e=>{const t=e.reduce(((e,t)=>e+t),0);return t/e.length||0},Oe=e=>e.reduce(((e,t)=>e+t),0),Le=e=>Math.max(...e),Pe=e=>Math.min(...e),Re=(e,t)=>Ce(e=(e=e>=0?0:e)<=-t?-t:e,-t,0,1,0),Ie=(e,t)=>(e=Math.abs(e),Ce(e=e>t?t:e,t,0,1,0)),De=(e,t)=>Ie(e=e>=0?e/3:e,t);const Fe=(e,t)=>{const r=t.filter(((e,t,r)=>r.indexOf(e)===t)),o=[];for(let s of r)for(let r=0;ro.indexOf(e)!==t)).length>=1){let n=0;for(let s in t){let i=t[s],a=e[s],l=r.indexOf(i);a!==o[l]&&n++}s=Ce(n,0,e.length,0,1)}return s},Ne=(e,t,r="DIF")=>{"MIN"!==r&&"DIF"!==r&&(r="DIF");const o=Le(e),s=Pe(e);let n=Math.abs(o-s);if(n<50)return 1;const i=Le(t),a=Pe(t);let l=s;if("DIF"===r)for(let r in t)if(t[r]===a){l=e[r];break}const c=t.map((e=>{let t=Ce(e,a,i,0,n);return t=Ae(t,0,n),t})),u=[];for(let t in e){let r=e[t],o=Math.abs(r-l),s=Math.abs(o-c[t]);u.push(s)}let d=Ce(ke(u),0,n,1,0);return Ae(d,0,1)},Ue=(e=[],t,r="OVERSET",o=1)=>{let s=[],n=t*o;for(let o of e){let e=t-o,i=1;switch(r){case"JUSTIFY":i=Ie(e,n);break;case"ATTEMPT_JUSTIFY":i=De(e,n);break;default:i=Re(e,n)}s.push(i)}return ke([...s])},Be=(e,t,r=[],o=[],s={left:0,top:0,right:0,bottom:0})=>{let n=!1,i="",a=Math.abs(s.top)+Math.abs(s.bottom);for(let e of r)a+=parseFloat(e);let l=Math.abs(s.left)+Math.abs(s.right);for(let e of o)l+=parseFloat(e);return l=Math.round(l),a=Math.round(a),a>t?(n=!0,i+=`Grid height is bigger than container (grid:${a}, container:${t}). `):ae?(n=!0,i+=`Grid width is bigger than container (grid:${l}, container:${e}). `):l{"RELATIVE"!==r&&"FIXED"!==r&&(r="RELATIVE");let s=0;"RELATIVE"===r?s=Oe(e):"FIXED"===r&&(s=o.height-(o.height*o.margin[1]+o.height*o.margin[3]));const n=e.map((e=>e/s));let i=[];for(let e in t){const r=Math.abs(t[e][3]-n[e]);i.push(r)}return 1-ke(i)},ze=(e,t,r=1,o=!0,s=[.4,.3,.3])=>{const n=t.map((e=>e[3]));let i,a=[Ne(e.map((e=>e.weight)),n),Ne(e.map((e=>e["font-stretch"])),n),r>1?Fe(e.map((e=>e["font-stretch"])),n):0],l=a.map(((e,t)=>e*s[t]));if(o)i=Oe(l);else{let e=a.map((e=>e>.2)),t=0;for(let r of e)r&&t++;i=Le(a)/t}return i};function Ve(e,t,r){return Math.max(t,Math.min(e,r))}function $e(e){return(e%360+360)%360}function He(e){var t,r;return $e(function(e,t){var r;return e*(null!==(r={rad:180/Math.PI,grad:.9,turn:360}[t.toLowerCase()])&&void 0!==r?r:1)}(parseFloat(e),null!==(r=null===(t=e.match(/deg|rad|grad|turn/i))||void 0===t?void 0:t[0])&&void 0!==r?r:"deg"))}function qe(e){return new RegExp(`^${e.source}$`,e.flags)}function We(e){return e.slice(1).filter((e=>void 0!==e))}const Xe=/[+-]?(?=\.\d|\d)\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/,Ye=/(?=[,\s])\s*(?:,\s*)?/,Ze=/\s*[,\/]\s*/,Je=Xe.source,Qe=Ye.source,Ke=new RegExp(`hsla?\\(\\s*(${Je}(?:deg|rad|grad|turn)?)${Qe}(${Je})%${Qe}(${Je})%(?:${Ze.source}(${Je}%?))?\\s*\\)`,"i");const et={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aqua:"#00FFFF",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blue:"#0000FF",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",fuchsia:"#FF00FF",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",goldenrod:"#DAA520",gold:"#FFD700",gray:"#808080",green:"#008000",greenyellow:"#ADFF2F",grey:"#808080",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavenderblush:"#FFF0F5",lavender:"#E6E6FA",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgray:"#D3D3D3",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",lime:"#00FF00",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",maroon:"#800000",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",navy:"#000080",oldlace:"#FDF5E6",olive:"#808000",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",purple:"#800080",rebeccapurple:"#663399",red:"#FF0000",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",silver:"#C0C0C0",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",teal:"#008080",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",white:"#FFFFFF",whitesmoke:"#F5F5F5",yellow:"#FFFF00",yellowgreen:"#9ACD32"};const tt=/[0-9a-fA-F]/.source,rt=new RegExp(`#(${tt}{2})(${tt}{2})(${tt}{2})(${tt}{2})?`),ot=new RegExp(`#(${tt})(${tt})(${tt})(${tt})?`);const st=Xe.source,nt=Ye.source,it=new RegExp(`rgba?\\(\\s*(${st}%?)${nt}(${st}%?)${nt}(${st}%?)(?:${Ze.source}(${st}%?))?\\s*\\)`,"i");function at(e){return{r:Ve(e.r,0,255),g:Ve(e.g,0,255),b:Ve(e.b,0,255),a:Ve(e.a,0,1)}}function lt(e){if("transparent"===(e=e.trim()).toLowerCase())return{r:0,g:0,b:0,a:0};const t=et[e.toLowerCase()];let r;return t&&(e=t),null!==(r=function(e){var t;const r=null!==(t=qe(rt).exec(e))&&void 0!==t?t:qe(ot).exec(e);return r?We(r):null}(e))?function(e){var t;const r=e.map((e=>(1===e.length&&(e=`${e}${e}`),parseInt(e,16)))),o=(null!==(t=r[3])&&void 0!==t?t:255)/255;return{r:r[0],g:r[1],b:r[2],a:o}}(r):null!==(r=function(e){const t=qe(it).exec(e);return t?We(t):null}(e))?function(e){var t;const r=e.map(((e,t)=>{let r=parseFloat(e);return e.indexOf("%")>-1&&(r*=.01,t<3&&(r*=255)),r}));return at({r:r[0],g:r[1],b:r[2],a:null!==(t=r[3])&&void 0!==t?t:1})}(r):null}function ct(e){return{h:$e(e.h),s:Ve(e.s,0,100),l:Ve(e.l,0,100),a:Ve(e.a,0,1)}}function ut(e){const t=lt(e);return t?function(e){const{r:t,g:r,b:o,a:s}=at(e),n=t/255,i=r/255,a=o/255,l=Math.max(n,i,a),c=Math.min(n,i,a),u=l-c,d=(c+l)/2;let h=NaN,p=0;if(0!==u){switch(p=(l-d)/Math.min(d,1-d),l){case n:h=(i-a)/u+(iparseFloat(e)));let s=null!==(t=o[3])&&void 0!==t?t:1;return(null===(r=e[3])||void 0===r?void 0:r.indexOf("%"))>-1&&(s*=.01),ct({h:He(e[0]),s:o[1],l:o[2],a:s})}(t):null}function ht(e){return`rgba(${(e=function(e){return{r:Math.round(e.r),g:Math.round(e.g),b:Math.round(e.b),a:e.a}}(e)).r}, ${e.g}, ${e.b}, ${e.a})`}function pt(e){const t=function(e){return"number"==typeof e.h&&"number"==typeof e.s&&"number"==typeof e.l&&"number"==typeof e.a}(e)?function(e){const{h:t,s:r,l:o,a:s}=ct(e),n=t||0,i=r/100,a=o/100;function l(e){const t=(e+n/30)%12,r=i*Math.min(a,1-a);return a-r*Math.max(-1,Math.min(t-3,9-t,1))}return{r:255*l(0),g:255*l(8),b:255*l(4),a:s}}(e):at(e);return 1===t.a?function(e){const t=(((255&Math.round(e.r))<<16)+((255&Math.round(e.g))<<8)+(255&Math.round(e.b))).toString(16).toUpperCase();return`#${"000000".substring(t.length)}${t}`}(t):ht(t)}var ft=(e,t)=>{if("number"!=typeof t||0===t)return e;const r=function(e){var t;const r=null!==(t=dt(e))&&void 0!==t?t:ut(e);if(null===r)throw new Error("Invalid color string");return r}(e),o=(r.h+t)%360;return pt(Object.assign(Object.assign({},r),{h:o}))};var mt=(e,t)=>"number"!=typeof t||0===t?e:ft(e,30*t);var yt=(e,t)=>{if("number"!=typeof t||0===t)return e;let r=0,o=t<0?-1:1,s=0;for(;s!==t;)s+=o,r+=s%2!=0?180*o:30*o;return ft(e,r)};const gt=()=>{const e=bt();return vt(e)},vt=e=>{const t=yt(e,1);return{baseColour:e,colorA:t,colorB:mt(t,Math.round(4*Math.random()-2))}},bt=()=>{const e=[Math.round(255*Math.random()),Math.round(255*Math.random()),Math.round(255*Math.random())].map((e=>e.toString(16).padStart(2,"0")));return`#${e.join("")}`};class _t{#d=!1;#h=!1;constructor(e,t,r=null,o=null){this.id=`${t}-${e}`,this.n=e,this.generation=t,this.ready=!1,this.params=JSON.parse(JSON.stringify(r)),this.fitness=1,this.constraint=0,this.metrics={legibility:1,gridAppropriateness:1},this.sentencesLenght=[];const s=null===o?r.size.height:o.size.height;this.maxFontSize=se.typography.maxSize*s,this.minFontSize=se.typography.minSize*s,this.genotype=null===o?this.#p(r):o,this.#d=null!==r&&r.display.grid,this.phenotype=null}copy=()=>{const e=this.genotype.grid,t=new xt(JSON.parse(JSON.stringify(e.size)),JSON.parse(JSON.stringify(e.v)),JSON.parse(JSON.stringify(e.h)),JSON.parse(JSON.stringify(e.defaultMargins)),JSON.parse(JSON.stringify(e.gwper)),JSON.parse(JSON.stringify(e.ghper))),r=JSON.parse(JSON.stringify(this.genotype.size)),o=JSON.parse(JSON.stringify(this.genotype.textboxes));for(let e in o)o[e].color=color(this.genotype.textboxes[e].color);const s=JSON.parse(JSON.stringify(this.genotype.background));s.colors[0]=color(this.genotype.background.colors[0]),s.colors[1]=color(this.genotype.background.colors[1]);let n=[];for(let e of this.genotype.images){const t={scale:e.scale,src:e.src,x:e.x,y:e.y};n.push(t)}const i={grid:t,textboxes:o,size:r,background:s,typography:JSON.parse(JSON.stringify(this.genotype.typography)),images:n};return new _t(this.n,this.generation,this.params,i)};#p=e=>{const t=gt(),r=new xt({width:e.size.width,height:e.size.height,margin:e.size.margin},2,e.sentences.length,JSON.parse(JSON.stringify(e.size.margin))),o=[],s=0===e.typography.verticalAlignment?Math.round(Math.random()*(se.textAlignmentOptions.length-2)+1):e.typography.verticalAlignment;for(let n in e.sentences){const i=e.sentences[n],a=Math.round(Math.random()*(e.typography.typefaces.length-1));let l=e.typography.typefaces[a].stretch;l.map((e=>isNaN(e)?100:parseInt(e))),l.length<2&&l.push(100);let c=e.typography.typefaces[a].weight,u=Math.round(Math.random()*(e.typography.weight.max-e.typography.weight.min)+e.typography.weight.min);u=Math.max(c[0],Math.min(u,c[1]));let d=Math.round(Math.random()*(e.typography.stretch.max-e.typography.stretch.min)+e.typography.stretch.min);d=Math.max(l[0],Math.min(d,l[1]));const h=se.availableTypefacesInfo[se.availableTypefaces[a]].leading;let p=Math.round(r.rows.l[0])/h;p+=Math.round(-p*se.typography.range+Math.random()*(p*se.typography.range)),p=Math.max(Math.round(e.size.height*se.typography.minSize),Math.min(Math.round(e.size.height*se.typography.maxSize),p)),r.defineRow(n,p*h,s);const f=0===e.typography.textAlignment?Math.round(Math.random()*(se.textAlignmentTbOptions.length-2)+1):e.typography.textAlignment;o.push({content:i,weight:u,"font-stretch":d,alignment:f,size:p,typeface:e.typography.typefaces[a].family,color:e.typography.color.random?t.baseColour:color(e.typography.color.value),uppercase:e.typography.uppercase})}const n=[];for(let t of e.images){const r=t.src,o=loadImage(r,(async t=>{await t.resize(0,e.size.height),t.ready=!0}));n.push({x:Math.random(),y:Math.random(),scale:Math.random(),src:o})}return{grid:r,textboxes:o,size:{width:e.size.width,height:e.size.height,margin:e.size.margin},background:{style:0===e.background.style?Math.round(1+Math.random()*(se.background.availableStyles.length-2)):e.background.style,colors:[e.background.color.random?t.colorA:color(e.background.color.valueA),e.background.color.random?t.colorB:color(e.background.color.valueB)]},typography:{verticalAlignment:s},images:n}};draw=async()=>{this.ready=!0,this.phenotype=createGraphics(this.genotype.size.width,this.genotype.size.height),this.phenotype.id=this.n;const e=Object.keys(Te)[this.genotype.background.style-1];return(0,Te[e])(this.phenotype,this.genotype.background.colors[0],this.genotype.background.colors[1]),this.ready=await this.#f(this.phenotype),await this.typeset(this.phenotype),this.#h&&(pg.textSize(10),pg.fill(0),pg.text(`${this.id}+${this.genotype.typography.verticalAlignment}+style=${this.genotype.background.style}\nfitness=${this.fitness}`,20,20)),(this.#d||this.#h)&&this.genotype.grid.display(this.phenotype),this.phenotype};evaluate=async e=>{this.phenotype=await this.draw();const t=this.params.typography.typefaces.length;Ge(this.genotype.grid.rows.l,e,"FIXED",this.genotype.size);const r=ze(this.genotype.textboxes,e,t);Ue(this.sentencesLenght,this.genotype.grid.getAvailableWidth(),"JUSTIFY"),this.fitness=r,console.group(),console.log(JSON.stringify(this.genotype.textboxes),JSON.stringify(e),JSON.stringify(t)),console.log("visualSemantics",r),console.groupEnd();const o=Ue(this.sentencesLenght,this.genotype.grid.getAvailableWidth(),"OVERSET"),s=Be(this.genotype.size.width,this.genotype.size.height,this.genotype.grid.rows.l,this.genotype.grid.columns.l,this.genotype.grid.marginsPos);return this.constraint=o+s,this.metrics.legibility=o,this.metrics.gridAppropriateness=s,{fitness:this.fitness,constraints:this.constraint}};typeset=async e=>{this.sentencesLenght=[],e.push(),e.translate(e.width/2,e.height/2);const t=e.drawingContext;for(let r in this.genotype.textboxes){const o=this.genotype.textboxes[r];let s=o.alignment,n=LEFT;2===s?n=CENTER:3===s&&(n=RIGHT),e.textAlign(n,BASELINE);let i=this.genotype.grid.col(s-1,!1),a=this.genotype.grid.row(parseInt(r)+1,!1);e.fill(o.color),t.font=`${o.weight} ${wt(o["font-stretch"])} ${o.size}px ${o.typeface}`,drawingContext.font=`${o.weight} ${wt(o["font-stretch"])} ${o.size}px ${o.typeface}`;let l=!0===o.uppercase?o.content.toUpperCase():o.content;e.text(l,i,a);const c=t.measureText(l).width;this.sentencesLenght.push(c)}e.pop()};#f=async e=>{let t=!0;for(let r of this.genotype.images)if(void 0!==r.src&&r.src.hasOwnProperty("ready")){if(r.src.ready){let t=e.width*r.x,o=e.height*r.y;e.imageMode(CENTER),e.image(r.src,t,o,r.src.width*r.scale,r.src.height*r.scale)}}else t=!1;return t};toggleGrid=(e=null)=>{null===e&&(e=!this.#d),this.#d=e,this.draw()}}const wt=e=>e>-10&&e<=50?"ultra-condensed":e>50&&e<=62.5?"extra-condensed":e>62.5&&e<=75?"condensed":e>75&&e<=87.5?"semi-condensed":e>87.5&&e<=100?"normal":e>100&&e<=112.5?"semi-expanded":e>112.5&&e<=125?"expanded":e>125&&e<=150?"extra-expanded":"ultra-expanded";class xt{constructor(e,t=12,r=24,o,s=.03,n=null){null===n&&(n=s),this.pos=createVector(e.width/2,e.height/2),this.size=JSON.parse(JSON.stringify(e)),this.defaultMargins=o,this.v=t,this.h=r,this.gwper=s,this.ghper=n,this.gapw=this.size.width*this.gwper,this.gaph=this.size.height*this.ghper,this.regular=!0,this.verticalSpace=[],this.marginsPos={},this.columns={},this.columns.y={},this.columns.center={},this.columns.gap={},this.rows={},this.rows.x={},this.rows.center={},this.rows.gap={},this.def()}export=()=>({pos:[this.pos.x,this.pos.y,this.pos.z],size:this.size,defaultMargins:this.defaultMargins,v:this.v,h:this.h,gapw:this.gapw,gaph:this.gaph,marginsPos:this.marginsPos,columns:this.columns,rows:this.rows});copy=()=>new xt(JSON.parse(JSON.stringify(this.size)),JSON.parse(JSON.stringify(this.v)),JSON.parse(JSON.stringify(this.h)),JSON.parse(JSON.stringify(this.defaultMargins)),JSON.parse(JSON.stringify(this.gwper)),JSON.parse(JSON.stringify(this.ghper)));updateMarginsBasedOnSize=(e=0,t=1,r,o=this.size.height)=>{const s=t*r;let n=this.size.height-s;0===e&&(n/=2),(0===e||1===e)&&this.size.margin[1]{0===e&&(t/=2),(0===e||1===e)&&this.size.margin[1]{this.size.margin=this.defaultMargins,this.marginsPos.left=this.size.margin[0]*this.size.width,this.marginsPos.top=this.size.margin[1]*this.size.height,this.marginsPos.right=this.size.margin[2]*this.size.width,this.marginsPos.bottom=this.size.margin[3]*this.size.height,this.def()};def=()=>{this.#m(),this.#y(),this.#g()};update=(e=null,t=null)=>{null!==e&&e!==this.v&&console.log(`grid updated from ${this.v} to ${e}`)};defineRow=(e,t,r)=>{this.regular=!1;const o=this.rows.l[e];this.rows.l[e]=t;let s=this.rows.l[e]-o;s=2===r?s/2:s,this.marginsPos.bottom,this.size.height,r<=2&&(this.size.margin[3]=(this.marginsPos.bottom-s)/this.size.height),r>=2&&(this.size.margin[1]=(this.marginsPos.top-s)/this.size.height),this.def()};#m=()=>{this.marginsPos.left=this.size.margin[0]*this.size.width,this.marginsPos.top=this.size.margin[1]*this.size.height,this.marginsPos.right=this.size.margin[2]*this.size.width,this.marginsPos.bottom=this.size.margin[3]*this.size.height};getSpace=()=>{const e=this.rows.l.reduce(((e,t)=>e+t),0)/this.rows.l.length;return{centre:{col:this.columns.l,row:e},gap:{col:this.columns.l-this.gapw/2,row:e-this.gaph/2}}};#y=()=>{this.columns.y.top=-this.size.height/2+this.marginsPos.top,this.columns.y.bottom=this.size.height/2-this.marginsPos.bottom;const e=(this.size.width-(this.marginsPos.left+this.marginsPos.right))/this.v;let t=[];for(let r=0;r0&&t{this.rows.x.left=-this.size.width/2+this.marginsPos.left,this.rows.x.right=this.size.width/2-this.marginsPos.right;const t=e;this.rows.l=t;let r=-this.size.height/2+this.marginsPos.top;for(let e=0;e0&&e{this.rows.x.left=-this.size.width/2+this.marginsPos.left,this.rows.x.right=this.size.width/2-this.marginsPos.right;const e=(this.size.height-(this.marginsPos.top+this.marginsPos.bottom))/this.h;if(null===this.verticalSpace||this.verticalSpace.length!==this.h||this.regular){this.verticalSpace=[];for(let t=0;tthis.h?r+=parseInt(this.rows.l[e-1]):r+=parseInt(this.rows.l[e]),this.rows.gap[e]={},e>0&&ee=0?t?this.columns.center[e]:this.columns.gap[e].right:(console.error(`this col dod not exists in grid. requested number ${e}`),0);row=(e,t=!1)=>e=0?t?this.rows.center[e]:this.rows.gap[e].top:(console.error(`this row do not exists in grid. requested number ${e}`),0);getAvailableWidth=(e=!0)=>{if(e){return this.size.width-this.size.width*this.size.margin[0]-this.size.width*this.size.margin[2]}return this.size.width};width=(e,t=!1,r=!1)=>e0?t||e===this.v?this.columns.l*e:r?this.columns.l*e-this.gapw/2:this.columns.l*e-this.gapw:(console.error(`side bigger than grid. requested side ${e}`),0);height=(e,t=!1,r=!1)=>e0?t||e===this.h?this.rows.l*e:r?this.rows.l*e-this.gaph/2:this.rows.l*e-this.gaph:(console.error(`side bigger than row grid. requested side ${e}`),0);display=(e,t=!0,r=!0,o=!0)=>{e.push(),e.translate(this.size.width/2,this.size.height/2),r&&this.#v(e),o&&this.#b(e),t&&this.#_(e),e.pop()};#_=(e,t="#0000ff")=>{e.push(),e.stroke(t),e.rectMode(CORNER),e.noFill(),e.rect(this.rows.x.left,this.columns.y.top,this.size.width-(this.marginsPos.left+this.marginsPos.right),this.size.height-(this.marginsPos.top+this.marginsPos.bottom)),e.pop()};#v=(e,t="#ff00ff",r="#009800")=>{e.push(),e.stroke(t);for(let t of Object.keys(this.columns.center)){const r=this.columns.center[t];e.line(r,this.columns.y.top,r,this.columns.y.bottom)}e.stroke(r);for(let t of Object.keys(this.columns.gap)){const r=this.columns.gap[t];"0"!==t&&t!==""+this.v&&(e.line(r.left,this.columns.y.top,r.left,this.columns.y.bottom),e.line(r.right,this.columns.y.top,r.right,this.columns.y.bottom))}e.pop()};#b=(e,t="#ff00ff",r="#009800")=>{e.push(),e.stroke(t);for(let t of Object.keys(this.rows.center)){const r=this.rows.center[t];e.line(this.rows.x.left,r,this.rows.x.right,r)}e.stroke(r);for(let t of Object.keys(this.rows.gap)){t=parseInt(t);const r=this.rows.gap[t];0!==t&&t!==this.h&&(e.text(t,this.rows.x.left+this.rows.x.right/2,r.top),e.line(this.rows.x.left,r.top,this.rows.x.right,r.top),e.line(this.rows.x.left,r.bottom,this.rows.x.right,r.bottom))}e.pop()}}class jt{#w;#x;constructor(e,t){this.size=e.evo.popSize,this.params=e,this.population=[],this.generations=0,this.ready=!1,this.evolving=!1,this.pause=!1,this.#x=t,this.targetSemanticLayout=this.#j(this.#x),this.#w=[],this.updated=!0,this.log={config:this.params,generations:[]},this.initialisation()}initialisation=async()=>{this.updated=!0,this.generations=0,this.#S();for(let e=0;ee.typeface));for(const e of r)-1===this.#w.indexOf(e)&&this.#w.push(e)}await this.evaluate(),this.updated=!0};evolve=async()=>{const e=[];await this.#S(),document.getElementById("generation-number").textContent=this.generations;const t=parseInt(this.params.evo.eliteSize);for(let r=0;re.fitness)),o=this.population.map((e=>e.constraint));const s=await this.#E(r,o);for(let r=t;r{this.evolve()}),100):(this.evolving=!1,console.group("stats"),console.log(this.log),console.groupEnd())};uniformCrossover=(e,t)=>{const r=e.copy();t=t.copy(),Math.random()>.5&&(r.genotype.typography.verticalAlignment=t.genotype.typography.verticalAlignment);for(const e in r.genotype.textboxes)Math.random()>.5&&(r.genotype.textboxes[e]=t.genotype.textboxes[e]);r.genotype.grid=new xt(this.params.size,2,this.params.sentences.length,this.params.size.margin);for(const e in r.genotype.textboxes){const t=r.genotype.textboxes[e],o=se.availableTypefacesInfo[t.typeface].leading;r.genotype.grid.defineRow(e,t.size*o,r.genotype.typography.verticalAlignment)}if(Math.random()>.5&&(r.genotype.background.style=t.genotype.background.style),Math.random()>.5){r.genotype.background.colors[0]=t.genotype.background.colors[0],r.genotype.background.colors[1]=t.genotype.background.colors[1];for(const e in r.genotype.textboxes)r.genotype.textboxes[e].color=t.genotype.textboxes[e].color}else{let t=e.genotype.textboxes[0].color,o=t.levels?color(t.levels[0],t.levels[1],t.levels[2]):color(t);for(const e in r.genotype.textboxes)r.genotype.textboxes[e].color=o}for(const e in r.genotype.images)Math.random()>.5&&(r.genotype.images[e]=t.genotype.images[e]);return r};mutate=e=>{let t=this.params.evo.mutationProb;if(Math.random()1){const e=Math.round(Math.random()*(this.params.typography.typefaces.length-1));n=e,s.typeface=this.params.typography.typefaces[e].family}if(Math.random(){for(let t of this.population)t.toggleGrid(e);this.updated=!0};evaluate=async()=>{for(let e of this.population)await e.evaluate(this.targetSemanticLayout);await this.#T()};#E=async(e,t,r=.45)=>{let o=this.population.length,s=Array.from(Array(o).keys());for(let n=0;ne[s[i+1]]||t[s[i]]>t[s[i+1]])&&(me(s,i,i+1),n=!1)}if(n)break;n=!0}return s};#T=async()=>{this.population=this.population.sort(((e,t)=>t.fitness-t.constraint-(e.fitness-e.constraint)))};copy=e=>JSON.parse(JSON.stringify(e));#M=(e,t=5,r=2,o=2)=>{t=te-t));let i=n.map((e=>o-2*e*(o-1)/(this.population.length-1)));const a=ye(i);i=i.map((e=>e/a)),i=(e=>{for(let t=e.length-1;t>0;t--){const r=Math.floor(Math.random()*(t+1));[e[t],e[r]]=[e[r],e[t]]}return e})(i);for(let e=0;e{for(let e of this.#w){if(!document.fonts.check(`12px ${e}`))return!1}return!0};#S=()=>{document.querySelectorAll("canvas:not(#defaultCanvas0)").forEach((e=>{e.remove()}))};draw=async()=>{this.updated=!1;const e=this.population.length{for(let e in this.population){const t=this.population[e];save(t.phenotype,`${Date.now()}-${this.generations}-${e}`)}};#j=(e,t=.1)=>{let r=[];for(let o of e.lexicon.sentences){let e=o.emotions.data.recognisedEmotions.length,s=o.emotions.data.recognisedEmotions.map((e=>e[0])),n=o.emotions.data.recognisedEmotions.reduce(((e,t)=>e+t[1]),0);n+=t,r.push([e,s,n])}const o=ye(r.map((e=>e[2])));return r=r.map((e=>[e[0],e[1],e[2],Math.round(e[2]/o*100)/100])),r}}window.preload=()=>{},window.setup=()=>{window.app=document.createElement("app-evo"),document.querySelector("main").appendChild(app),noCanvas(),noLoop(),frameRate(25)},window.draw=()=>{if(window.app.screen<3)return null;window.app.population.updated&&(push(),background(window.app.backgroundColor),window.app.population.draw(),pop())},window.windowResized=()=>{if(window.app.screen<2)return null},window.keyPressed=()=>{if(window.app.screen<2)return null};class St extends re{static properties={screen:0,results:{},evolving:!1};constructor(){super(),this.results=null,this.screen=0,this.evolving=!1;const e=this.#A();this.config={evo:{popSize:se.evolution.popSize,noGen:se.evolution.noGen,crossoverProb:se.evolution.crossoverProb,mutationProb:se.evolution.mutationProb,eliteSize:se.evolution.eliteSize},size:{width:se.visualisationGrid.width,height:se.visualisationGrid.height,margin:se.visualisationGrid.posterMargins},images:[],sentences:null,background:{style:0,color:{random:!0,valueA:se.background.defaultColors[0],valueB:se.background.defaultColors[1]},lock:[!1,!1]},typography:{verticalAlignment:0,color:{random:!0,value:se.typography.defaultColor},textAlignment:0,typefaces:e.typefaces,weight:e.weight,stretch:e.stretch,uppercase:!1,texboxAlignment:0,lock:[!1,!1,!1,!1,!1,!1,!1,!1]},display:{grid:!0}},this.population=null,this.errorMessage=new he,this.resultsContainer=new de,this.inputForm=new ie(this.analyse,this.resultsContainer,this.errorMessage),this.header=new Me,this.initPopForm=new Ee(this.config,this.#k,this.population,this.errorMessage),document.getElementById("defaultCanvas0").style.visibility="visible",this.backgroundColor=getComputedStyle(document.documentElement).getPropertyValue("--main-bg-color")}#A=()=>{const e={typefaces:[],weight:{min:Number.MAX_VALUE,max:Number.MIN_VALUE},stretch:{min:Number.MAX_VALUE,max:Number.MIN_VALUE}};for(let t of Array.from(document.fonts))if(se.availableTypefaces.includes(t.family)){let r=t.stretch.replaceAll("%",""),o=[100,100];"normal"!==r&&(o=r.split(" ").map((e=>parseInt(e)))),e.stretch.min>o[0]&&(e.stretch.min=o[0]),e.stretch.maxparseInt(e)));e.weight.min>s[0]&&(e.weight.min=s[0]),e.weight.max{const e=this.inputForm.data();let t=`/${e.shouldDivide?"text":`lines/${e.delimiter}`}/${e.lang}/${e.textContent}`;fetch(t).then((e=>e.json())).then((e=>{this.results=e,!1===e.success&&this.errorMessage.set(e),this.resultsContainer.set(this.results),this.inputForm.dis(),this.screen=1})).catch((e=>{this.errorMessage.set(e)}))};setupEvolution=e=>{e.preventDefault(),this.screen=2,this.config.images=Array.from(document.querySelectorAll("#input-images img")),this.#O(),this.#k()};#k=(e=!1)=>{e&&this.#O(),background(this.backgroundColor),null!==this.results?(null==this.config.sentences&&(this.config.sentences=this.results.sentences),this.population=new jt(this.config,this.results),this.initPopForm.pop=this.population,this.screen=3,this.header.showControls()):this.errorMessage.set({msg:"text input not defined. Not possible to init population"})};#O=()=>{let e=se.visiblePosters,t=Math.ceil(e/Math.floor(windowWidth/this.config.size.width));t*=this.config.size.height+2*se.visualisationGrid.marginY,createCanvas(windowWidth,t),loop()};#L=()=>F`