Compare commits

...

2 Commits

Author SHA1 Message Date
cd35dd58a6 Added base app structure (face detector->not working) 2021-05-03 13:06:34 +02:00
e867ac1d3a Initial webapp 2021-05-03 12:00:09 +02:00
13 changed files with 981721 additions and 420 deletions

View File

@ -1,3 +1,7 @@
# photo_mem
Outil web de sauvegarde des noms des personnes sur les photos et d'identification automatique des visages.
Outil web de sauvegarde des noms des personnes sur les photos et d'identification automatique des visages.
## Détection de visage
La détection de visage utilise la librairie OpenCV.js avec [*"Haar Feature-based Cascade Classifier"*](https://docs.opencv.org/3.4/d2/d99/tutorial_js_face_detection.html).

69
index.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="fr">
<!--
Copyright © 2017-2021 J. PLISSON
Copyleft 🄯 2021-current Liness et al.
License: GNU AGPL v3
-->
<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>photo_mem v1.0.0</title>
<!--v1.0.0 is not actual, it is set in script.js-->
<link rel="stylesheet" href="styles/style.css">
</head>
<body>
<header>
<h1>photo_mem v<span class="version">1.0.0</span></h1>
</header>
<main>
<div class="actions">
<input id="file" multiple type="file" class=cotecote onChange="lecfic(this.files);" />
<input id="file" type="button" class=cotecote value="Enregistrer xml" onclick="enregistrer_fichier(enreg_xml)" />
<input id="file" type="button" class=cotecote value="Enregistrer image " onclick="image_finale()" />
<input type="button" id="detect" value="detect">
</div>
<div style="position: relative; ">
<img src="" id="ima_fond" style="position: absolute; left: 0; top: 0; z-index: 0;">
</div>
<svg class="invisible" style="position: absolute" ;>
<circle id="cirsvg" cx="30" cy="30" r="28" />
</svg>
<div id="ajout" class="invisible" style="position: relative; z-index: 1;">
<form name="ajout_personne">
<center>
<font color="green">NOUVELLE PERSONNE</font>
</center>
Nom : <INPUT type="text" name="nom" id="nom" autofocus><BR>
Née : <INPUT type="text" name="nom_jf" id="nom_jeune_fille"><BR>
Prénom : <INPUT type="text" name="prénom" id="prenom"><BR>
Année : <INPUT type="text" name="année" id="annee"><BR>
Note : <INPUT type="text" name="note" id="note"><BR>
<INPUT type="reset" id="enreg" value="Ajouter" onClick=ajouter_personne_xml();>
<INPUT type="reset" value="Annuler" onClick='document.getElementById("ajout").className="invisible";'>
</form>
</div>
<div id="menu_modif" class="invisible">
<div id="modifier" onClick="window.print();menu.style.visibility='hidden';">modifier </div>
<div id="supprimer" onClick="supprimer_personne();menu.style.visibility='hidden';">supprimer</div>
<div id="annuler" onClick="menu.style.visibility='hidden';">annuler</div>
</div>
</main>
<footer>
<div class="center">
&#127279; Liness <em>et al.</em>
</div>
</footer>
<script src="https://docs.opencv.org/4.5.2/opencv.js"></script>
<script src="scripts/script.js"></script>
<script src="scripts/detector.js"></script>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 898 KiB

After

Width:  |  Height:  |  Size: 898 KiB

35
media/zizou.xml Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<photo>
<titre titx="350px" tity="55px">Coupe du monde 1998 </titre>
<date/>
<lieu/>
<auteur/>
<commentaire/>
<personne>
<nom>Zizou</nom>
<nom_jeune_fille>
</nom_jeune_fille>
<prenom>
</prenom>
<surnom>
</surnom>
<annee_naiss>
</annee_naiss>
<note>
</note>
<position posx="104" posy="132" etx="74px" ety="192px"/>
</personne>
<personne>
<nom>Deschamps </nom>
<nom_jeune_fille>
</nom_jeune_fille>
<prenom>Didier</prenom>
<surnom>
</surnom>
<annee_naiss>
</annee_naiss>
<note>
</note>
<position posx="399" posy="323" etx="369px" ety="383px"/>
</personne>
</photo>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,419 +0,0 @@
<!DOCTYPE HTML>
<!-- Photo_mem v1.6
Copyright © 2017-2021 J. PLISSON -->
<html>
<head>
<meta charset="utf-8"/>
<style>
circle {
fill: transparent;
stroke: black;
stroke-width: 2;
}
#ajout {
border:2px solid red;
border-radius: 10px;
top: 100px;
left: 200px;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
background-color: Azure;
width: 230px;
}
#ajout input:focus {border: solid 2px green;}
.cotecote {display: inline;}
.visible { visibility:visible; }
.invisible { visibility:hidden; }
.etiq {
background-color:oldlace;
border:1px solid blue;
border-radius: 10px;
position:absolute;
font-family: Arial;
font-size: 13px;
left:-200px;
top: 100px;
}
.tit {
background-color:LightYellow;
border: 2px solid Yellow;
border-radius: 5px;
position:absolute;
left:-200px;
top: 100px;
}
#menu_modif {
display: block;
color: black;
background-color: gainsboro;
cursor: pointer;
border: 2px solid;
border-radius: 6px;
text-align: center;
position: absolute;
width: 80px;
z-index: 10;
}
</style>
</head>
<body>
<input id="file" multiple type="file" class=cotecote onChange="lecfic(this.files);"/>
<input id="file" type="button" class=cotecote value="Enregistrer xml" onclick="enregistrer_fichier(enreg_xml)"/>
<input id="file" type="button" class=cotecote value="Enregistrer image " onclick="image_finale()"/>
<div style="position: relative; ">
<img src="" id="ima_fond" style="position: absolute; left: 0; top: 0; z-index: 0;">
</div>
<svg class="invisible" style="position: absolute" ;>
<circle id="cirsvg" cx="30" cy="30" r="28" />
</svg>
<div id="ajout" class="invisible" style="position: relative; z-index: 1;">
<form name="ajout_personne">
<center><font color="green">NOUVELLE PERSONNE</font></center>
Nom : <INPUT type="text" name="nom" id="nom" autofocus><BR>
Née : <INPUT type="text" name="nom_jf" id="nom_jeune_fille"><BR>
Prénom : <INPUT type="text" name="prénom" id="prenom"><BR>
Année : <INPUT type="text" name="année" id="annee"><BR>
Note : <INPUT type="text" name="note" id="note"><BR>
<INPUT type="reset" id="enreg" value="Ajouter" onClick=ajouter_personne_xml();>
<INPUT type="reset" value="Annuler" onClick='document.getElementById("ajout").className="invisible";'>
</form>
</div>
<div id="menu_modif" class="invisible">
<div id="modifier" onClick="window.print();menu.style.visibility='hidden';">modifier </div>
<div id="supprimer" onClick="supprimer_personne();menu.style.visibility='hidden';">supprimer</div>
<div id="annuler" onClick="menu.style.visibility='hidden';">annuler</div>
</div>
<script>
var personnes=[],nom=[],nomjf=[],prenom=[],posx=[],posy=[],etx=[],ety=[], can_etiq=[];
var ibac=0, tit={}, titre="";
var image = document.getElementById('ima_fond');
var cercle = document.getElementById("cirsvg");
var menu = document.getElementById("menu_modif");
var cant = document.createElement("canvas");
document.body.appendChild(cant);
function lecfic(fichier) {
i_xml=0;
if (fichier.length==2) {
for (var i = 0; i < fichier.length; i++) {
var ext=fichier[i].name.split('.').pop();
if (ext=="xml") {i_xml=i};
} ;
}
else {
alert("Choisissez deux fichiers : un .xml et un fichier image");
return;
}
i_img=((i_xml-1)<0 ? 1 : 0);
var fichier_xml=fichier[i_xml];
fond=fichier[i_img];
var src=fichier[i_img].name.substring(0,fichier[i_img].name.indexOf("."));
enreg_xml=src+".xml"
enreg_noms=src+"_noms.png"
var reader = new FileReader();
reader.onload = function(evt) {lecture(evt.target.result);};
reader.readAsText(fichier_xml);
function lecture(text) {
var parser = new DOMParser();
data_xml = parser.parseFromString(text,"text/xml");
affiche_fond();
lecture_xml();
};
}
function lecture_xml() {
personnes = data_xml.documentElement.getElementsByTagName("personne");
tit = data_xml.documentElement.getElementsByTagName("titre")[0];
titre=tit.textContent
nb_pers=personnes.length
for (var i = 0; i < nb_pers; i++) {
nom[i] = personnes[i].getElementsByTagName( "nom")[0].textContent;
if (personnes[i].getElementsByTagName( "nom_jeune_fille")[0]) {
nomjf[i] = personnes[i].getElementsByTagName( "nom_jeune_fille")[0].textContent};
prenom[i] = personnes[i].getElementsByTagName( "prenom")[0].textContent;
posx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posx'].value);
posy[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posy'].value);
etx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['etx'].value);
ety[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['ety'].value);
}
if (titre!=='') {affiche_titre()}
else {affiche_etiquette()} ;
};
// Chargement et dessin de l'image background
function affiche_fond() {
var read_fond = new FileReader();
read_fond.addEventListener("load", function (evt) {
image.src = evt.target.result;
}, false);
read_fond.readAsDataURL(fond);
}
function affiche_titre() {
cant.className="tit";
cant.height=23;
var taille=titre.length;
cant.width=taille*12;
tx = parseFloat(tit.attributes['titx'].value);
ty = parseFloat(tit.attributes['tity'].value);
cant.style.left = tx + "px";
cant.style.top = ty + "px";
titre_ctx = cant.getContext("2d");
titre_ctx.font = '21px Arial';
titre_ctx.fillStyle = 'Maroon';
titre_ctx.fillText(titre, 20, 18);
affiche_etiquette();
}
function affiche_etiquette() {
// affichage du texte nom/prénom dans des canvas etiquette
rayon=28
for (var i = 0; i < nb_pers; i++) {
var id="can"+i;
if (document.getElementById(id)) continue ;
var canv = document.createElement("canvas");
canv.id=id;
document.body.appendChild(canv);
can_etiq[i] = document.getElementById(canv.id);
can_etiq[i].className="etiq";
can_etiq[i].height=30;
etiq_ctx = can_etiq[i].getContext("2d");
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
can_etiq[i].width=taille*7+10
if (nomjf[i].length>1) {can_etiq[i].height=45};
etiq_ctx.font = '13px Arial';
etiq_ctx.fillStyle = 'chocolate';
can_etiq[i].style.left = etx[i] + "px";
can_etiq[i].style.top = ety[i] + "px";
etiq_ctx.fillText(nom[i], 7, 12);
etiq_ctx.fillText(prenom[i], 7, 25);
if (nomjf[i].length>1) {etiq_ctx.fillText("née : "+nomjf[i], 7, 38)};
};
gestion_souris(); // enregistre la position de l'étiquette
};
function gestion_souris() {
if (titre!=='') { // pour déplacer le titre
cant.addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
cant.addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
}
for (var i = 0; i < nb_pers; i++) { // pour déplacer les étiquettes nom,prénom ...
can_etiq[i].addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
can_etiq[i].addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
};
ima_fond.addEventListener('mousedown', afficher_formulaire); // pour afficher le formulaire de saisie personne
ima_fond.addEventListener('mousemove', tracer_cercle); // pour afficher cercle personne
cercle.addEventListener('contextmenu', function (e) { menu_modif(e); e.preventDefault();}, false); // menu modif personne
};
function deplace_etiquette(e){
e.target.style.top = e.pageY-15+"px";
e.target.style.left = e.pageX-30+"px";
};
function menu_modif(){
menu.style.left = parseFloat(cercle.getAttribute("cx"))+10 +"px";
menu.style.top = parseFloat(cercle.getAttribute("cy"))+40 +"px";
menu.style.visibility="visible";
}
function supprimer_personne() {
misajour_xml();
x = data_xml.getElementsByTagName("personne")[ibac];
x.parentNode.removeChild(x);
for (var i = 0; i < nb_pers; i++) {
x = can_etiq[i];
x.parentNode.removeChild(x);
};
cercle.style.visibility="hidden";
lecture_xml();
}
function position_souris(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
};
function tracer_cercle(e) {
document.getElementsByTagName("svg")[0].setAttribute('height', image.naturalHeight);
document.getElementsByTagName("svg")[0].setAttribute('width',image.naturalWidth);
var pos_x=position_souris(ima_fond, e).x;
var pos_y=position_souris(ima_fond, e).y;
for (var i = 0; i < nb_pers; i++) {
var dx = posx[i] - pos_x;
var dy = posy[i] - pos_y;
var dist2 = dx * dx + dy * dy;
var rayon2 = rayon * rayon;
if (dist2 < rayon2) {
ibac=i
bac=can_etiq[i].style.backgroundColor;
can_etiq[i].style.background = "palegreen"
cercle.setAttribute("cx",posx[i]);
cercle.setAttribute("cy",posy[i]);
cercle.setAttribute("r",rayon);
cercle.style.visibility="visible";
// grossir ou diminuer la taille du cercle
// cercle.addEventListener("wheel", function(e) {
// rayon=rayon + (e.deltaY>0 ? -1 : +1);
// cercle.setAttribute("r",rayon );
// } , false);
return
}
};
cercle.style.visibility="hidden";
can_etiq[ibac].style.backgroundColor = "oldlace";
};
function afficher_formulaire(e) {
souris_x = position_souris(ima_fond, e).x ;
souris_y = position_souris(ima_fond, e).y;
if (souris_y-document.getElementById('ajout').height<0) sourisy=50;
document.getElementById('ajout').style.top=souris_y+40+"px";
document.getElementById('ajout').style.left=souris_x-80+"px";
setTimeout(function () { document.getElementById("nom").focus(); },10);
document.getElementById('ajout').className='visible';
};
function ajouter_personne_xml() {
// création d'un nouvel élément <personne> dans data_xml
var nomform=document.getElementById("nom").value
var nomjfform=document.getElementById("nom_jeune_fille").value
var prenomform=document.getElementById("prenom").value
var surnomform=""
var anneeform=document.getElementById("annee").value
var noteform=document.getElementById("note").value
document.getElementById('ajout').className='invisible';
console.log(nomform+" "+prenomform+" "+anneeform)
var personne_ = data_xml.createElement("personne");
var nom_ = data_xml.createElement("nom");
nom_.appendChild(data_xml.createTextNode(nomform));
var nom_jf_ = data_xml.createElement("nom_jeune_fille");
nom_jf_.appendChild(data_xml.createTextNode(nomjfform));
var prenom_ = data_xml.createElement("prenom");
prenom_.appendChild(data_xml.createTextNode(prenomform));
var surnom_ = data_xml.createElement("surnom");
surnom_.appendChild(data_xml.createTextNode(surnomform));
var annee_ = data_xml.createElement("annee_naiss");
annee_.appendChild(data_xml.createTextNode(anneeform));
var note_ = data_xml.createElement("note");
note_.appendChild(data_xml.createTextNode(noteform));
var position_ = data_xml.createElement("position");
position_.setAttribute("posx", souris_x);
position_.setAttribute("posy", souris_y);
position_.setAttribute("etx", souris_x-30);
position_.setAttribute("ety", souris_y+60);
personne_.appendChild(nom_);
personne_.appendChild(nom_jf_);
personne_.appendChild(prenom_);
personne_.appendChild(surnom_);
personne_.appendChild(annee_);
personne_.appendChild(note_);
personne_.appendChild(position_);
data_xml.getElementsByTagName("photo")[0].appendChild(personne_)
lecture_xml();
};
function misajour_xml(){
tit.setAttribute("titx",cant.style.left);
tit.setAttribute("tity",cant.style.top);
for (var i = 0; i < nb_pers; i++) {
position=data_xml.getElementsByTagName( "position")[i];
position.setAttribute("etx",can_etiq[i].style.left);
position.setAttribute("ety",can_etiq[i].style.top);
};
lecture_xml();
} ;
function enregistrer_fichier(fichier) {
misajour_xml()
var texte_xml=(new XMLSerializer()).serializeToString(data_xml)
var reg = /(>)\s*(<)(\/*)/g;
// règle pour enlever id="etiqnn" dans les versions précédentes du fichier xml
var rex=/<personne(.*?)>/g;
texte_xml = texte_xml.replace(rex,'<personne>');
texte_xml = texte_xml.replace(/\r|\n/g, '');
texte_xml = texte_xml.replace(reg, '$1\r\n$2$3');
var blob = new Blob([texte_xml], {type: "text/plain;charset=utf-8"});
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fichier);
} else {
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', fichier);
a.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(texte_xml));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
function image_finale() {
misajour_xml()
var decalx=5;
var decaly=29;
var can_imf = document.createElement("canvas");
document.body.appendChild(can_imf);
imf_ctx = can_imf.getContext("2d");
can_imf.width=ima_fond.width;
can_imf.height=ima_fond.height;
imf_ctx.drawImage(ima_fond,0,0)
if (titre!=='') {
var taille=titre.length;
hauteur=25
roundedRect(imf_ctx,tx-decalx,ty-decaly,taille*11,hauteur,5,'lightyellow','yellow');
imf_ctx.drawImage(cant, tx-decalx, ty-decaly)
};
for (var i = 0; i < nb_pers; i++) {
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
hauteur=30
if (nomjf[i].length>1) {hauteur=45};
roundedRect(imf_ctx,etx[i]-decalx,ety[i]-decaly,taille*7+10,hauteur,15,'oldlace','blue');
imf_ctx.drawImage(can_etiq[i],etx[i]-decalx,ety[i]-decaly)
}
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', enreg_noms);
a.setAttribute('href', can_imf.toDataURL("image/png").replace("image/png", "image/octet-stream"));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
document.body.removeChild(can_imf);
function roundedRect(ctx, x, y, width, height, radius ,couleur_fond ,couleur_trait) {
ctx.beginPath();
ctx.strokeStyle = couleur_trait;
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.closePath();
ctx.fillStyle = couleur_fond;
ctx.fill();
ctx.stroke();
}
}
</script>
</body>
</html>

30
scripts/detector.js Normal file
View File

@ -0,0 +1,30 @@
let img = document.getElementById('ima_fond');
let mat;
img.onload = function() {
mat = cv.imread(img);
document.getElementById('detect').addEventListener('click', function() {
console.log(mat);
let gray = new cv.Mat();
cv.cvtColor(mat, gray, cv.COLOR_RGBA2GRAY, 0);
let faces = new cv.RectVector();
let profiles = new cv.RectVector();
let faceCascade = new cv.CascadeClassifier();
let profileCascade = new cv.CascadeClassifier();
// Load pretrained classifier
faceCascade.load("../models/haarcascade_frontalcatface.xml");
profileCascade.load("../models/haarcascade_profileface.xml");
// Detect faes
let msize = new cv.Size(0, 0);
faceCascade.detectMultiScale(gray, faces, 1.05, 0);
profileCascade.detectMultiScale(gray, profiles, 1.1, 3, 0, msize, msize);
// Show detected faces
faces = faces.concat(profiles);
for (let i = 0; i < faces.length; i++) {
let point1 = new cv.Point(faces.get(i).x, faces.get(i).y);
let point2 = new cv.Point(faces.get(i).x + faces.get(i).width,
faces.get(i).y + faces.get(i).height);
cv.rectangle(mat, point1, point2, [255, 0, 0, 255]);
}
});
}

937071
scripts/opencv.js Normal file

File diff suppressed because one or more lines are too long

373
scripts/script.js Normal file
View File

@ -0,0 +1,373 @@
// Make sure that photo_mem titles displays right version
let version = '1.6.1';
version_spans = document.getElementsByClassName('version');
title = document.getElementsByTagName('title')[0];
title.innerHTML = title.innerHTML.replace('1.0.0', version)
for (span of version_spans) {
span.innerHTML = version
}
// Photo_mem script:
var personnes = [],
nom = [],
nomjf = [],
prenom = [],
posx = [],
posy = [],
etx = [],
ety = [],
can_etiq = [];
var ibac = 0,
tit = {},
titre = "";
var image = document.getElementById('ima_fond');
var cercle = document.getElementById("cirsvg");
var menu = document.getElementById("menu_modif");
var cant = document.createElement("canvas");
document.body.appendChild(cant);
function lecfic(fichier) {
i_xml = 0;
if (fichier.length == 2) {
for (var i = 0; i < fichier.length; i++) {
var ext = fichier[i].name.split('.').pop();
if (ext == "xml") {
i_xml = i
};
};
} else {
alert("Choisissez deux fichiers : un .xml et un fichier image");
return;
}
i_img = ((i_xml - 1) < 0 ? 1 : 0);
var fichier_xml = fichier[i_xml];
fond = fichier[i_img];
var src = fichier[i_img].name.substring(0, fichier[i_img].name.indexOf("."));
enreg_xml = src + ".xml"
enreg_noms = src + "_noms.png"
var reader = new FileReader();
reader.onload = function(evt) {
lecture(evt.target.result);
};
reader.readAsText(fichier_xml);
function lecture(text) {
var parser = new DOMParser();
data_xml = parser.parseFromString(text, "text/xml");
affiche_fond();
lecture_xml();
};
}
function lecture_xml() {
personnes = data_xml.documentElement.getElementsByTagName("personne");
tit = data_xml.documentElement.getElementsByTagName("titre")[0];
titre = tit.textContent
nb_pers = personnes.length
for (var i = 0; i < nb_pers; i++) {
nom[i] = personnes[i].getElementsByTagName("nom")[0].textContent;
if (personnes[i].getElementsByTagName("nom_jeune_fille")[0]) {
nomjf[i] = personnes[i].getElementsByTagName("nom_jeune_fille")[0].textContent
};
prenom[i] = personnes[i].getElementsByTagName("prenom")[0].textContent;
posx[i] = parseFloat(personnes[i].getElementsByTagName("position")[0].attributes['posx'].value);
posy[i] = parseFloat(personnes[i].getElementsByTagName("position")[0].attributes['posy'].value);
etx[i] = parseFloat(personnes[i].getElementsByTagName("position")[0].attributes['etx'].value);
ety[i] = parseFloat(personnes[i].getElementsByTagName("position")[0].attributes['ety'].value);
}
if (titre !== '') {
affiche_titre()
} else {
affiche_etiquette()
};
};
// Chargement et dessin de l'image background
function affiche_fond() {
var read_fond = new FileReader();
read_fond.addEventListener("load", function(evt) {
image.src = evt.target.result;
}, false);
read_fond.readAsDataURL(fond);
}
function affiche_titre() {
cant.className = "tit";
cant.height = 23;
var taille = titre.length;
cant.width = taille * 12;
tx = parseFloat(tit.attributes['titx'].value);
ty = parseFloat(tit.attributes['tity'].value);
cant.style.left = tx + "px";
cant.style.top = ty + "px";
titre_ctx = cant.getContext("2d");
titre_ctx.font = '21px Arial';
titre_ctx.fillStyle = 'Maroon';
titre_ctx.fillText(titre, 20, 18);
affiche_etiquette();
}
function affiche_etiquette() {
// affichage du texte nom/prénom dans des canvas etiquette
rayon = 28
for (var i = 0; i < nb_pers; i++) {
var id = "can" + i;
if (document.getElementById(id)) continue;
var canv = document.createElement("canvas");
canv.id = id;
document.body.appendChild(canv);
can_etiq[i] = document.getElementById(canv.id);
can_etiq[i].className = "etiq";
can_etiq[i].height = 30;
etiq_ctx = can_etiq[i].getContext("2d");
var taille = Math.max(nom[i].length, prenom[i].length, nomjf[i].length + 5);
can_etiq[i].width = taille * 7 + 10
if (nomjf[i].length > 1) {
can_etiq[i].height = 45
};
etiq_ctx.font = '13px Arial';
etiq_ctx.fillStyle = 'chocolate';
can_etiq[i].style.left = etx[i] + "px";
can_etiq[i].style.top = ety[i] + "px";
etiq_ctx.fillText(nom[i], 7, 12);
etiq_ctx.fillText(prenom[i], 7, 25);
if (nomjf[i].length > 1) {
etiq_ctx.fillText("née : " + nomjf[i], 7, 38)
};
};
gestion_souris(); // enregistre la position de l'étiquette
};
function gestion_souris() {
if (titre !== '') { // pour déplacer le titre
cant.addEventListener("mousedown", function(e) {
this.addEventListener("mousemove", deplace_etiquette);
});
cant.addEventListener("mouseup", function(e) {
this.removeEventListener("mousemove", deplace_etiquette);
});
}
for (var i = 0; i < nb_pers; i++) { // pour déplacer les étiquettes nom,prénom ...
can_etiq[i].addEventListener("mousedown", function(e) {
this.addEventListener("mousemove", deplace_etiquette);
});
can_etiq[i].addEventListener("mouseup", function(e) {
this.removeEventListener("mousemove", deplace_etiquette);
});
};
ima_fond.addEventListener('mousedown', afficher_formulaire); // pour afficher le formulaire de saisie personne
ima_fond.addEventListener('mousemove', tracer_cercle); // pour afficher cercle personne
cercle.addEventListener('contextmenu', function(e) {
menu_modif(e);
e.preventDefault();
}, false); // menu modif personne
};
function deplace_etiquette(e) {
e.target.style.top = e.pageY - 15 + "px";
e.target.style.left = e.pageX - 30 + "px";
};
function menu_modif() {
menu.style.left = parseFloat(cercle.getAttribute("cx")) + 10 + "px";
menu.style.top = parseFloat(cercle.getAttribute("cy")) + 40 + "px";
menu.style.visibility = "visible";
}
function supprimer_personne() {
misajour_xml();
x = data_xml.getElementsByTagName("personne")[ibac];
x.parentNode.removeChild(x);
for (var i = 0; i < nb_pers; i++) {
x = can_etiq[i];
x.parentNode.removeChild(x);
};
cercle.style.visibility = "hidden";
lecture_xml();
}
function position_souris(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
};
function tracer_cercle(e) {
document.getElementsByTagName("svg")[0].setAttribute('height', image.naturalHeight);
document.getElementsByTagName("svg")[0].setAttribute('width', image.naturalWidth);
var pos_x = position_souris(ima_fond, e).x;
var pos_y = position_souris(ima_fond, e).y;
for (var i = 0; i < nb_pers; i++) {
var dx = posx[i] - pos_x;
var dy = posy[i] - pos_y;
var dist2 = dx * dx + dy * dy;
var rayon2 = rayon * rayon;
if (dist2 < rayon2) {
ibac = i
bac = can_etiq[i].style.backgroundColor;
can_etiq[i].style.background = "palegreen"
cercle.setAttribute("cx", posx[i]);
cercle.setAttribute("cy", posy[i]);
cercle.setAttribute("r", rayon);
cercle.style.visibility = "visible";
// grossir ou diminuer la taille du cercle
// cercle.addEventListener("wheel", function(e) {
// rayon=rayon + (e.deltaY>0 ? -1 : +1);
// cercle.setAttribute("r",rayon );
// } , false);
return
}
};
cercle.style.visibility = "hidden";
can_etiq[ibac].style.backgroundColor = "oldlace";
};
function afficher_formulaire(e) {
souris_x = position_souris(ima_fond, e).x;
souris_y = position_souris(ima_fond, e).y;
if (souris_y - document.getElementById('ajout').height < 0) sourisy = 50;
document.getElementById('ajout').style.top = souris_y + 40 + "px";
document.getElementById('ajout').style.left = souris_x - 80 + "px";
setTimeout(function() {
document.getElementById("nom").focus();
}, 10);
document.getElementById('ajout').className = 'visible';
};
function ajouter_personne_xml() {
// création d'un nouvel élément <personne> dans data_xml
var nomform = document.getElementById("nom").value
var nomjfform = document.getElementById("nom_jeune_fille").value
var prenomform = document.getElementById("prenom").value
var surnomform = ""
var anneeform = document.getElementById("annee").value
var noteform = document.getElementById("note").value
document.getElementById('ajout').className = 'invisible';
console.log(nomform + " " + prenomform + " " + anneeform)
var personne_ = data_xml.createElement("personne");
var nom_ = data_xml.createElement("nom");
nom_.appendChild(data_xml.createTextNode(nomform));
var nom_jf_ = data_xml.createElement("nom_jeune_fille");
nom_jf_.appendChild(data_xml.createTextNode(nomjfform));
var prenom_ = data_xml.createElement("prenom");
prenom_.appendChild(data_xml.createTextNode(prenomform));
var surnom_ = data_xml.createElement("surnom");
surnom_.appendChild(data_xml.createTextNode(surnomform));
var annee_ = data_xml.createElement("annee_naiss");
annee_.appendChild(data_xml.createTextNode(anneeform));
var note_ = data_xml.createElement("note");
note_.appendChild(data_xml.createTextNode(noteform));
var position_ = data_xml.createElement("position");
position_.setAttribute("posx", souris_x);
position_.setAttribute("posy", souris_y);
position_.setAttribute("etx", souris_x - 30);
position_.setAttribute("ety", souris_y + 60);
personne_.appendChild(nom_);
personne_.appendChild(nom_jf_);
personne_.appendChild(prenom_);
personne_.appendChild(surnom_);
personne_.appendChild(annee_);
personne_.appendChild(note_);
personne_.appendChild(position_);
data_xml.getElementsByTagName("photo")[0].appendChild(personne_)
lecture_xml();
};
function misajour_xml() {
tit.setAttribute("titx", cant.style.left);
tit.setAttribute("tity", cant.style.top);
for (var i = 0; i < nb_pers; i++) {
position = data_xml.getElementsByTagName("position")[i];
position.setAttribute("etx", can_etiq[i].style.left);
position.setAttribute("ety", can_etiq[i].style.top);
};
lecture_xml();
};
function enregistrer_fichier(fichier) {
misajour_xml()
var texte_xml = (new XMLSerializer()).serializeToString(data_xml)
var reg = /(>)\s*(<)(\/*)/g;
// règle pour enlever id="etiqnn" dans les versions précédentes du fichier xml
var rex = /<personne(.*?)>/g;
texte_xml = texte_xml.replace(rex, '<personne>');
texte_xml = texte_xml.replace(/\r|\n/g, '');
texte_xml = texte_xml.replace(reg, '$1\r\n$2$3');
var blob = new Blob([texte_xml], {
type: "text/plain;charset=utf-8"
});
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fichier);
} else {
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', fichier);
a.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(texte_xml));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
function image_finale() {
misajour_xml()
var decalx = 5;
var decaly = 29;
var can_imf = document.createElement("canvas");
document.body.appendChild(can_imf);
imf_ctx = can_imf.getContext("2d");
can_imf.width = ima_fond.width;
can_imf.height = ima_fond.height;
imf_ctx.drawImage(ima_fond, 0, 0)
if (titre !== '') {
var taille = titre.length;
hauteur = 25
roundedRect(imf_ctx, tx - decalx, ty - decaly, taille * 11, hauteur, 5, 'lightyellow', 'yellow');
imf_ctx.drawImage(cant, tx - decalx, ty - decaly)
};
for (var i = 0; i < nb_pers; i++) {
var taille = Math.max(nom[i].length, prenom[i].length, nomjf[i].length + 5);
hauteur = 30
if (nomjf[i].length > 1) {
hauteur = 45
};
roundedRect(imf_ctx, etx[i] - decalx, ety[i] - decaly, taille * 7 + 10, hauteur, 15, 'oldlace', 'blue');
imf_ctx.drawImage(can_etiq[i], etx[i] - decalx, ety[i] - decaly)
}
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', enreg_noms);
a.setAttribute('href', can_imf.toDataURL("image/png").replace("image/png", "image/octet-stream"));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
document.body.removeChild(can_imf);
function roundedRect(ctx, x, y, width, height, radius, couleur_fond, couleur_trait) {
ctx.beginPath();
ctx.strokeStyle = couleur_trait;
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.closePath();
ctx.fillStyle = couleur_fond;
ctx.fill();
ctx.stroke();
}
}

66
styles/style.css Normal file
View File

@ -0,0 +1,66 @@
circle {
fill: transparent;
stroke: black;
stroke-width: 2;
}
#ajout {
border: 2px solid red;
border-radius: 10px;
top: 100px;
left: 200px;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
background-color: Azure;
width: 230px;
}
#ajout input:focus {
border: solid 2px green;
}
.cotecote {
display: inline;
}
.visible {
visibility: visible;
}
.invisible {
visibility: hidden;
}
.etiq {
background-color: oldlace;
border: 1px solid blue;
border-radius: 10px;
position: absolute;
font-family: Arial;
font-size: 13px;
left: -200px;
top: 100px;
}
.tit {
background-color: LightYellow;
border: 2px solid Yellow;
border-radius: 5px;
position: absolute;
left: -200px;
top: 100px;
}
#menu_modif {
display: block;
color: black;
background-color: gainsboro;
cursor: pointer;
border: 2px solid;
border-radius: 6px;
text-align: center;
position: absolute;
width: 80px;
z-index: 10;
}