add recursion
This commit is contained in:
parent
7cf393af71
commit
64fa7098a0
2 changed files with 92 additions and 25 deletions
|
@ -1,7 +1,7 @@
|
|||
import {CollageConfig, CollageMode, Segment} from "@/types";
|
||||
import {choice, randint, range, shuffle} from "@/utils";
|
||||
|
||||
const collageModeType = [
|
||||
export const collageModeType = [
|
||||
"clean_grid", "chaos_grid",
|
||||
"row", "irow",
|
||||
"col", "icol",
|
||||
|
@ -91,7 +91,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Regular Row",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(4) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(4) + 2);
|
||||
const segmentSize = [ctx.canvas.width / numImages, ctx.canvas.height];
|
||||
return range(numImages).map((idx) => {
|
||||
return {
|
||||
|
@ -108,7 +108,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Irregular Row",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(4) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(4) + 2);
|
||||
const segmentSize = [ctx.canvas.width / numImages, ctx.canvas.height];
|
||||
return range(numImages).map((idx) => {
|
||||
const irregularWidth = images ?
|
||||
|
@ -128,7 +128,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Regular Column",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(4) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(4) + 2);
|
||||
const segmentSize = [ctx.canvas.width, ctx.canvas.height / numImages];
|
||||
return range(numImages).map((idx) => {
|
||||
return {
|
||||
|
@ -145,7 +145,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Irregular Column",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(4) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(4) + 2);
|
||||
const segmentSize = [ctx.canvas.width, ctx.canvas.height / numImages];
|
||||
return range(numImages).map((idx) => {
|
||||
const irregularHeight = images ?
|
||||
|
@ -165,7 +165,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Constant factor concentric",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(4) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(4) + 2);
|
||||
let factor: number;
|
||||
if (Math.random() > .5) {
|
||||
factor = choice([1 / Math.sqrt(2), .5, .88]);
|
||||
|
@ -188,7 +188,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Equally spaced concentric",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(2) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(2) + 2);
|
||||
return range(numImages).map((idx) => {
|
||||
return {
|
||||
x: ctx.canvas.width / 2,
|
||||
|
@ -204,7 +204,7 @@ const modes: { [key in CollageModeType]: CollageMode } = {
|
|||
name: "Blending",
|
||||
minImages: 2,
|
||||
getSegments: (ctx, config, images) => {
|
||||
const numImages = Math.min(images?.length || 0, config?.numImages || randint(2) + 2);
|
||||
const numImages = Math.min(images?.length || Infinity, config?.numImages || randint(2) + 2);
|
||||
return range(numImages).map((_) => {
|
||||
return {
|
||||
x: ctx.canvas.width / 2,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<label v-for="(mode, idx) in modes"
|
||||
:class="{disabled: images.length < mode.minImages,
|
||||
selected: idx === currentModeType,
|
||||
lastActive: idx === lastActiveModeType}">
|
||||
lastActive: lastActiveModeTypes.includes(idx)}">
|
||||
{{mode.name}}
|
||||
<input type="radio" :value="idx" v-model="currentModeType">
|
||||
</label>
|
||||
|
@ -28,10 +28,16 @@
|
|||
!SHUFFLE ALL!
|
||||
<input type="radio" value="shuffle" v-model="currentModeType">
|
||||
</label>
|
||||
<label :class="{disabled: images.length < minImages,
|
||||
selected: 'recursive' === currentModeType}">
|
||||
#RECURSIVE#
|
||||
<input type="radio" value="recursive" v-model="currentModeType">
|
||||
</label>
|
||||
</div>
|
||||
<button :disabled="images.length < minImages" @click="renderCollage">REPAINT</button>
|
||||
<hr>
|
||||
<div class="config">
|
||||
<template v-if="currentModeType !== 'recursive'">
|
||||
<label class="config-numimages">
|
||||
#N of images:
|
||||
<input type="number" :min="minImages" :max="images.length"
|
||||
|
@ -39,6 +45,18 @@
|
|||
:disabled="Object.keys(forceConfig).includes('numImages')"
|
||||
v-model="forceConfig.numImages || collageConfig.numImages">
|
||||
</label>
|
||||
</template>
|
||||
<template v-else>
|
||||
<label>
|
||||
Recursion levels:
|
||||
<input type="number" :min="1" :max="10" v-model="recursiveConfig.level">
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" v-model="recursiveConfig.repeat">
|
||||
Repeat images?
|
||||
</label>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,10 +65,10 @@
|
|||
<script lang="ts">
|
||||
import {Component, Prop, Vue, Watch} from "vue-property-decorator";
|
||||
import collageModes, {CollageModeType} from "../collages";
|
||||
import {CollageConfig, CollageMode} from "@/types";
|
||||
import {CollageConfig, CollageMode, Segment} from "@/types";
|
||||
import {choice, shuffle} from "@/utils";
|
||||
|
||||
type DisplayCollageModeType = CollageModeType | & "shuffle";
|
||||
type DisplayCollageModeType = CollageModeType | & "shuffle" | & "recursive";
|
||||
|
||||
@Component
|
||||
export default class Collage extends Vue {
|
||||
|
@ -63,12 +81,16 @@ export default class Collage extends Vue {
|
|||
private collageConfig: CollageConfig = {
|
||||
numImages: undefined
|
||||
};
|
||||
private recursiveConfig = {
|
||||
level: 2,
|
||||
repeat: true
|
||||
};
|
||||
private currentModeType: DisplayCollageModeType = "shuffle";
|
||||
private lastActiveModeType: CollageModeType | null = null;
|
||||
private lastActiveModeTypes: CollageModeType[] = [];
|
||||
private modes = collageModes;
|
||||
|
||||
private get minImages() {
|
||||
if (this.currentModeType === "shuffle") {
|
||||
if (this.currentModeType === "shuffle" || this.currentModeType === "recursive") {
|
||||
return Math.min(...Object.values(this.modes).map((mode) => mode.minImages));
|
||||
} else {
|
||||
return this.modes[this.currentModeType].minImages;
|
||||
|
@ -76,7 +98,9 @@ export default class Collage extends Vue {
|
|||
}
|
||||
|
||||
private get lastMode() {
|
||||
return this.lastActiveModeType ? this.modes[this.lastActiveModeType] : undefined;
|
||||
if (this.lastActiveModeTypes.length === 1) {
|
||||
return this.modes[this.lastActiveModeTypes[0]];
|
||||
}
|
||||
}
|
||||
|
||||
private get forceConfig() {
|
||||
|
@ -91,24 +115,67 @@ export default class Collage extends Vue {
|
|||
@Watch("images")
|
||||
@Watch("currentModeType")
|
||||
@Watch("collageConfig", {deep: true})
|
||||
@Watch("recursiveConfig", {deep: true})
|
||||
private renderCollage() {
|
||||
if (this.images.length >= this.minImages) {
|
||||
this.reset();
|
||||
this.lastActiveModeType = this.currentModeType === "shuffle" ? null : this.currentModeType;
|
||||
|
||||
let mode: CollageMode;
|
||||
if (this.currentModeType === "shuffle") {
|
||||
if (this.currentModeType !== "recursive") {
|
||||
let mode: CollageMode;
|
||||
if (this.currentModeType === "shuffle") {
|
||||
const permissibleModeKeys = Object.keys(collageModes)
|
||||
.filter(k => collageModes[k as CollageModeType].minImages <= this.images.length) as CollageModeType[];
|
||||
const randomModeType = choice(permissibleModeKeys);
|
||||
this.lastActiveModeTypes = [randomModeType];
|
||||
mode = collageModes[randomModeType];
|
||||
} else {
|
||||
this.lastActiveModeTypes = [this.currentModeType];
|
||||
mode = this.modes[this.currentModeType];
|
||||
}
|
||||
const shuffledImages = shuffle(this.images);
|
||||
const segments = mode.getSegments(this.context, this.collageConfig, shuffledImages);
|
||||
mode.place(this.context, shuffledImages, segments);
|
||||
} else {
|
||||
const permissibleModeKeys = Object.keys(collageModes)
|
||||
.filter(k => collageModes[k as CollageModeType].minImages <= this.images.length) as CollageModeType[];
|
||||
const randomModeType = choice(permissibleModeKeys);
|
||||
this.lastActiveModeType = randomModeType;
|
||||
mode = collageModes[randomModeType];
|
||||
} else {
|
||||
mode = this.modes[this.currentModeType];
|
||||
this.lastActiveModeTypes = [];
|
||||
const shuffledImages = shuffle(this.images);
|
||||
const rootSegment: Segment = {x: 0, y: 0, w: this.context.canvas.width, h: this.context.canvas.height};
|
||||
const processSegment = async (segment: Segment, level: number): Promise<ImageBitmap> => {
|
||||
console.log(segment, level);
|
||||
if (segment === rootSegment || level <= this.recursiveConfig.level - 1) {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = segment.w;
|
||||
canvas.height = segment.h;
|
||||
let modeKey = choice(permissibleModeKeys);
|
||||
console.log(modeKey);
|
||||
this.lastActiveModeTypes.push(modeKey);
|
||||
let mode = this.modes[modeKey];
|
||||
let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||
let segments = mode.getSegments(ctx);
|
||||
console.log(segments);
|
||||
let bitmaps = await Promise.all(segments.map((segment) => processSegment(segment, level + 1)));
|
||||
mode.place(ctx, bitmaps, segments);
|
||||
return await createImageBitmap(canvas);
|
||||
} else {
|
||||
if (this.recursiveConfig.repeat) {
|
||||
return choice(shuffledImages);
|
||||
} else {
|
||||
if (shuffledImages.length > 0) {
|
||||
return shuffledImages.pop() as ImageBitmap;
|
||||
} else {
|
||||
throw "RAN OUT OF IMAGES";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
processSegment(rootSegment, 0).then((finalCollage) => {
|
||||
console.log(finalCollage);
|
||||
this.context.drawImage(finalCollage, 0, 0);
|
||||
}).catch((error) => {
|
||||
alert(error);
|
||||
});
|
||||
}
|
||||
const shuffledImages = shuffle(this.images);
|
||||
const segments = mode.getSegments(this.context, this.collageConfig, shuffledImages);
|
||||
mode.place(this.context, shuffledImages, segments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue