| |
| 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)]; |
| } |
| } |
| }); |