1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
| "use strict";
function rendreTexteCercle(cvsDest, texte, police, couleur, taille, coefZoom, attenuationZoomCentre)
{
var cvs;
var ctx;
var angle;
var i;
var j;
var largeurTexte;
var hauteurTexte;
var rayon;
var rx;
var ry;
var x;
var x2;
var xCentre;
var xTexte;
var xTexte_droite;
var y;
var y2;
var yCentre;
var yTexte;
var yTexte_bas;
var pixels;
var pixels2;
const deb = new Date().getTime();
cvs = document.createElement("canvas");
// NOTA : le paramètre taille n'est pas utilisée, on récupère la taille du canvas destination
// Calcul largeur au mieux
const FONT_SIZE = cvsDest.height *1.54; // 1.54 valeur empirique se rapproche de Loralina
const oSpan = document.createElement("SPAN");
oSpan.style.fontSize = FONT_SIZE + "px";
oSpan.style.fontFamily = police;
oSpan.style.position = "absolute";
oSpan.style.top = "-2em";
oSpan.textContent = texte;
// ajout a document pour récup. dimensions
document.body.appendChild(oSpan);
const MAX_LARGEUR = oSpan.offsetWidth;
const MAX_HEIGHT = oSpan.offsetHeight;
// supprime plus besoin
document.body.removeChild(oSpan);
// init context2d
cvs.width = MAX_LARGEUR
cvs.height = FONT_SIZE;
ctx = cvs.getContext("2d");
ctx.textBaseline = "top"; // (!) on place le texte en haut
ctx.font = FONT_SIZE + "px " + police;
ctx.fillStyle = couleur;
ctx.fillText(texte, 0, 0);
// récup. des données
pixels = ctx.getImageData(0, 0, MAX_LARGEUR, MAX_HEIGHT).data;
// ajustage zone d'intérêt
let px;
let col;
let offsetY;
const rectTexte = {};
const bufferLineSize = (MAX_LARGEUR << 2);
// recherche 1st line à partir du début
px = 3;
while (pixels[px] === 0) {
px += 4;
}
rectTexte.top = parseInt(px / bufferLineSize, 10);
// recherche last line à partir de la fin
px = pixels.length - 1;
while (pixels[px] === 0) {
px -= 4;
}
rectTexte.bottom = parseInt(px / bufferLineSize, 10);
const MAX_DATA = rectTexte.bottom * bufferLineSize;
// recherche bord gauche
offsetY = rectTexte.top * bufferLineSize;
col = 3;
px = offsetY + col;
while (pixels[px] === 0) {
px += bufferLineSize;
if (px > MAX_DATA) {
px = (col += 4) + offsetY;
// il faut bien s'arrêter un jour
if (col > bufferLineSize) break;
}
}
rectTexte.left = col >> 2;
// recherche bord droit
col = bufferLineSize - 1;
px = offsetY + col;
while (pixels[px] === 0) {
px += bufferLineSize;
if (px > MAX_DATA) {
px = (col -= 4) + offsetY;
// il faut bien s'arrêter un jour
if (col < 0) break;
}
}
rectTexte.right = col >> 2;
xTexte = rectTexte.left;
yTexte = rectTexte.top;
largeurTexte = rectTexte.right - rectTexte.left;
hauteurTexte = rectTexte.bottom - rectTexte.top;
console.log("Time (1):", new Date().getTime() -deb);
console.log("rectTexte :", rectTexte);
console.log("largeurTexte :", largeurTexte);
console.log("hauteurTexte :", hauteurTexte);
pixels = ctx.getImageData(xTexte, yTexte, largeurTexte, hauteurTexte).data;
yCentre = xCentre = rayon = cvsDest.width * 0.5;
pixels2 = new Uint8ClampedArray(rayon * rayon * 16);
i = pixels.length;
console.log("nbr datas :", i);
// précalcul pour mise en cache
const _2r = rayon * 2;
const coef = Number(attenuationZoomCentre) * (1 - coefZoom);
const rapportX = _2r / largeurTexte;
const rapportY = _2r / hauteurTexte;
// précalcul
const tabAtan2 = [];
const tabX2 = [];
const tabY2 = [];
for (col = 0; col < largeurTexte; col += 1) {
angle = Math.atan2(rayon, (col * rapportX) - xCentre);
tabAtan2.push(angle);
tabX2.push(rayon * Math.cos(angle));
tabY2.push(rayon * Math.sin(angle));
}
// TODO faire la même chose pour les lignes
while ((i -= 4) > 0)
{
col = i >> 2;
//x = ((i / 4) % largeurTexte) * rayon * 2 / largeurTexte - xCentre;
//y = Math.floor((i / 4) / largeurTexte) * rayon * 2 / hauteurTexte - yCentre;
x = ((col) % largeurTexte) * rapportX - xCentre;
y = Math.floor((col) / largeurTexte) * rapportY - yCentre;
//angle = Math.atan2(rayon, x);
//x2 = rayon * Math.cos(angle);
//y2 = rayon * Math.sin(angle);
col %= largeurTexte;
angle = tabAtan2[col];
x2 = tabX2[col];
y2 = tabY2[col];
//rx = rayon * Math.pow(Math.abs(x) / rayon, coefZoom + Number(attenuationZoomCentre) * (1 - coefZoom) * (1 - Math.abs(x) / rayon));
rx = rayon * Math.pow(Math.abs(x) / rayon, coefZoom + coef * (1 - Math.abs(x) / rayon));
ry = y2 / Math.sin(Math.acos(x2 / rx));
angle = Math.atan2(y, x * ry / rx);
//j = 4 * (xCentre + Math.round(rx * Math.cos(angle)) + (yCentre + Math.round(ry * Math.sin(angle))) * rayon * 2);
j = 4 * (xCentre + Math.round(rx * Math.cos(angle)) + (yCentre + Math.round(ry * Math.sin(angle))) * _2r);
if (pixels2[j + 3] === 0)
{
if (pixels[i + 3] !== 0)
{
pixels2[j] = pixels[i];
pixels2[j + 1] = pixels[i + 1];
pixels2[j + 2] = pixels[i + 2];
pixels2[j + 3] = pixels[i + 3];
}
}
else
{
pixels2[j + 3] = (pixels2[j + 3] + pixels[i + 3]) * 0.5;
}
}
cvsDest.getContext("2d").putImageData(new ImageData(pixels2, rayon * 2), 0, 0);
console.log("Time (End):", new Date().getTime() -deb);
}
rendreTexteCercle(document.getElementById("texteCercle"),
"CIRCLE",
"impact",
"#0099FF",
400, //si taille trop petite, le remplissage ne sera pas plein
.8, //[0,1], plus la valeur est petite plus la déformation est forte
true); |
Partager