Datenvisualisierung/Funktionsplotter
Es wird ein Script vorgestellt, das mathematische Funktionen über Inputelemente einliest und grafisch darstellt. Für die grafische Darstellung wird das SVG-Element verwendet.
Es gibt auch eine Version des Funktionsplotters, die das Canvas-Element verwendet.
Das Script besteht aus dem Grafikobjekt grafik
, dem Plotobjekt plot
und dem Funktionsplotter.
Inhaltsverzeichnis
Das Grafikobjekt
Das Grafikobjekt ist die Schnittstelle zur SVG.
- SW.grafik(grafikelement)
- legt das SVG-Element an.
- grafikelement: ID des Elements oder Referenz auf das Element, in dem das SVG-Element angelegt wird.
SW.grafik definiert die Methoden:
- .setwidth(width)
- setzt die Linienstärke.
- width: Linienstärke in Pixeln.
- .line(xs,ys,xe,ye,color)
- zeichnet eine Linie von (xs,ys) nach (xe,ye) in Farbe color.
- xs,ys: Koordinaten des Startpunkts in Pixeln,
- xe,ye: Koordinaten des Endpunkts in Pixeln,
- color: Linienfarbe im css-Format.
- .polyline(points,color)
- zeichnet einen Linienzug.
- points: Array der Form [{x: xwert, y: ywert},{…},…] mit den Koordinaten der Stützpunkte in Pixeln.
- color: Linienfarbe im css-Format.
- .polyfill(points,color,a)
- zeichnet einen Linienzug. Die vom Linienzug umschlossene Fläche wird eingefärbt.
- points: Array der Form [{x: xwert, y: ywert},{…},…] mit den Koordinaten der Stützpunkte in Pixeln.
- color: Füllfarbe im css-Format.
- alpha: Transparenz, 0<=alpha<=1
- .text(x,y,size,color,text,align,direction)
- gibt Text aus.
- x,y: Koordinaten des Bezugspunkts in Pixeln,
- size: Texthöhe im css-Format
- color: Linienfarbe im css-Format.
- align: String aus zwei Buchstaben, gibt die Lage des Bezugspunkts relativ zum Text an. Der erste Buchstabe darf die Werte l, m, oder r annehmen für links, mitte oder rechts. Der zweite Buchstabe darf die Werte o, m oder u annehmen für oben, mitte oder unten.
- direction: gibt die Laufrichtung des Textes an, darf die Werte h und v für horizontal und vertikal annehmen.
- .del()
- löscht die Grafik.
"use strict";
var SW = window.SW || {};
// Das Grafikobjekt
SW.grafik = function(grafikelement) {
this.method = "svg";
// SVG in Größe des "grafikelement" anlegen
if(typeof grafikelement == "string") grafikelement = document.getElementById(grafikelement);
this.w = grafikelement.offsetWidth;
this.h = grafikelement.offsetHeight;
var linewidth = 1;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute("width","100%");
svg.setAttribute("height","100%");
svg.setAttribute("viewBox","0 0 "+this.w+" "+this.h);
svg.setAttribute("preserveAspectRatio","none");
grafikelement.appendChild(svg);
// Linienstärke setzen
this.setwidth = function(width) {
linewidth = width;
} // setwidth
// Linie von (xs,ys) nach (xe,ye) in Farbe color zeichnen
this.line = function(xs,ys,xe,ye,color) {
var linie = document.createElementNS('http://www.w3.org/2000/svg', 'line');
linie.setAttribute("x1",xs);
linie.setAttribute("y1",this.h-ys);
linie.setAttribute("x2",xe);
linie.setAttribute("y2",this.h-ye);
linie.setAttribute('stroke', color);
linie.setAttribute('stroke-width', linewidth);
linie.setAttribute("vector-effect","non-scaling-stroke");
svg.appendChild(linie);
} // line
// Polylinie mit den Werten in points in Farbe color zeichnen
this.polyline = function(points,color) {
var polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
polyline.setAttribute('stroke', color);
polyline.setAttribute('stroke-width', linewidth);
polyline.setAttribute('fill', "none");
polyline.setAttribute("vector-effect","non-scaling-stroke");
var pointstring = "";
for(var i=0;i<points.length;i++) pointstring += points[i].x+","+(this.h-points[i].y)+" ";
polyline.setAttribute('points', pointstring);
svg.appendChild(polyline);
} // polyline
// Polylinie mit den Werten in points zeichnen
// Die von der Polylinie umschlossene Fläche wird in Farbe color mit Alphawert alpha eingefärbt
this.polyfill = function(points,color,alpha) {
var polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
polygon.setAttribute('stroke', "none");
polygon.setAttribute('fill', color);
polygon.setAttribute('fill-opacity', alpha);
var pointstring = "";
for(var i=0;i<points.length;i++) pointstring += points[i].x+","+(this.h-points[i].y)+" ";
polygon.setAttribute('points', pointstring);
svg.appendChild(polygon);
} // polyfill
// Text an (x,y) ausgeben
// size: Schriftgröße
// text: Text
// align: Bezug für (x,y), zwei Buchstaben, z.B. lu für links unten, s. case
// diretion: Textrichtung: v für vertikal, sonst horizontal
this.text = function(x,y,size,color,text,align,direction) {
var stext = document.createElementNS('http://www.w3.org/2000/svg', 'text');
stext.style.fontSize = size;
stext.style.color = color;
stext.style.fill = color;
stext.textContent = text;
var align_h = "m";
var align_v = "m";
if(align && align.length) {
align_h = align.substr(0,1);
if(align.length>1) align_v = align.substr(1,1);
}
switch(align_h) {
case "l": stext.setAttribute("text-anchor","start"); break;
case "m": stext.setAttribute("text-anchor","middle"); break;
case "r": stext.setAttribute("text-anchor","end"); break;
default: stext.setAttribute("text-anchor","middle"); break;
}
switch(align_v) {
case "o": stext.setAttribute("dy","1.1em"); break;
case "m": stext.setAttribute("dy","0.3em"); break;
case "u": stext.setAttribute("dy","-0.1em"); break;
default: stext.setAttribute("dy","-0.3em"); break;
}
stext.setAttribute("x",x);
stext.setAttribute("y",this.h-y);
if(direction && direction=="v") stext.setAttribute("transform","rotate(270 "+x+" "+(this.h-y)+")");
svg.appendChild(stext);
// Werte für unscale
stext.setAttribute("class","noscale");
stext.xorg = x;
stext.yorg = this.h-y;
if(direction && direction=="v") stext.phiorg = 270;
else stext.phiorg = 0;
} // text
// Canvas löschen
this.del = function() {
grafikelement.innerHTML = "";
} // del
// Einige automatische Skalierungen rückgängig machen
var unscale = function() {
var etext = document.querySelectorAll(".noscale"),esvg,m;
for(var i=0;i<etext.length;i++) {
esvg = etext[i].ownerSVGElement;
m = esvg.getScreenCTM();
etext[i].setAttribute("transform","scale("+1/m.a+" "+1/m.d+")" + "rotate("+etext[i].phiorg+" "+etext[i].xorg*m.a+" "+etext[i].yorg*m.d+")");
etext[i].setAttribute("x",etext[i].xorg*m.a);
etext[i].setAttribute("y",etext[i].yorg*m.d);
}
}
window.addEventListener("resize",unscale);
} // grafik
SVG-Grafiken können mit dem SVG-Element mit skalieren. Dazu wurde dem SVG-Element eine viewbox gegeben und der Parameter .setAttribute("preserveAspectRatio","none")
gesetzt. Leider skalieren auch die Linienstärke und die Textgröße mit. Das Skalieren der Linienstärke wurde mit .setAttribute("vector-effect","non-scaling-stroke")
unterbunden. Um das Skalieren des Textes ebenfalls zu unterbinden, wird Javascript benötigt. Es wird ein Eventhandler für das resize
-Event notiert, in dem die neue Skalierung des SVG-Elements abgefragt und dann bei den Text-Elementen rückgängig gemacht wird.
Das folgende Beispiel zeigt die Anwendung des Grafikobjekts.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beispiel: Test Grafikobjekt auf SVG-Basis</title>
<style>
#plotarea { background-color:#ffffff; width:90%; height:80vh; border: 1px solid black }
</style>
<script src="grafik_svg.js"></script>
<script>
"use strict";
window.addEventListener("DOMContentLoaded",function() {
var grafik = new SW.grafik("plotarea");
grafik.line(20,20,grafik.w-20,40,"black");
var werte = [{x:20 ,y:25 },{x:15 ,y:grafik.h-10 },{x:grafik.w-10 ,y:grafik.h-50 },{x:grafik.w-30 ,y:100 },{x:grafik.w-100 ,y:50 }];
grafik.setwidth(3);
grafik.polyline(werte,"green");
werte = [{x:70 ,y:70 },{x:70 ,y:grafik.h-70 },{x:grafik.w-70 ,y:grafik.h-70 },{x:grafik.w-70 ,y:70 }];
grafik.polyfill(werte,"red",0.2);
grafik.text(70,70,"0.8em","blue","Text_ro","ro","h"); // Referenzpunkt rechts oben
grafik.text(70,70,"1em","blue","Text_lu","lu","h"); // Referenzpunkt links unten
grafik.text(grafik.w-70,grafik.h/2,"1.5em","blue","Text_mm","mm","v"); // Referenzpunkt mitte mitte
});
</script>
</head>
<body>
<h1>Beispiel: Test Grafikobjekt auf SVG-Basis</h1>
<figure id="plotarea"></figure>
</body>
</html>
Das Plotobjekt
Das Plotobjekt erstellt das Diagramm mit Achsen und Achsenbeschriftung.
- SW.plot(feld,xstr,ystr)
- legt den Bereich für das Diagramm an.
- Feld: ID des Elements oder Referenz auf das Element, in dem das Diagramm angelegt wird.
- xstr, ystr: Bezeichner der Objektelemente mit den x- und y-Werten im Datenarray. Defaultwerte sind x und y. Das Datenarray sieht dann so aus: [{x: xwert, y: ywert}{...},...]
SW.plot definiert die Methoden:
- .scale(daten)
- ermittelt zu den Werten im Array daten die kleinsten und größten Werte.
- daten: Array der Form [{xstr: xwert, ystr: ywert}{...},...]
- .clear()
- löscht das Diagramm
- .frame(x0,y0,xtext,ytext)
- legt das Achsenkreuz an.
- x0, y0: Koordinaten der linken unteren Ecke in Pixel.
- xtext, ytext: Beschriftung der Achsen.
- .plot(daten,color) Plottet die Daten.
- daten: Array der Form [{xstr: xwert, ystr: ywert}{...},...]
- color: Linienfarbe im css-Format.
Weitere Eigenschaften und deren Defaultwerte:
- .ticwidth
- Linienstärke der Gitterlinien (1)
- .linewidth
- Linienstärke der Plotlinien (1)
- .borderwidth
- Linienstärke des Rahmens um den Plot (2)
- .framecol
- Farbe des Rahmens ("black")
- .gridcol
- Farbe der Gitterlinien ("gray")
- .labelcol
- Farbe der Achsenbeschriftung ("black")
- .fillopac
- Deckkraft der Füllfarbe unter der Plotlinie (0.1)
"use strict";
var SW = window.SW || {};
// Math.log10 wird noch nicht von allen Browsern unterstützt
if(!Math.log10) Math.log10 = function(x) { return Math.log(x)/Math.LN10; };
// Das Plotobjekt
// feld ist das Objekt bzw. dessen Id, in dem das Diagramm erstellt werden soll
// xstr und ystr geben die Bezeichner der Objektelemente mit den x- und y-Werten im Datenarray an.
// Defaultwerte sind x und y. Das Datenarray sieht dan so aus: [{x:xwert,y:ywert}{...},...]
SW.plot = function(feld,xstr,ystr) {
// Defaultwerte
this.ticwidth = 1;
this.linewidth = 1;
this.borderwidth = 2;
this.framecol = "black";
this.gridcol = "gray";
this.labelcol = "black";
this.fillopac = 0.1;
// Plotbereich anlegen
if(typeof feld == "string") feld = document.getElementById(feld);
feld.innerHTML = "";
// Einige Variablen
var xobj = xstr?xstr:"x";
var yobj = ystr?ystr:"y";
var xmin=0,xmax=0,ymin=0,ymax=0;
var xfak=0,yfak=0;
var dx,dy,fx,fy;
var gr = null;
// Zu den Werten in daten xmin, xmax, ymin und ymax ermitteln
this.scale = function(daten) {
if(xmin==xmax) { // Startwerte beim ersten Datensatz
xmax = xmin = daten[0][xobj];
ymax = ymin = daten[0][yobj];
}
for(var i=1;i<daten.length;i++) {
var t = daten[i];
if(t[xobj]<xmin) xmin = t[xobj];
if(t[xobj]>xmax) xmax = t[xobj];
if(t[yobj]<ymin) ymin = t[yobj];
if(t[yobj]>ymax) ymax = t[yobj];
}
} // scale
// Plotbereich leeren
this.clear = function() {
feld.innerHTML = "";
xmax = xmin = ymax = ymin = xfak = yfak = 0;
} // clear
// Achsenkreuz, Tics und Beschriftung, linke untere Ecke bei (x0,y0)
// xtext und ytext sind die Beschriftungen der Achsen
this.frame = function(x0,y0,xtext,ytext) {
this.x0 = x0;
this.y0 = y0;
// Den Bereich für das Diagramm anlegen
feld.innerHTML = "";
gr = new SW.grafik(feld);
this.method = gr.method;
// Achsenbeschriftungen
if(xtext.length) gr.text((gr.w-x0)/2+x0,0,".9em",this.labelcol,xtext,"mu","h");
if(ytext.length) gr.text(10,(gr.h-y0)/2+y0,".9em",this.labelcol,ytext,"mm","v");
// xmin und xmax auf die nächst kleinere bzw. größere "glatte" Zahl runden und den
// Abstand der Tics auf glatte Zahlen (1 2 5 0) für x-Achse legen
if(xmax==xmin) { xmin -= 0.5; xmax += 0.5; }
dx = (xmax - xmin)/100;
xmin -= dx; xmax += dx;
dx = xmax - xmin;
fx = Math.pow(10,Math.floor(Math.log10(dx))-1); // Die Größenordnung ermitteln
xmin = Math.floor(xmin/fx)*fx;
xmax = Math.ceil(xmax/fx)*fx;
xfak = (gr.w-x0)/(xmax-xmin);
var tx = ticdist(100*dx/gr.w);
var mxmin = Math.ceil(xmin/tx)*tx;
// Tics und Zahlen an der x-Achse
gr.setwidth(this.ticwidth);
for(var x=mxmin;x<=xmax;x+=tx) {
var xx = (x-xmin)*xfak + x0;
gr.line(xx,y0,xx,gr.h,this.gridcol);
if(xtext.length && xx<(gr.w-5) && xx>5) gr.text(xx,y0-2,".8em",this.labelcol,myround(x,tx),"mo","h");
}
// ymin und ymax auf die nächst kleinere bzw. größere "glatte" Zahl runden und den
// Abstand der Tics auf glatte Zahlen (1 2 5 0) für x-Achse legen
if(ymax==ymin) { ymin -= 0.5; ymax += 0.5; }
dy = (ymax - ymin)/100;
ymin -= dy; ymax += dy;
dy = ymax - ymin;
fy = Math.pow(10,Math.floor(Math.log10(dy))-1); // Die Größenordnung ermitteln
ymin = Math.floor(ymin/fy)*fy;
ymax = Math.ceil(ymax/fy)*fy;
yfak = (gr.h-y0)/(ymax-ymin);
var ty = ticdist(gr.h<250 ? 50*dy/gr.h : 100*dy/gr.h);
var mymin = Math.ceil(ymin/ty)*ty;
// Tics und Zahlen an der y-Achse
for(var y=mymin;y<=ymax;y+=ty) {
var yy = (y-ymin)*yfak + y0;
gr.line(x0,yy,gr.w,yy,this.gridcol);
if(ytext.length && yy<(gr.h-5) && yy>5) gr.text(x0-2,yy,".8em",this.labelcol,myround(y,ty),"rm","h");
}
gr.setwidth(this.borderwidth);
gr.polyline([
{x:x0, y: y0},
{x:gr.w-this.borderwidth, y:y0},
{x:gr.w-this.borderwidth, y:gr.h-this.borderwidth},
{x:x0, y:gr.h-this.borderwidth},
{x:x0, y:y0}],
this.framecol);
} // frame
// Daten Plotten
// daten: Datenarray mit Objekten mit den x- und y-Werten
// color Diagrammfarbe
this.plot = function(daten,color) {
var arr=[];
for(var i=0,l=daten.length;i<l;i++)
arr.push({x:(daten[i][xobj]-xmin)*xfak+this.x0, y:(daten[i][yobj]-ymin)*yfak+this.y0});
if(this.fillopac>0) {
var fillline;
if(ymax*ymin<=0) fillline = -ymin*yfak+this.y0 ;
else if(ymin>0) fillline = 1+this.y0;
else fillline = gr.h-1;
arr.push({x:(daten[l-1][xobj]-xmin)*xfak+this.x0,y:fillline});
arr.push({x:(daten[0][xobj]-xmin)*xfak+this.x0,y:fillline});
arr.push({x:(daten[0][xobj]-xmin)*xfak+this.x0,y:(daten[0][yobj]-ymin)*yfak+this.y0});
gr.polyfill(arr,color,this.fillopac);
arr.length -= 3;
}
gr.setwidth(this.linewidth);
gr.polyline(arr,color);
} // plot
// Hilfsfunktionen zum Runden
var myround = function(z,d) {
var l10 = Math.floor(Math.log10(d));
var f = Math.pow(10,l10);
var zz = Math.round(z/f)*f;
var zzz = Number(zz.toPrecision(15)).toString(10);
return zzz;
}
// Hilfsfunktion zum berechnen des Abstands der Achsen-Tics, Abstände auf 1 2 5 0 gerundet
var ticdist = function(td) {
var td10 = Math.pow(10,Math.floor(Math.log10(td)));
td = Math.round(td/td10);
td = Number(String(td).replace(/3/,"2").replace(/[4567]/,"5").replace(/[89]/,"10"));
td *= td10;
return td;
} // ticdist
} // plot
Das folgende Beispiel zeigt die Anwendung des Plotobjekts:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beispiel: Test Plotobjekt auf SVG-Basis</title>
<style>
#plotarea { background-color:#ffffff; margin:0; height:calc(100vh - 7em); min-height:300px; }
</style>
<script src="grafik_svg.js"></script>
<script src="plot.js"></script>
<script>
"use strict";
window.addEventListener("DOMContentLoaded",function() {
var daten = [],
xmin = -Math.PI,
xmax = Math.PI,
npt = 1000;
var dx = ( xmax - xmin ) / npt;
for(var x=xmin;x<=xmax;x+=dx) daten.push( { x: x, y: Math.sin(x) } );
var plt = new SW.plot("plotarea") ;
plt.scale(daten);
plt.frame(50,35,"x","sin(x)");
plt.plot(daten,"red");
});
</script>
</head>
<body>
<h1>Beispiel: Test Plotobjekt auf SVG-Basis</h1>
<figure id="plotarea"></figure>
</body>
</html>
Der Funktionsplotter
Der Funktionsplotter befindet sich im Eventhandler für das Ereignis DOMContentLoaded
. Hier werden die Referenzen auf die HTML-Elemente ermittelt und die benötigten Eventhandler angelegt.
In der Funktion fkt_plotter
werden dann die Inputfelder mit den Funktionen und den Min- und Maxwerten für die X-Achse ausgelesen, die Funktionswerte berechnet und der Plot erstellt. Zusätzlich wird noch in einem versteckten Div-Element eine gekürzte Wertetabelle für Screenreader angelegt.
Das Plotterscript sieht so aus:
"use strict";
window.addEventListener("DOMContentLoaded",function() {
// Zahlen einlesen und bei Bedarf korrigieren
var get_num = function(e) {
var num = e.value;
if (isNaN(num)) { num = num.replace(/,/g,"."); }
if (isNaN(num) || num.length==0 ) { num = 0.0; e.value = num; }
return parseFloat(num);
}
// Der Funktionsplotter
var fkt_plotter = function() {
var funktionen = [];
// Funktionen lesen
for(var i=0;i<e_fkt.length;i++ ) funktionen[i] = e_fkt[i].value;
// xmin und xmax lesen, prüfen und bei Bedarf korrigieren
var xmin = get_num(e_xmin);
var xmax = get_num(e_xmax);
if (xmax==xmin) {
xmin -= 0.5; xmax += 0.5;
e_xmin.value = xmin;
e_xmax.value = xmax;
}
else if (xmax<xmin) {
var t = xmax;
xmax = xmin;
xmin = t;
e_xmin.value = xmin;
e_xmax.value = xmax;
}
var dx = (xmax - xmin)/npt;
// Werte für Diagramm berechnen ...
var daten = [];
for(var i=0;i<funktionen.length;i++) {
try {
if(funktionen[i].length && funktionen[i].search(/\S/)!=-1) {
var fun = new Function("x","with(Math){return("+funktionen[i]+")}");
var ar = [];
for(var x=xmin;x<=xmax;x+=dx) ar.push( { x: x, y: fun(x) } );
daten.push(ar);
}
}
catch(e) {
alert("Fehler in der Formel Nr "+(i+1)+":\n\n"+funktionen[i]+"\n\n"+e);
}
}
// ... und plotten
plt.clear();
plt.fillopac = .3;
for(var i=0;i<daten.length;i++) if(!isNaN(daten[i][0].y)) plt.scale(daten[i]);
plt.frame(50,35,"x","y");
for(var i=0;i<daten.length;i++) if(!isNaN(daten[i][0].y)) plt.plot(daten[i],cols[i]);
// ... und Ausgabe in versteckter Tabelle für Screenreader
var tabelle = "";
for(var j=0;j<daten.length;j++) {
tabelle += "<table>";
tabelle += "<caption>Wertetabelle für Funktion "+(j+1)+"</caption>";
tabelle += "<thead><tr><th colspan='2'>"+funktionen[j]+"</th></tr>";
tabelle += "<tr><th>x</th><th>y"+(j+1)+"</th></tr></thead>";
tabelle += "<tbody>";
for(var i=0;i<daten[j].length;i+=npt/20 ) tabelle += "<tr><td>"+daten[j][i].x.toFixed(3)+"</td><td>"+daten[j][i].y.toFixed(3)+"</td></tr>";
tabelle += "</tbody>"
tabelle += "</table>";
}
e_wertetabelle.innerHTML = tabelle;
} // fkt_plotter
var i,j,e_plotarea,e_wertetabelle,e_fkt=[],e_xmin,e_xmax,plt,e_jsfkt,e_vdeffkt;
var npt = 1000;
var current = 0;
var cols = ["#ff0000","#008000","#0000ff"];
var vdef_fkt = {
AM: "(1-0.3*sin(x/4))*sin(3*x)",
PM: "sin(3*x-2*sin(x/3))",
"sin(x)/x": "sin(x)/x",
sinh: "(exp(x)-exp(-x))/2",
cosh: "(exp(x)+exp(-x))/2",
tanh: "(exp(x)-exp(-x))/(exp(x)+exp(-x))",
Puls: "(function(){var y=0;for(var ii=10;ii<30;ii++) y+=sin(ii*x);return y})(x)"
};
var js_fkt = {
abs: "abs(x)",
acos: "acos(x)",
asin: "asin(x)",
atan: "atan(x)",
cos: "cos(x)",
exp: "exp(x)",
log: "log(x)",
pow: "pow(x,2)",
sin: "sin(x)",
sqrt: "sqrt(x)",
tan: "tan(x)",
};
// Referenzen
e_plotarea = document.getElementById("plotarea");
e_wertetabelle = document.getElementById("wertetabelle");
e_xmin = document.getElementById("idxmin");
e_xmax = document.getElementById("idxmax");
e_jsfkt = document.querySelectorAll("#jsfkt button");
e_vdeffkt = document.querySelectorAll("#vdeffkt button");
for(i=0;i<3;i++) {
e_fkt[i] = document.getElementById("fkt"+(i+1));
document.getElementById("f"+(i+1)).style.color = cols[i];
}
// Die Eventhandler
document.getElementById("plotbutton").addEventListener("click",fkt_plotter);
document.getElementById("fkt1").addEventListener("click",function(){ current = 0 });
document.getElementById("fkt2").addEventListener("click",function(){ current = 1 });
document.getElementById("fkt3").addEventListener("click",function(){ current = 2 });
for(i=0;i<e_vdeffkt.length;i++) e_vdeffkt[i].addEventListener("click",function() {
e_fkt[current].value = vdef_fkt[this.innerHTML] });
for(i=0;i<e_jsfkt.length;i++) e_jsfkt[i].addEventListener("click",function() {
e_fkt[current].value += "+"+ js_fkt[this.innerHTML] });
// Plottbereich anlegen und Startwerte plotten
plt = new SW.plot(e_plotarea);
fkt_plotter();
// SVG kann sich an Größenänderungen anpassen, bei Canvas muss der Plot neu erstellt werden
if(plt.method=="canvas")
window.addEventListener("resize",function() {
plt = new SW.plot(e_plotarea);
fkt_plotter();
});
});
Das folgende Beispiel zeigt den Funktionsplotter.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Plottet Funktionen">
<title>Beispiel: Funktionsplot auf SVG-Basis</title>
<style>
#plotarea { background-color:#ffffff; margin:0; height:calc(100vh - 19em); min-height:300px; }
#plotter { margin-bottom: 1em; border: none }
#plotter div { display:inline-block; vertical-align:top }
#plotter div:nth-child(1) label { display:block; }
#plotter div:nth-child(2) button { display:block; margin: 1em 0 0 5em;}
#idxmin, #idxmax { text-align:right; width:10em; }
#fkt1, #fkt2, #fkt3 { width:30em; }
</style>
<script src="grafik_svg.js"></script>
<script src="plot.js"></script>
<script src="fkt_plotter.js"></script>
</head>
<body>
<h1>Beispiel: Funktionsplot auf SVG-Basis</h1>
<p>Stellt mathematische Funktionen grafisch dar.</p>
<figure id="plotarea"></figure>
<div hidden id="wertetabelle" aria-live="polite"></div>
<fieldset id="plotter">
<div aria-live="polite">
<label id="f1">f<sub>1</sub>(x) = <input type="text" id="fkt1" value="sin(x)/x"></label>
<label id="f2">f<sub>2</sub>(x) = <input type="text" id="fkt2" value="sin(x)"></label>
<label id="f3">f<sub>3</sub>(x) = <input type="text" id="fkt3" value="cos(x)"></label>
</div>
<div>
<label>xmin = <input lang="en" type="number" step="any" id="idxmin" value="-20"></label>
<label>xmax = <input lang="en" type="number" step="any" id="idxmax" value="20"></label>
<button id="plotbutton">Plotten</button>
</div>
</fieldset>
<p id="vdeffkt">Vordefinierte Funktionen:
<button>AM</button>,
<button>PM</button>,
<button>sin(x)/x</button>,
<button>sinh</button>,
<button>cosh</button>,
<button>tanh</button> und
<button>Puls</button>.
</p>
<p id="jsfkt">Javascript unterstützt folgende Funktionen:
<button>abs</button>,
<button>acos</button>,
<button>asin</button>,
<button>atan</button>,
<button>cos</button>,
<button>exp</button>,
<button>log</button>,
<button>pow</button>,
<button>sin</button>,
<button>sqrt</button> und
<button>tan</button>.
Bitte den Definitionsbereich der Funktionen beachten.</p>
</body>
</html>