|
|
|
|
|
class Region { |
|
|
#weight = 1; |
|
|
constructor(x, y, width, height, prompt, weight) { |
|
|
this.enabled = true; |
|
|
this.x = x; |
|
|
this.y = y; |
|
|
this.width = Math.max(width, 16); |
|
|
this.height = Math.max(height, 16); |
|
|
this.prompt = prompt; |
|
|
this.weight = weight; |
|
|
this.mouse_drag_offset = { x: 0, y: 0 }; |
|
|
this.tool_operation_mode = "none"; |
|
|
this.selected = false; |
|
|
} |
|
|
get weight() { |
|
|
return this.#weight; |
|
|
} |
|
|
set weight(value) { |
|
|
if (value > 1) { |
|
|
value = 1; |
|
|
} else if (value < -1) { |
|
|
value = -1; |
|
|
} |
|
|
this.#weight = value; |
|
|
} |
|
|
snap(canvas_width, canvas_height, rows, columns) { |
|
|
this.stayWithinBounds(canvas_width, canvas_height); |
|
|
let cell_width = Math.round(canvas_width / columns); |
|
|
let cell_height = Math.round(canvas_height / rows); |
|
|
|
|
|
this.x = Math.round(this.x / cell_width) * cell_width; |
|
|
this.y = Math.round(this.y / cell_height) * cell_height; |
|
|
|
|
|
this.width = Math.max(Math.round(this.width / cell_width) * cell_width, 16); |
|
|
this.height = Math.max(Math.round(this.height / cell_height) * cell_height, 16); |
|
|
|
|
|
} |
|
|
|
|
|
getRatios(canvas_width, canvas_height) { |
|
|
let w = canvas_width / (this.width) |
|
|
let h = canvas_height / (this.height) |
|
|
return { |
|
|
division: [h, w], |
|
|
position: [this.y / (canvas_height / h), this.x / (canvas_width / w)] |
|
|
}; |
|
|
} |
|
|
|
|
|
onMouseMove(mouse_position, canvas_width, canvas_height) { |
|
|
if (this.enabled == false) { |
|
|
return |
|
|
} |
|
|
if (this.selected) { |
|
|
if(this.tool_operation_mode == "move") { |
|
|
this.move({ |
|
|
x: mouse_position.x - this.mouse_drag_offset.x, |
|
|
y: mouse_position.y - this.mouse_drag_offset.y}, |
|
|
canvas_width, canvas_height); |
|
|
} |
|
|
if(this.tool_operation_mode == "scale") { |
|
|
this.scale({ |
|
|
x: mouse_position.x, |
|
|
y: mouse_position.y}, |
|
|
canvas_width, canvas_height); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
selectIfMouseOver(mouse_position) { |
|
|
if (this.enabled == false) { |
|
|
return |
|
|
} |
|
|
|
|
|
if (this.pointInside(mouse_position)) { |
|
|
this.mouse_drag_offset = { x: mouse_position.x - this.x, y: mouse_position.y - this.y }; |
|
|
this.selected = true; |
|
|
this.tool_operation_mode = "move"; |
|
|
} |
|
|
|
|
|
|
|
|
if (this.pointInsideScaleControl(mouse_position)) { |
|
|
this.tool_operation_mode = "scale"; |
|
|
} |
|
|
|
|
|
return this.selected; |
|
|
} |
|
|
|
|
|
|
|
|
onMouseUp(mouse_position) { |
|
|
if (this.enabled == false) { |
|
|
return |
|
|
} |
|
|
if (this.selected) { |
|
|
this.selected = false; |
|
|
this.tool_operation_mode = "none"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
onMouseLeave(canvas_width, canvas_height) { |
|
|
if (this.enabled == false) { |
|
|
return |
|
|
} |
|
|
if (this.selected) { |
|
|
this.selected = false; |
|
|
this.tool_operation_mode = "none"; |
|
|
|
|
|
this.stayWithinBounds(canvas_width, canvas_height); |
|
|
} |
|
|
} |
|
|
|
|
|
stayWithinBounds(canvas_width, canvas_height) { |
|
|
this.stayInBoundsWhileMoving(canvas_width, canvas_height); |
|
|
this.stayWithinBoundsWhileScaling(canvas_width, canvas_height); |
|
|
} |
|
|
|
|
|
stayWithinBoundsWhileScaling(canvas_width, canvas_height) { |
|
|
if (this.x + this.width > canvas_width) { |
|
|
this.width = canvas_width - this.x; |
|
|
} |
|
|
if (this.y + this.height > canvas_height) { |
|
|
this.height = canvas_height - this.y; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
stayInBoundsWhileMoving(canvas_width, canvas_height) { |
|
|
this.x = Math.max(0, Math.min(this.x, canvas_width - this.width)); |
|
|
this.y = Math.max(0, Math.min(this.y, canvas_height - this.height)); |
|
|
} |
|
|
|
|
|
move(point, canvas_width, canvas_height) { |
|
|
this.x = Math.round(point.x); |
|
|
this.y = Math.round(point.y); |
|
|
this.stayInBoundsWhileMoving(canvas_width, canvas_height); |
|
|
} |
|
|
|
|
|
scale(point, canvas_width, canvas_height) { |
|
|
console.log("Scaling") |
|
|
this.width = point.x - this.x + 8; |
|
|
this.height = point.y - this.y + 8; |
|
|
|
|
|
if (this.width < 16) { |
|
|
this.width = 16; |
|
|
} |
|
|
if (this.height < 16) { |
|
|
this.height = 16; |
|
|
} |
|
|
this.stayWithinBoundsWhileScaling(canvas_width, canvas_height); |
|
|
} |
|
|
|
|
|
pointInside(point) { |
|
|
return ( |
|
|
point.x >= this.x && |
|
|
point.x <= this.x + this.width && |
|
|
point.y >= this.y && |
|
|
point.y <= this.y + this.height |
|
|
); |
|
|
} |
|
|
|
|
|
pointInsideScaleControl(point) { |
|
|
return ( |
|
|
point.x >= this.x + this.width - 16 && |
|
|
point.x <= this.x + this.width && |
|
|
point.y >= this.y + this.height - 16 && |
|
|
point.y <= this.y + this.height); |
|
|
|
|
|
} |
|
|
|
|
|
draw(ctx, label) { |
|
|
if (this.enabled == false) { |
|
|
return |
|
|
} |
|
|
ctx.beginPath(); |
|
|
ctx.fillStyle = 'rgba(0,0,0,0.65)'; |
|
|
ctx.lineWidth = 1; |
|
|
ctx.fillRect(this.x, this.y, this.width, this.height); |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.fillStyle = 'rgba(255,0,0,0.5)'; |
|
|
ctx.lineWidth = 1; |
|
|
ctx.fillRect(this.x + this.width - 16, this.y + this.height - 16, 16, 16); |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.strokeStyle = 'rgba(255,255,255,1)'; |
|
|
ctx.lineWidth = 2; |
|
|
ctx.strokeRect(this.x, this.y, this.width, this.height); |
|
|
ctx.closePath(); |
|
|
ctx.fill(); |
|
|
|
|
|
if(this.selected) { |
|
|
ctx.beginPath(); |
|
|
|
|
|
ctx.strokeStyle = 'rgba(255,0,0,1)'; |
|
|
ctx.lineWidth = 4; |
|
|
ctx.rect(this.x, this.y, this.width, this.height); |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
} |
|
|
|
|
|
ctx.fillStyle = 'rgba(255,255,255,1)'; |
|
|
ctx.font = '16px Arial'; |
|
|
ctx.textAlign = 'center'; |
|
|
ctx.textBaseline = 'middle'; |
|
|
ctx.fillText(label, this.x + this.width / 2, this.y + this.height / 2); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
var latent_couple_mapper = new Vue({ |
|
|
el: '#latent_couple_mapper', |
|
|
mounted:function(){ |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
data: { |
|
|
regions: [], |
|
|
grid_enabled: true, |
|
|
grid_rows: 8, |
|
|
grid_columns: 8, |
|
|
image_loaded: false, |
|
|
image_resource: null, |
|
|
canvas_width: 512, |
|
|
canvas_height: 512, |
|
|
global_region: new Region(0, 0, 512, 512, "", 0.2), |
|
|
instructions_visible: false, |
|
|
|
|
|
}, |
|
|
watch: { |
|
|
canvas_width: function() { |
|
|
this.$refs.canvas.width = Math.max(this.canvas_width, 64); |
|
|
this.global_region.width = this.$refs.canvas.width; |
|
|
for(let i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].stayWithinBounds(this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
canvas_height: function() { |
|
|
|
|
|
this.$refs.canvas.height = Math.max(this.canvas_height, 64); |
|
|
this.global_region.height = this.$refs.canvas.height; |
|
|
for(let i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].stayWithinBounds(this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
regions: { |
|
|
handler(_) { |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
deep: true |
|
|
}, |
|
|
grid_enabled: function(enabled) { |
|
|
this.redrawCanvas(); |
|
|
|
|
|
}, |
|
|
grid_rows: function(rows) { |
|
|
this.redrawCanvas(); |
|
|
|
|
|
}, |
|
|
grid_columns: function(columns) { |
|
|
this.redrawCanvas(); |
|
|
|
|
|
} |
|
|
}, |
|
|
methods: { |
|
|
toggle_instructions: function() { |
|
|
this.instructions_visible = !this.instructions_visible; |
|
|
}, |
|
|
canvas_loaded: function() { |
|
|
return this.$refs.canvas != null; |
|
|
}, |
|
|
divisions: function() { |
|
|
if (this.canvas_loaded() == false) { |
|
|
return "???"; |
|
|
} |
|
|
output = "" |
|
|
all_regions = [this.global_region].concat(this.regions).filter(function(region) { |
|
|
return region.enabled; |
|
|
}); |
|
|
for (var i = 0; i < all_regions.length; i++) { |
|
|
d = all_regions[i].getRatios(this.$refs.canvas.width, this.$refs.canvas.height).division |
|
|
output += `${d[0].toFixed(2)}:${d[1].toFixed(2)}` |
|
|
if (i < all_regions.length - 1) { |
|
|
output += ','; |
|
|
} |
|
|
} |
|
|
return output; |
|
|
}, |
|
|
positions: function() { |
|
|
if (this.canvas_loaded() == false) { |
|
|
return "???"; |
|
|
} |
|
|
output = "" |
|
|
all_regions = [this.global_region].concat(this.regions).filter(function(region) { |
|
|
return region.enabled; |
|
|
}); |
|
|
for (var i = 0; i < all_regions.length; i++) { |
|
|
p = all_regions[i].getRatios(this.$refs.canvas.width, this.$refs.canvas.height).position |
|
|
output += `${p[0].toFixed(2)}:${p[1].toFixed(2)}` |
|
|
if (i < all_regions.length - 1) { |
|
|
output += ','; |
|
|
} |
|
|
} |
|
|
return output; |
|
|
}, |
|
|
weights: function() { |
|
|
if (this.canvas_loaded() == false) { |
|
|
return "???"; |
|
|
} |
|
|
output = "" |
|
|
all_regions = [this.global_region].concat(this.regions).filter(function(region) { |
|
|
return region.enabled; |
|
|
}); |
|
|
for (var i = 0; i < all_regions.length; i++) { |
|
|
output += all_regions[i].weight.toFixed(2).toString() |
|
|
if (i < all_regions.length - 1) { |
|
|
output += ','; |
|
|
} |
|
|
} |
|
|
return output; |
|
|
}, |
|
|
prompt: function() { |
|
|
output = "" |
|
|
all_regions = [this.global_region].concat(this.regions).filter(function(region) { |
|
|
return region.enabled; |
|
|
}); |
|
|
for (var i = 0; i < all_regions.length; i++) { |
|
|
output += all_regions[i].prompt |
|
|
if (i < all_regions.length - 1) { |
|
|
output += '\nAND '; |
|
|
} |
|
|
} |
|
|
return output; |
|
|
}, |
|
|
setCanvasWidth(canvas_width) { |
|
|
this.$refs.canvas.width = canvas_width; |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
setCanvasHeight(canvas_height) { |
|
|
this.$refs.canvas.height = canvas_height; |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
uploadImage: function(e) { |
|
|
this.image_loaded = false; |
|
|
const reader = new FileReader(); |
|
|
reader.onload = (event) => { |
|
|
this.image_resource = new Image(); |
|
|
this.image_resource.onload = () => { |
|
|
this.canvas_width = this.image_resource.width; |
|
|
this.canvas_height = this.image_resource.height; |
|
|
this.image_loaded = true; |
|
|
for(let i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].stayWithinBounds(this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}; |
|
|
this.image_resource.src = event.target.result; |
|
|
}; |
|
|
reader.readAsDataURL(e.target.files[0]); |
|
|
|
|
|
}, |
|
|
|
|
|
selectNone: function() { |
|
|
for (let i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].selected = false; |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
|
|
|
selectRegion: function(region) { |
|
|
this.selectNone(); |
|
|
region.selected = true; |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
|
|
|
getSelectedRegion: function() { |
|
|
for (let i = 0; i < this.regions.length; i++) { |
|
|
if(this.regions[i].selected == true) { |
|
|
return this.regions[i]; |
|
|
} |
|
|
} |
|
|
return null; |
|
|
}, |
|
|
|
|
|
snapAllRegions: function() { |
|
|
for (let i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].snap(this.$refs.canvas.width, this.$refs.canvas.height, this.grid_rows, this.grid_columns); |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
|
|
|
redrawCanvas: function () { |
|
|
var ctx = this.$refs.canvas.getContext('2d'); |
|
|
|
|
|
|
|
|
ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
|
|
|
|
|
|
if (this.image_loaded) { |
|
|
ctx.drawImage(this.image_resource, 0, 0); |
|
|
} |
|
|
else { |
|
|
ctx.fillStyle = "white"; |
|
|
ctx.fillRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
|
|
|
|
|
|
if (this.grid_enabled) { |
|
|
|
|
|
|
|
|
var cell_width = this.$refs.canvas.width / this.grid_columns; |
|
|
var cell_height = this.$refs.canvas.height / this.grid_rows; |
|
|
ctx.strokeStyle = 'rgba(0,0,0,0.6)'; |
|
|
for (var i = 0; i < this.grid_columns; i++) { |
|
|
ctx.beginPath(); |
|
|
ctx.moveTo(i * cell_width, 0); |
|
|
ctx.lineWidth = 1; |
|
|
ctx.lineTo(i * cell_width, this.$refs.canvas.height); |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
} |
|
|
for (var j = 0; j < this.grid_rows; j++) { |
|
|
ctx.beginPath(); |
|
|
ctx.moveTo(0, j * cell_height); |
|
|
ctx.lineWidth = 1; |
|
|
ctx.lineTo(this.$refs.canvas.width, j * cell_height); |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (var i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].draw(ctx, (i + 1).toString()); |
|
|
} |
|
|
|
|
|
}, |
|
|
deleteRegion(region) { |
|
|
this.regions.splice(this.regions.indexOf(region), 1); |
|
|
this.selectNone(); |
|
|
}, |
|
|
onCanvasMouseDown: function(event) { |
|
|
var canvas = event.target; |
|
|
var x = event.pageX - canvas.offsetLeft; |
|
|
var y = event.pageY - canvas.offsetTop; |
|
|
|
|
|
|
|
|
for (var i = this.regions.length - 1; i >= 0; i--) { |
|
|
if (event.which == 1) { |
|
|
if (this.regions[i].selectIfMouseOver({x: x, y: y})){ |
|
|
break; |
|
|
} |
|
|
} else if (event.which == 3) { |
|
|
if (this.regions[i].selectIfMouseOver({x: x, y: y})){ |
|
|
this.deleteRegion(this.getSelectedRegion()); |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (this.getSelectedRegion() == null) { |
|
|
if (event.which == 1) { |
|
|
new_region = new Region(x, y, 16, 16, "", 0.8); |
|
|
this.regions.push(new_region); |
|
|
this.selectRegion(new_region); |
|
|
new_region.tool_operation_mode = "scale"; |
|
|
} |
|
|
} |
|
|
|
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
|
|
|
onCanvasMouseMove: function (event) { |
|
|
var canvas = event.target; |
|
|
var x = event.pageX - canvas.offsetLeft; |
|
|
var y = event.pageY - canvas.offsetTop; |
|
|
|
|
|
|
|
|
for (var i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].onMouseMove({x: x, y: y}, this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
|
|
|
this.redrawCanvas(); |
|
|
|
|
|
}, |
|
|
onCanvasMouseUp: function(event) { |
|
|
var canvas = event.target; |
|
|
var x = event.pageX - canvas.offsetLeft; |
|
|
var y = event.pageY - canvas.offsetTop; |
|
|
|
|
|
for (var i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].onMouseUp({x: x, y: y}); |
|
|
} |
|
|
this.redrawCanvas(); |
|
|
}, |
|
|
|
|
|
onCanvasMouseLeave: function(event) { |
|
|
for (var i = 0; i < this.regions.length; i++) { |
|
|
this.regions[i].onMouseLeave(this.$refs.canvas.width, this.$refs.canvas.height); |
|
|
} |
|
|
}, |
|
|
getRatios: function(region){ |
|
|
return region.getRatios(this.$refs.canvas.width, this.$refs.canvas.height) |
|
|
}, |
|
|
copyText(text) { |
|
|
navigator.clipboard.writeText(text); |
|
|
} |
|
|
}, |
|
|
computed: { |
|
|
nick: function() { |
|
|
|
|
|
let nicknames = ["DeepDreamDestroyer", "Artificial Artist", "Synthetic Sorcerer", "The IP Bandit", "Hue Hacker", "AInomaly", "Deep Dream Disaster", "The Property Intellectual", "Content Crook, Let Him Cook", "The Canvas Caper", "Cyber Surrealist", "The Trademark Terrorist", "Infringe This", "NeuralNetNinja", "The Photo Copyer", "GANtastic", "Pixel Pirate", "Oops I Stole Your Art :3"] |
|
|
return nicknames[Math.floor(Math.random() * nicknames.length)]; |
|
|
} |
|
|
} |
|
|
}); |