I need to make an application that needs to draw a point on the image, and when clicked on another location of the image with the same point selected, it deletes the previous point and draws it in the new location. The way I found it to do this is to delete all the canvas content, draw the image and then draw the dot. However, when the point is drawn, it appears that it is being drawn before the image is loaded. Currently I have no options on how to fix this problem. Below I leave the html code of the page, and the javascript file used to do the canvas manipulations. Here is the code:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Landmark Measurement</title>
<link rel="stylesheet" type="text/css" href="http://127.0.0.1:8000/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="http://127.0.0.1:8000/css/bezier.css">
<link rel="stylesheet" type="text/css" href="http://127.0.0.1:8000/css/landmark_system.css">
<link rel="icon" href="http://127.0.0.1:8000/img/favicon.ico">
</head>
<body>
<!-- Wrap all page content here -->
<div id="wrap">
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Landmark Measurement</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="http://127.0.0.1:8000/home">Início</a></li>
<li><a href="#">Ajuda</a></li>
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown">Sair <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="">
<form method="POST" action="http://127.0.0.1:8000/logout">
<input type="hidden" name="_token" value="7s4KE7xeDQn3fufnNO2Z2NQ9sSuSB0ryx1ruo7Td"> <button class="btn btn-primary" type="submit">Logout</button>
</form>
</li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search...">
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active"><a href="#">
<label class="filter-label">Curvas</label>
<select id="curvesId" style="width: 80%; color:black">
<option selected>Selecione</option>
<option onclick="curve()">Perfil Mole</option>
<option>Sela Túrcica</option>
<option>Sutura Fronto-Nasal</option>
<option>Borda Póstero-Inferior</option>
<option>Fissura Pterigomaxilar</option>
<option>Pório Anatômico</option>
<option>Maxila</option>
<option>Mandíbula</option>
<option>Dentes</option>
<option>Incisivos Centrais</option>
<option>Dentes Posteriores</option>
</select>
</a></li>
<li class="active"><a href="#"><label class="filter-label">Pontos</label>
<select id="pointsId" style="width: 80%; color:black">
<option selected>Selecione</option>
<option>Básio (Ba)</option>
<option>Sela (S)</option>
<option>Násio (N)</option>
<option>Espinha nasal anterior (ENA)</option>
<option>Espinha nasal posterior (ENP)</option>
<option>Ponto subespinhal (A)</option>
<option>Ponto pupramental (B)</option>
<option>Próstil (Pr)</option>
<option>Infradental (Id)</option>
<option>Pogônio (Pog)</option>
<option>Gnátio (Gn)</option>
<option>Mento (Me)</option>
<option>Ponto D (D)</option>
<option>Bolton (Bo)</option>
<option>Articular (Ar)</option>
<option>Pório (Po)</option>
<option>Pterigóideo (Pt)</option>
<option>Ponto E (E)</option>
<option>Mentoniano (Men)</option>
<option>Condílio (Co)</option>
<option>Pró-nasal (Pn)</option>
<option>Columela (Cm)</option>
<option>Subnasal (Sn)</option>
<option>Lábio Superior (Ls)</option>
<option>Stomion Superior (Sts)</option>
<option>Pogônio Mole (Pg’)</option>
<option>Palato Mole (pm)</option>
<option>Adenóide (ad)</option>
<option>Ponto bl (bl)</option>
<option>Ponto bf (bf)</option>
</select></a></li>
<li class="active"><a href="#">
<label class="filter-label">Contraste</label>
<input type="range" id="contrast" min="0" max="200" value="100"/>
</a></li>
<li class="active"><a href="#">
<label class="filter-label">Brilho</label>
<input type="range" id="brightness" min="0" max="200" value="100"/>
</a></li>
<li class="active"><a href="#">
<label class="filter-label">Escala de cinza</label>
<input type="range" id="grayscale" min="0" max="100" value="0"/>
</a></li>
<li class="active"><a href="#">
<label class="filter-label">Negativo</label>
<input type="range" id="invert" min="0" max="100" value="0"/>
</a></li>
<li class="active"><a href="#">
<label class="filter-label"><font color="#696969"><input type="button" value="Desfazer"
onclick="reset()"/></font></label>
</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="page-header">
<table class="methods-table" width="400px" border="0">
<tr>
<td>
<input type="image" name="selectImage" src="http://127.0.0.1:8000/img/Abrir.png"onClick="openImageSelection()">
</td>
<td>
<input type="image" name="markStitch" src="http://127.0.0.1:8000/img/Ponto.png"onClick="openWindowSave()">
</td>
<!--<td>
<input type="image" name="generateMeasurement" src="http://127.0.0.1:8000/img/Tracar.png"onClick="this.form.submit()">
</td>-->
<td>
<input type="image" name="unmake" src="http://127.0.0.1:8000/img/Desfazer.png"onClick="desfazer()">
</td>
<td>
<form method="post" action="http://127.0.0.1:8000/image_landmark">
<input type="hidden" name="_token" value="7s4KE7xeDQn3fufnNO2Z2NQ9sSuSB0ryx1ruo7Td"> <input type="hidden" name="savedPoints" id="saved_points" value=""/>
<input type="hidden" name="currentImage" id="current_image" value=""/>
<input type="image" name="save" src="http://127.0.0.1:8000/img/salvar.png"onClick="this.form.submit()">
</form>
</td>
</tr>
</table>
</div>
<canvas id="image"></canvas>
</div>
</div>
<script lang="js">
function openImageSelection() {
window.open("http://127.0.0.1:8000/image", "_blank", "width=600, height=400");
}
function openWindowSave() {
window.open("http://127.0.0.1:8000/image_landmark", "_blank", "width=600, height=400");
}
</script>
</div>
</div>
<div id="footer">
<div class="container">
<p align="center" class="text-muted">
© 2018 <a href="https://github.com/argalvao/">Abel Ramalho Galvão</a> and <a
href="https://github.com/jictyvoo/">João Victor Oliveira Couto</a>. Powered by <a
href="http://php.net"
target="_blank">PHP</a>
</p>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="http://127.0.0.1:8000/js/jquery-3.3.1.min.js"></script><scriptsrc="http://127.0.0.1:8000/js/bootstrap.min.js"></script>
<script language="javascript" src="http://127.0.0.1:8000/js/landmark_selection.js"></script></body></html>
TheJS:
image_url="";
global_points = null;
global_effects = null;
function openImage(path) {
img = new Image();
image_url = path;
let ctx = document.getElementById('image');
ctx.setAttribute("onmousedown", "bezier_coordinate(event)");
if (ctx.getContext) {
ctx = ctx.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = 785;
img.onload = function () {
ctx.drawImage(img, 0, 0, 1050, 785); //draw background image
ctx.fillStyle = "rgba(1, 1, 1, 0)"; //draw a box over the top
};
}
img.src = path;
}
function image(path) {
global_points = [];
global_effects = [];
openImage(path);
reset();
}
function drawLandmark(div, locations) {
let ctx = div.getContext('2d');
ctx.beginPath();
const imageOffset = $("#image").offset();
const imgOfLf = imageOffset.left;
const imgOfTp = imageOffset.top;
ctx.arc(Math.floor(parseInt(locations.X) - imgOfLf), Math.floor(parseInt(locations.Y) - imgOfTp), 4, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#330005';
ctx.stroke();
}
function removeLandmark(canvas, exceptFor) {
let context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
openImage(image_url);
global_points[exceptFor].exist = false;
Object.keys(global_points).forEach(function (element, index, array) {
if (element !== exceptFor) {
drawLandmark(canvas, global_points[element]);
}
});
}
function coordenadas(event) {
const selectedIndex = document.getElementById("pointsId").selectedIndex;
const currentPoint = document.getElementById("pointsId").options[selectedIndex].text;
if (currentPoint !== "Selecione") {
x = event.pageX;
y = event.pageY;
const div = document.getElementById('image');
if (!global_points[currentPoint]) {
global_points[currentPoint] = [];
}
if (global_points[currentPoint].exist) {
removeLandmark(div, currentPoint);
}
global_points[currentPoint].X = x;
global_points[currentPoint].Y = y;
global_points[currentPoint].exist = true;
drawLandmark(div, global_points[currentPoint]);
const data_json = toJSON(global_points);
let hiddenForm = document.getElementById("saved_points");
hiddenForm.setAttribute("value", data_json);
hiddenForm = document.getElementById("current_image");
let imageSource = image_url;
const splicedSource = imageSource.split("/");
imageSource = splicedSource[splicedSource.length - 1].charAt(0);
hiddenForm.setAttribute("value", imageSource);
}
}
function desfazer() {
global_points.htmlPoint.outerHTML = '';
/*erase the point*/
/* will use global_effects array */
}
function toJSON(js_array) {
var returned_json = "{";
for (var key in js_array) {
if (returned_json.length > 1) {
returned_json = returned_json + ",";
}
returned_json = returned_json + "\"" + key + "\":{";
var internalArray = js_array[key];
returned_json = returned_json + "\"X\":" + internalArray.X + ",\"Y\":" + internalArray.Y + "}";
}
returned_json = returned_json + "}";
return returned_json;
}
var brightness = document.getElementById('brightness'),
contrast = document.getElementById('contrast'),
grayscale = document.getElementById('grayscale'),
invert = document.getElementById('invert');
function getValues() {
var filterStyle = "filter: ",
brightnessValue = brightness.value,
contrastValue = contrast.value,
grayscaleValue = grayscale.value,
invertValue = invert.value;
// noinspection JSAnnotator
filterStyle += '
brightness(${brightnessValue}%)
contrast(${contrastValue}%)
grayscale(${grayscaleValue}%)
invert(${invertValue}%)';
return filterStyle;
}
function onChangeValue() {
var imageDiv = document.getElementById('image');
var filterValue = getValues();
imageDiv.setAttribute("style", filterValue);
}
function reset() {
brightness.value = 100;
contrast.value = 100;
grayscale.value = 0;
invert.value = 0;
onChangeValue();
}
function bezier_coordinate(event) {
const selectedIndex = document.getElementById("curvesId").selectedIndex;
const currentCurve = document.getElementById("curvesId").options[selectedIndex].text;
if (currentCurve === "Selecione") {
coordenadas(event);
} else {
bezier_curve(event, currentCurve);
}
}
var elements = document.getElementsByTagName('input');
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener("input", onChangeValue);
}