Skip to content

Commit

Permalink
refactor: fixes on crossover method #16
Browse files Browse the repository at this point in the history
preload of fonts
remove window.fontface depedency
deep copy params
  • Loading branch information
sergiomrebelo committed Jul 19, 2023
1 parent 12f1826 commit b23e294
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 128 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/generator.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ const inputText = {
},
evo: {
popSize: {
init: 20,
testing: 10
init: 10,
testing: 20
},
noGen: {
init: 1000,
Expand Down
26 changes: 24 additions & 2 deletions src/client/Params.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,32 @@ export class Params {
'ta', 'te', 'th', 'tr', 'uk', 'ur', 'vi', 'cy'
];


// JOIN
static availableTypefaces = [
'Amstelvar', 'Anybody', 'Barlow', 'Cabin', 'Emberly', 'Epilogue', 'IBMPlexSans', 'Inconsolata'
]

static availableTypefacesInfo = {
'Amstelvar':{
leading: 1.1
}, 'Anybody':{
leading: 1.1
}, 'Barlow':{
leading: 1.1
}, 'Cabin':{
leading: 1.1
}, 'Emberly':{
leading: 1.1
}, 'Epilogue':{
leading: 1.1
}, 'IBMPlexSans':{
leading: 1.1
}, 'Inconsolata':{
leading: 1.1
}
}

static visualisationGrid = {
height: 423,
width: 300,
Expand All @@ -22,7 +44,7 @@ export class Params {
static imageMaxSize = 1024;

static evolution = {
popSize: 20,
popSize: 10,
noGen: 1000,
crossoverProb: 0.75,
mutationProb: 0.30,
Expand All @@ -39,7 +61,7 @@ export class Params {

static typography = {
defaultColor: `#000000`,
range: 0.1,
range: 0.05,
maxSize: 0.95,
minSize: 0.05
}
Expand Down
49 changes: 47 additions & 2 deletions src/client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export class App extends LitElement {
this.screen = 0;
this.evolving = false;

const fonts = this.#getAvailableTypefaces();
console.log(fonts);
// evolution controllers
//
this.config = {
Expand Down Expand Up @@ -98,7 +100,7 @@ export class App extends LitElement {
value: Params.typography.defaultColor,
},
textAlignment: 0,
typefaces: [],
typefaces: fonts,
weight: 100,
stretch: 200,
uppercase: false,
Expand All @@ -123,6 +125,47 @@ export class App extends LitElement {
this.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--main-bg-color');
}

#getAvailableTypefaces = () => {
const fonts = {
typefaces: [],
weight: {
min: Number.MAX_VALUE,
max: Number.MIN_VALUE
},
stretch: {
min: Number.MAX_VALUE,
max: Number.MIN_VALUE
}
}

for (let font of Array.from(document.fonts)) {
if (Params.availableTypefaces.includes(font.family)) {
let stretch = font.stretch.replaceAll(`%`, ``);
let stretchValues = stretch.split(" ").map((x) => parseInt(x));
if (fonts.stretch.min > stretchValues[0]) {
fonts.stretch.min = stretchValues[0]
}
if (fonts.stretch.max < stretchValues[1]) {
fonts.stretch.max = stretchValues[1]
}
let weightValues = font.weight.split(" ").map((x) => parseInt(x));
if (fonts.weight.min > weightValues[0]) {
fonts.weight.min = weightValues[0]
}
if (fonts.weight.max < weightValues[1]) {
fonts.weight.max = weightValues[1]
}
font.load();
fonts.typefaces.push({
family: font.family,
weight: weightValues,
stretch: stretchValues
});
}
}
return fonts;
}

analyse = async () => {
const formData = this.inputForm.data();
let params = formData.shouldDivide ? `text` : `lines/${formData.delimiter}`;
Expand All @@ -145,7 +188,9 @@ export class App extends LitElement {
e.preventDefault();
this.screen = 2;
// get images
this.config.images = document.querySelectorAll(`#input-images img`);
// TODO: error
this.config.images = Array.from(document.querySelectorAll(`#input-images img`));


this.#initCanvas();
this.#initPopulation();
Expand Down
49 changes: 7 additions & 42 deletions src/client/components/panels/GenerationPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ export class GenerationPanel extends LitElement {
this.restart = restart;

// available fonts
this.fonts = this.#getAvailableTypefaces();
if (this.params) {
// this.fonts = this.#getAvailableTypefaces();
/* if (this.params) {
if (this.params["typography"]) {
this.params["typography"]["weight"] && (this.params["typography"]["weight"] = this.fonts["weight"]);
this.params["typography"]["stretch"] && (this.params["typography"]["stretch"] = this.fonts["stretch"] );
this.params["typography"]["typefaces"] && (this.params["typography"]["typefaces"] = this.fonts["typefaces"] );
}
}
}*/
this.changesInTypefaces = 0;

// error handler
Expand Down Expand Up @@ -77,15 +77,15 @@ export class GenerationPanel extends LitElement {
this.restart();
}, ["col-4"]),
weight: {
min: new Slider(`Min`, this.fonts.weight.min, this.fonts.weight.min, this.fonts.weight.max, 1, `typeface-weight-min`, (e) => {
min: new Slider(`Min`, this.params["typography"]["typefaces"]["weight"]["min"], this.params["typography"]["typefaces"]["weight"]["min"], this.params["typography"]["typefaces"]["weight"]["max"], 1, `typeface-weight-min`, (e) => {
this.params["typography"]["weight"]["min"] = parseInt(e.target.value);
if (this.params["typography"]["weight"]["min"] > this.params["typography"]["weight"]["max"]) {
this.params["typography"]["weight"]["min"] = this.params["typography"]["weight"]["max"];
e.target.value = this.params["typography"]["weight"]["max"];
}
this.restart();
}, ["my-2"]),
max: new Slider(`Max`, this.fonts.weight.max, this.fonts.weight.min, this.fonts.weight.max, 1, `typeface-weight-max`, (e) => {
max: new Slider(`Max`, this.params["typography"]["typefaces"]["weight"]["max"], this.params["typography"]["typefaces"]["weight"]["min"], this.params["typography"]["typefaces"]["weight"]["max"], 1, `typeface-weight-max`, (e) => {
this.params["typography"]["weight"]["max"] = parseInt(e.target.value);
if (this.params["typography"]["weight"]["max"] < this.params["typography"]["weight"]["min"]) {
this.params["typography"]["weight"]["max"] = this.params["typography"]["weight"]["min"];
Expand All @@ -95,15 +95,15 @@ export class GenerationPanel extends LitElement {
}, ["my-2"])
},
stretch: {
min: new Slider(`Min`, this.fonts.stretch.min, this.fonts.stretch.min, this.fonts.stretch.max, 1, `typeface-stretch-min`, (e) => {
min: new Slider(`Min`, this.params["typography"]["typefaces"]["stretch"]["min"], this.params["typography"]["typefaces"]["stretch"]["min"], this.params["typography"]["typefaces"]["stretch"]["max"], 1, `typeface-stretch-min`, (e) => {
this.params["typography"]["stretch"]["min"] = parseInt(e.target.value);
if (this.params["typography"]["stretch"]["min"] > this.params["typography"]["stretch"]["max"]) {
this.params["typography"]["stretch"]["min"] = this.params["typography"]["stretch"]["max"];
e.target.value = this.params["typography"]["stretch"]["max"];
}
this.restart();
}, ["my-2"]),
max: new Slider(`Max`, this.fonts.stretch.max, this.fonts.stretch.min, this.fonts.stretch.max, 1, `typeface-stretch-max`, (e) => {
max: new Slider(`Max`, this.params["typography"]["typefaces"]["stretch"]["max"], this.params["typography"]["typefaces"]["stretch"]["min"], this.params["typography"]["typefaces"]["stretch"]["max"], 1, `typeface-stretch-max`, (e) => {
this.params["typography"]["stretch"]["max"] = parseInt(e.target.value);
if (this.params["typography"]["stretch"]["max"] < this.params["typography"]["stretch"]["min"]) {
this.params["typography"]["stretch"]["max"] = this.params["typography"]["stretch"]["min"];
Expand Down Expand Up @@ -197,41 +197,6 @@ export class GenerationPanel extends LitElement {
}


#getAvailableTypefaces = () => {
const fonts = {
typefaces: [],
weight: {
min: Number.MAX_VALUE,
max: Number.MIN_VALUE
},
stretch: {
min: Number.MAX_VALUE,
max: Number.MIN_VALUE
}
}

for (let font of Array.from(document.fonts)) {
if (Params.availableTypefaces.includes(font.family)) {
let stretch = font.stretch.replaceAll(`%`, ``);
let stretchValues = stretch.split(" ").map((x) => parseInt(x));
if (fonts.stretch.min > stretchValues[0]) {
fonts.stretch.min = stretchValues[0]
}
if (fonts.stretch.max < stretchValues[1]) {
fonts.stretch.max = stretchValues[1]
}
let weightValues = font.weight.split(" ").map((x) => parseInt(x));
if (fonts.weight.min > weightValues[0]) {
fonts.weight.min = weightValues[0]
}
if (fonts.weight.max < weightValues[1]) {
fonts.weight.max = weightValues[1]
}
fonts.typefaces.push(font);
}
}
return fonts;
}

#updateSize = () => {
let width = validateNumberInput(document.getElementById(`size-x-input`).value);
Expand Down
67 changes: 32 additions & 35 deletions src/client/controllers/Population.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class Population {

// mutation
for (let i = eliteSize; i < offspring.length; i++) {
await this.mutate(offspring[i]);
// await this.mutate(offspring[i]);
}

// replace the individuals in the population with the new offspring
Expand Down Expand Up @@ -115,38 +115,21 @@ export class Population {
uniformCrossover = (parentA, parentB) => {
const child = parentA.copy();
parentB = parentB.copy();
// size is fixed
// grid
if (Math.random() > 0.5) {
child.genotype["grid"] = parentB.genotype["grid"];
// grid is defined based on the verticalAlignment
child.genotype["typography"]["verticalAlignment"] = parentB.genotype["background"]["verticalAlignment"];
child.genotype["typography"]["verticalAlignment"] = parentB.genotype["typography"]["verticalAlignment"];
}
// textboxes
for (const i in child.genotype["textboxes"]) {
if (Math.random() > 0.5) {
child.genotype["textboxes"][i] = parentB.genotype["textboxes"][i];
child.genotype["grid"].defineRow(i, child.genotype["textboxes"][i]["size"], child.genotype["typography"]["verticalAlignment"]);
}
// designed to maintain the colour scheme
let original = parentA.genotype["textboxes"][i]["color"];
let c;
if ( original["levels"]) {
c = color(original["levels"][0],original["levels"][1], original["levels"][2]);
} else {
c = color(original);
}

for (const i in child.genotype["textboxes"]) {
child.genotype["textboxes"][i]["color"] = c;
}
}

// force update size
for (const i in child.genotype["textboxes"]) {
child.genotype["grid"].defineRow(i, child.genotype["textboxes"][i]["size"], child.genotype["typography"]["verticalAlignment"]);
child.genotype["grid"].defineRow(i, child.genotype["textboxes"][i]["size"], 1);
}

// background
// style
if (Math.random() > 0.5) {
Expand All @@ -160,6 +143,13 @@ export class Population {
for (const i in child.genotype["textboxes"]) {
child.genotype["textboxes"][i]["color"] = parentB.genotype["textboxes"][i]["color"];
}
} else {
// designed to maintain the colour scheme
let original = parentA.genotype["textboxes"][0]["color"];
let c = original["levels"] ? color(original["levels"][0],original["levels"][1], original["levels"][2]) : color(original);
for (const i in child.genotype["textboxes"]) {
child.genotype["textboxes"][i]["color"] = c;
}
}

//images
Expand All @@ -175,6 +165,7 @@ export class Population {
// mutate background style
let prob = this.params["evo"]["mutationProb"];

// background
// colours
if (Math.random() < prob) {
const colorScheme = randomScheme();
Expand All @@ -190,33 +181,20 @@ export class Population {
}
}
}

// style
if (Math.random() < prob && !this.params["background"]["lock"][0]) {
ind.genotype["background"]["style"] = Math.round(1+Math.random()*2);
}

// textboxes features
for (let i in ind.genotype.textboxes) {
let tb = ind.genotype.textboxes[i];

// textAlignment
if (Math.random() < prob && !this.params["typography"]["lock"][7]) {
tb["textAlignment"] = Math.round(1+Math.random()*2);
}

// size
if (Math.random() < prob) {
let next = Math.round(tb["size"] + -SIZE_MUTATION_ADJUST+(Math.random()*SIZE_MUTATION_ADJUST));
// check if inside font thresholds
const maxFontSize = Params.typography.maxSize * ind.genotype["size"]["height"];
const minFontSize = Params.typography.minSize * ind.genotype["size"]["height"];
next = Math.min(Math.max(next, minFontSize), maxFontSize);

// TODO: adjust grid globally
// TODO: error on centre

tb["size"] = next;
ind.genotype["grid"].defineRow(i, tb["size"] , ind.genotype["typography"]["verticalAlignment"]);
}
// typeface
// typeface is not lock because user.
// This array stores the available typefaces
Expand All @@ -227,11 +205,30 @@ export class Population {
break;
}
}
// get info about the most typeface
if (Math.random() < prob && this.params["typography"]["typefaces"].length > 1) {
const r = Math.round(Math.random()*(this.params["typography"]["typefaces"].length-1));
selectedTypeface = r;
tb["typeface"] = this.params["typography"]["typefaces"][r].family;
}

// TODO: size
if (Math.random() < prob) {
const leading = Params.availableTypefacesInfo[Params.availableTypefaces[selectedTypeface]]["leading"];
let size = Math.round(tb["size"] + -SIZE_MUTATION_ADJUST+(Math.random()*SIZE_MUTATION_ADJUST));
// check if inside typeface min and max thresholds
size = Math.min(Math.max(size, ind.minFontSize), ind.maxFontSize);
tb["size"] = size;
console.log("verticalAlignment", ind.genotype["typography"]["verticalAlignment"]);
// check if the poster content is inside of canvas
// console.log(ind.genotype["grid"]);
// opt 1 -> reset margins
// opt 2 -> reset grid
// console.log("verticalAlignment", ind.genotype["typography"]["verticalAlignment"]);
// tb["size"] = next * leading;
// ind.genotype["grid"].defineRow(i, tb["size"] * leading, ind.genotype["typography"]["verticalAlignment"]);*/
}

// based on the selected typeface
// weight
if (Math.random() < prob) {
Expand Down
Loading

0 comments on commit b23e294

Please sign in to comment.