• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

Dynamisch sich anpassende Frequenzskala.

xorg1990

New member
Hi,
ich versuche Algorithmus zu programmieren der mir eine Frequenzskala dynamisch an ein canvas anpasst.

Soll heißen: ein User leget eine Canvas größe fest, 800x600 oder 1024*768 usw. und die Bandbreite die er darstellen möchten von 100-1500Hz oder 0-100hz usw..
Habe schon zig Versuche unternommen doch es passt nicht, irgendwie muss man ein zusammen Spiel zwischen “Anzal der Zeilen“ und „den an zu zeigen werten finden“.
Egal was ich unternehme es klappt nicht. Der Abstand der Zeilen sollte nicht kleiner sein als ein Buchstabe groß(hoch) ist sein. Ein Buchstabe ist bei ein Schriftgröße von 12px, 7px hoch, dass habe ich via offsetHeight ermittelt.

Aus übersichtlichen gründen finde ich es besser jede 2te Zeile nur ein Strich zu machen, dass ist aber optional uns muss nicht sein.

habe da schon mal was vorbereitet:
Code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head>
    <title>null</title>
    <script type="text/javascript">
	
function RederFreqAxsis(){
if (typeof document.test != "undefined") {
                var F_min = parseInt(document.test.Fmin.value);
		var F_max = parseInt(document.test.Fmax.value);
    }
    
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//erzeuge ein span für test länge berechnen 
var Ziffernblock = document.getElementById("Text");

var ruler = document.createElement("canvas");
var ruler_ctx = ruler.getContext('2d');
ruler.width=80;
ruler.height=canvas.height;
ruler_ctx.fillStyle = "white"
ruler_ctx.fillRect(0,0,80,canvas.height);


var F_band=F_max-F_min;//Darzustellende Bandbreite in hz
var Az = 24;//Anzahl Zeilen
var Sa = Math.round((canvas.height/Az));
var schritt = Math.round(F_band/Az);//Schritte in Hz


console.log(F_band,Sa,schritt);


var k=0;
var string=F_min;

for(var i =canvas.height+Az;i>0;i-=Az,string+=schritt,k++){
    Ziffernblock.innerHTML=string+" Hz";
    if (k%2 == 0) {//mod ==1 erst Zahlen, mod==0 erst stich dann Zahlen
	ruler_ctx.beginPath();
	 ruler_ctx.lineWidth="1";
	ruler_ctx.strokeStyle="black";
	ruler_ctx.moveTo(5,i-Sa);
	 ruler_ctx.lineTo(80,i-Sa);
	 ruler_ctx.stroke();
    }else{
    ruler_ctx.font="12px Calibri";
    ruler_ctx.fillStyle="red"
    ruler_ctx.fillText(Ziffernblock.innerText,5,i-Sa+3);
    
    
    ruler_ctx.beginPath();
    ruler_ctx.lineWidth="1";
    ruler_ctx.strokeStyle="black";
    ruler_ctx.moveTo(Ziffernblock.innerText.length*7,i-Sa);
    ruler_ctx.lineTo(80,i-Sa);
    ruler_ctx.stroke();
    }
    
    
    
    
}
console.log(Ziffernblock.innerText.length);


var tempCanvas = document.createElement("canvas"),
tempCtx = tempCanvas.getContext("2d");
tempCanvas.width=canvas.width;
tempCanvas.height=canvas.height;


ctx.drawImage(ruler,canvas.width-250,0);
}
</script>
    
 </head>
<body onload=RederFreqAxsis()>
    
<form name=test>
    <input type="number" name="Fmin" value=100>Min<br>
    <input type="number" name="Fmax" value=1000>Max
	<input type="button" value="Feuer frei" onclick="RederFreqAxsis()">
</form>

<canvas id="canvas" width="1024" height="768" style="display: block; background-color: black ;"</canvas>
<span id="Text" style="visibility: hidden; font-size: 12px;"</span>


</body>
</html>

Der kleinere Wert soll immer unten stehen der große immer ganz oben im canvas.
die Variable Az habe ich zu Schluss hergeholt, wo ich mir gedacht habe…hm legste halt fest 800*600bis1027*768, 24Zeilen und größer,50 Zeilen kleiner als 600 eben 15 Zeilen.
Hat aber am Ende auch nicht geklappt.

Am ende ist das ganz einfach, ich krige das nicht ohne Hilfe raus.
VG xorg1990
 
Zuletzt bearbeitet:
innerText scheint in Firefox nicht zu funktionieren, dies wird hier diskutiert:
javascript - 'innerText' works in IE, but not in Firefox - Stack Overflow
Wenn man es durch innerHTML ersetzt, funktioniert dein Code und das Lineal wird angezeigt, allerdings verstehe ich die Systematik in der Beschriftung nicht und der obere Grenzwert scheint auch nicht zu stimmen.
Außerdem hattest Du zwei Tags nicht geschlossen, so ist es richtig:
HTML:
<canvas id="canvas" width="1024" height="768" style="display: block; background-color: black ;"></canvas>
<span id="Text" style="visibility: hidden; font-size: 12px;"></span>
Ich empfehle dir, dich mit der Fehlerkonsole und dem Debugger vertraut zu machen, damit findet man solche Fehler.
Edit: Habe jetzt erst gesehen, dass das gar nicht dein Problem ist, sondern die Einteilung des Lineals. Wenn man mit Frequenzen arbeitet, wählt man eher eine logarithmische Einteilung.
 
Zuletzt bearbeitet:
Sempervivum schrieb:
innerText scheint in Firefox nicht zu funktionieren
Oh, gut zu wissen aber das ist ich das Problem. Ich hatte nach ner Methode gesucht die Stringlänge in px auszugeben. Das span tag nehme ich dann weider raus. Habe einen andren Weg gefunden.
Der Code ist ohne hin nur beispiel, damit ihr nachvollziehen könnt was ich mein.

Sempervivum schrieb:
obere Grenzwert scheint auch nicht zu stimmen.
Genau das ist das Problem, ich weiß nicht durch wie viele Schleifendurchläufe ich brauche und was ich pro Durchlauf auf var string aufaddieren muss damit es oben passt:(.

Am ende habe ich nur 4 werte canvas höhe, Freq max,-min, F_band(die Anzuzeigende Bandbreite)
Was muss nun gerechnet werden damit ich ein immer valide Frequenzskala habe. Irgend wie habe ich da ein Brett vorm Kopf.
 
Mir scheint, Du hast in deiner for-Schleife etwas falsch gemacht:
Code:
//            for (var i = canvas.height + Az; i > 0; i -= Az, string += schritt, k++) {
            for (var i = canvas.height + Sa; i > 0; i -= Sa, string += schritt, k++) {
Damit keine "krummen" Werte bei der Beschriftung und der Schrittweite herauskommen, habe ich mal etwas ausgearbeitet, so dass die Schrittweite immer ein Zehnerexponent von 1, 2 oder 5 ist:
Code:
            var F_band = F_max - F_min; //Darzustellende Bandbreite in hz
            var Az = 24; //Anzahl Zeilen
            step1 = F_band / Az;
            var exp = Math.floor(Math.log(step1) / Math.LN10);
            var stepnorm = step1 / Math.pow(10, exp);
            if (stepnorm < 1.5) step2 = 1; else if (stepnorm < 3.5) step2 = 2; else step2 = 5;
            schritt = step2 * Math.pow(10, exp);
            Az = F_band / schritt;


            var Sa = Math.round((canvas.height / Az));
            //var schritt = Math.round(F_band / Az); //Schritte in Hz


            console.log(F_band, Az, schritt);


            var k = 0;
            var string = F_min;

//            for (var i = canvas.height + Az; i > 0; i -= Az, string += schritt, k++) {
            for (var i = canvas.height + Sa; i > 0; i -= Sa, string += schritt, k++) {
Hoffe, dies ist in etwa das, was Du erreichen wolltest.
 
Hura, jaaa, brafo, :cool:
Das habe ich gesucht, ich bin ewig nicht auf das Wort Exponent gekommen :beaten:

Eines muss ich doch noch ankreiden. Wenn das canvas 900px hoch ist und eine Bandbreite 900Hz habe ist mir die sakra zu grob, mann müsste also Az verdoppeln, damit es schick aussieht.
Stelle ich allerdings Min 773.25 und max 789.71 Hz ein dann sieht das schon schick aus. Kann man jetzt Az auch noch dynamisch anpassen oder der muss ich da 2,3 else ifs machen, also wenn höhe<800px dann so und so, wenn >900 so
 
Zuletzt bearbeitet:
Das ist der Preis dafür, dass in der Abstufung der Skala nur glatte Werte auftreten, daher kann die Schrittweite in Pixel um bis zu dem Faktor 2,5 variieren. Du kannst dies nur verbessern, wenn Du Nachkommastellen zulässt, etwa so:
Code:
             if (stepnorm < 1.3) step2 = 1;
             else if (stepnorm < 1.8) step2 = 1.5;
             else if (stepnorm < 2.2) step2 = 2;
             else if (stepnorm < 4.2) step2 = 3.5;
             else if (stepnorm < 6.5) step2 = 5;
             else step2 = 7.5;
 
Zuletzt bearbeitet:
Tacho,
Ne das hatte ich nicht gemeint, ich meinte den Zeilenabstand oder die anzahl der Schleifendurchläufe.
Der hinweiß mit den Kommastellen ist auch nicht falsch gewesen, habe noch ne Rundungsfunktion eingebaut, die auf 2 Nachkommastellen rundet.

Code:
function Round(zahl,n){
    var faktor;
    faktor = Math.pow(10,n);
    return(Math.round(zahl * faktor) / faktor);
}
toFixed ging nicht das hatte immer Kommastellen erzeugt.

Das mit den Schleifendurchläufen habe ich gelöst in dem ich de Höhe eines Buchstaben in px berechen, dass geht wiederum durch ein canvas.
Steht auch hier geschrieben:
canvas - Calculate exact character\string height in javascript - Stack Overflow

Das Ergebnis rechne ich dann nochmal durch 2(damit's nicht ganz so dicht wird) und dann durch die canvas höhe.
Das Ergebnis kann sich sehn lassen.
SkalaFreq.png
Ok oben ist es über 139 aber schei** drauf.
Bin überhaut mal gespant ob der Browser das Spektrum so fein gerendert bekommt oder ob man dann grobkörnige Pixel sieht:grey:

Tausend dank
MfG xorg1990

- - - Aktualisiert - - -

Geändert von Sempervivum (Heute um 20:30 Uhr)

3min zu spät geantwortet :rolleyes:

- - - Aktualisiert - - -

Ei karamba, wir haben doch noch ein Problem, und zwar war ich grade auf der Website vom DK7FC und der hat Auflösungen von 47µHz
60000.jpg

allerdings auch ist das Fenster auch dementsprechend klein. Jedenfalls rendert bei µHz Auflösung nix mehr:(


Lösungsvorschlag are welcome
 
Zuletzt bearbeitet:
Ah ok die zuletz gezeigte Skala rendert auch ich hatte mich nur verlesen aber 0,005Hz geht dann doch nicht. Da kommt beim Exponenten -Infinity raus.
0,005Hz gibt wirklich als FFT Spektrum.
RSDN20F1.jpg

Gibt es dafür auch 'ne Lösung oder sind die grenzen von Javascript erreicht.
 
Zurück
Oben