I Want 2 Study
Chemistry

Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, tooltip: {is Html: true}, // This MUST be set to true for your chart to show. line Width: 3, colors: ['black'], // Ensure responsiveness width: '100%', height: '100%' // Let container control height }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); if (!chart_div) return; // Exit if chart div not found var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists // Clear previous chart drawings to prevent memory leaks on resize google.visualization.events.add Listener(chart, 'ready', function() { var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var svg = chart_div.query Selector('svg'); // Get the SVG element if (svg) { // Check if SVG exists var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); svg.insert Before(defs, svg.first Child); } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); $(svg).find("[clip-path]").parent().find("rect").first().attr("fill", "url(#fx)").attr("fill-opacity", "1"); change Chart Color($("#indtype").val()); } }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return 7.0; } else if (burette Vol < get Float("bvol") ) { return p HSA( ( init Mol - burette Vol * get Float("bconc") * get Float("btype") ) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( (burette Vol*get Float("bconc")*get Float("btype")-init Mol) ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; tooltip Charts HTML = {}; generate Graph For Current Burette Volume(); } function generate Graph For Current Burette Volume() { var tot Acid Mol = get Float("aconc") * get Float("avol") * get Float("atype") / 1000; var acid Mol = tot Acid Mol - burette Vol * get Float("bconc") * get Float("btype") / 1000; var salt Mol = burette Vol * get Float("bconc") * get Float("btype") / 1000; if (salt Mol > tot Acid Mol) salt Mol = tot Acid Mol; var data = new google.visualization.Data Table(); data.add Column('string', 'Species Type'); data.add Column('number', 'Mols'); data.add Rows([ ["strong acid", acid Mol > 0 ? acid Mol : 0], ["salt", salt Mol], ["xs strong base", acid Mol < 0 ? -acid Mol : 0] ]); var hidden Div = document.get Element By Id('hidden_div'); if (!hidden Div) return; // Exit if hidden div not found var tooltip Chart = new google.visualization.Column Chart(hidden Div); var cur Burette Vol = burette Vol.to Fixed(2); // As the following function is a callback, it means that by the time it is called burette Vol may have changed. So we fixed it in a variable now google.visualization.events.add Listener(tooltip Chart, 'ready', function() { // Get the PNG of the chart and set it as the src of an img tag, to be displayed as HTML tooltip Charts HTML[cur Burette Vol] = '<img src="' + tooltip Chart.get Image URI() + '">';; }); var tooltip Options = { title: 'Amount of each species present', v Axis: { title: 'Amount / mol', title Text Style: {color: 'black', bold: 1, italic: 0, font Size: 10, font Name: 'Lucida Sans Unicode' }, view Window: { min: 0, max: get Float("aconc") * get Float("avol") * get Float("atype") / 1000 }, }, legend: {position: 'none'}, axes: { y: { 0: {label: "Amount / mol"} } } }; tooltip Chart.draw(data, tooltip Options); } function titrate Step() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); generate Graph For Current Burette Volume( ); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); // Scroll to bottom of table var table Div = $("#titable").parent(); if (table Div.length) { table Div.scroll Top(table Div[0].scroll Height); } } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("atype") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { resu <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <link rel="stylesheet" href="cs/bootstrap.min.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSA(get Float("aconc") * get Float("atype")); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HSA( (init Mol - burette Vol * get Float("bconc")) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HBB( ( burette Vol * get Float("bconc") - init Mol ), (init Mol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("aconc") * get Float("atype") ) / ( get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==false && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base <span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="container mt-4" sty <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); // Tooltip generation logic removed for brevity as it's not used in this chart type directly for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { set Float( "p X", data.get Value(selected Item.row, 0) ); set Float( "p Y", data.get Value(selected Item.row, 1) ); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ){ return 7.0; } else if (burette Vol < get Float("avol") ) { return p HSB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ) / (tot Vol) ); } else if (burette Vol > get Float("avol") ) { return p HSA(( ( burette Vol * get Float("aconc") * get Float("atype") ) - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { set Float("avol", get Float("bvol") * get Float("btype") * get Float("bconc") / (get Float("atype") * get Float("aconc")) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: What is the nature of the salt formed?'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <div class="container mt-4" style="max-width: 95%;"> <!-- Added max-width style --> <div class="hover_img mb-3 text-center"> <p style="font-size:20px"><b>Titration Curve of Strong Base against Strong Acid</b> <a href="#">(image)<span><img src="SBSA.png" height=500 border=2 alt="Example titration curve for Strong Base vs Strong Acid"></span></a></p> </div> <div class="row"> <div class="col-lg-2 mb-3"> <!-- Column for Image --> <img src="SBSA.png" class="img-fluid mb-3" alt="Titration curve for Strong Base vs Strong Acid"> </div> <div class="col-lg-4 mb-3"> <!-- Column for Inputs - Wider --> <table class="table table-bordered table-sm"> <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + (Math.log10(conc S/conc A)); } //not tested function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSB(get Float("bconc") * get Float("btype")); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HSB( (init Mol - burette Vol * get Float("aconc") ) / tot Vol ); } else if (burette Vol > get Float("avol") ) { return p HAB( ( burette Vol * get Float("aconc") - init Mol ) , init Mol ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( get Float("bvol") * get Float("bconc") * get Float("btype") / get Float("aconc") ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==false && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Wea <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + Math.log10(conc S/conc A); } function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWA(); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HAB( parse Float( init Mol - burette Vol * get Float("bconc") * get Float("btype") ), parse Float(burette Vol * get Float("bconc") * get Float("btype")) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( burette Vol * get Float("bconc") * get Float("btype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); } function update Neutralisation() { set Float("bvol", (( get Float("avol") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc")))); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <link rel="stylesheet" href="cs/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWB(); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HBB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ), (burette Vol * get Float("aconc") * get Float("atype")) ); } else if (burette Vol > get Float("avol") ) { return p HSA( ( burette Vol * get Float("aconc") * get Float("atype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( ( get Float("bvol") * get Float("bconc") ) / ( get Float("atype") * get Float("aconc") ) ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <d

Open Index, an interactive HTML5 learning activity for chemistry.

Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, tooltip: {is Html: true}, // This MUST be set to true for your chart to show. line Width: 3, colors: ['black'], // Ensure responsiveness width: '100%', height: '100%' // Let container control height }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); if (!chart_div) return; // Exit if chart div not found var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists // Clear previous chart drawings to prevent memory leaks on resize google.visualization.events.add Listener(chart, 'ready', function() { var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var svg = chart_div.query Selector('svg'); // Get the SVG element if (svg) { // Check if SVG exists var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); svg.insert Before(defs, svg.first Child); } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); $(svg).find("[clip-path]").parent().find("rect").first().attr("fill", "url(#fx)").attr("fill-opacity", "1"); change Chart Color($("#indtype").val()); } }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return 7.0; } else if (burette Vol < get Float("bvol") ) { return p HSA( ( init Mol - burette Vol * get Float("bconc") * get Float("btype") ) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( (burette Vol*get Float("bconc")*get Float("btype")-init Mol) ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; tooltip Charts HTML = {}; generate Graph For Current Burette Volume(); } function generate Graph For Current Burette Volume() { var tot Acid Mol = get Float("aconc") * get Float("avol") * get Float("atype") / 1000; var acid Mol = tot Acid Mol - burette Vol * get Float("bconc") * get Float("btype") / 1000; var salt Mol = burette Vol * get Float("bconc") * get Float("btype") / 1000; if (salt Mol > tot Acid Mol) salt Mol = tot Acid Mol; var data = new google.visualization.Data Table(); data.add Column('string', 'Species Type'); data.add Column('number', 'Mols'); data.add Rows([ ["strong acid", acid Mol > 0 ? acid Mol : 0], ["salt", salt Mol], ["xs strong base", acid Mol < 0 ? -acid Mol : 0] ]); var hidden Div = document.get Element By Id('hidden_div'); if (!hidden Div) return; // Exit if hidden div not found var tooltip Chart = new google.visualization.Column Chart(hidden Div); var cur Burette Vol = burette Vol.to Fixed(2); // As the following function is a callback, it means that by the time it is called burette Vol may have changed. So we fixed it in a variable now google.visualization.events.add Listener(tooltip Chart, 'ready', function() { // Get the PNG of the chart and set it as the src of an img tag, to be displayed as HTML tooltip Charts HTML[cur Burette Vol] = '<img src="' + tooltip Chart.get Image URI() + '">';; }); var tooltip Options = { title: 'Amount of each species present', v Axis: { title: 'Amount / mol', title Text Style: {color: 'black', bold: 1, italic: 0, font Size: 10, font Name: 'Lucida Sans Unicode' }, view Window: { min: 0, max: get Float("aconc") * get Float("avol") * get Float("atype") / 1000 }, }, legend: {position: 'none'}, axes: { y: { 0: {label: "Amount / mol"} } } }; tooltip Chart.draw(data, tooltip Options); } function titrate Step() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); generate Graph For Current Burette Volume( ); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); // Scroll to bottom of table var table Div = $("#titable").parent(); if (table Div.length) { table Div.scroll Top(table Div[0].scroll Height); } } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("atype") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { resu <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <link rel="stylesheet" href="cs/bootstrap.min.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSA(get Float("aconc") * get Float("atype")); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HSA( (init Mol - burette Vol * get Float("bconc")) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HBB( ( burette Vol * get Float("bconc") - init Mol ), (init Mol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("aconc") * get Float("atype") ) / ( get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==false && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base <span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="container mt-4" sty <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); // Tooltip generation logic removed for brevity as it's not used in this chart type directly for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { set Float( "p X", data.get Value(selected Item.row, 0) ); set Float( "p Y", data.get Value(selected Item.row, 1) ); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ){ return 7.0; } else if (burette Vol < get Float("avol") ) { return p HSB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ) / (tot Vol) ); } else if (burette Vol > get Float("avol") ) { return p HSA(( ( burette Vol * get Float("aconc") * get Float("atype") ) - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { set Float("avol", get Float("bvol") * get Float("btype") * get Float("bconc") / (get Float("atype") * get Float("aconc")) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: What is the nature of the salt formed?'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <div class="container mt-4" style="max-width: 95%;"> <!-- Added max-width style --> <div class="hover_img mb-3 text-center"> <p style="font-size:20px"><b>Titration Curve of Strong Base against Strong Acid</b> <a href="#">(image)<span><img src="SBSA.png" height=500 border=2 alt="Example titration curve for Strong Base vs Strong Acid"></span></a></p> </div> <div class="row"> <div class="col-lg-2 mb-3"> <!-- Column for Image --> <img src="SBSA.png" class="img-fluid mb-3" alt="Titration curve for Strong Base vs Strong Acid"> </div> <div class="col-lg-4 mb-3"> <!-- Column for Inputs - Wider --> <table class="table table-bordered table-sm"> <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + (Math.log10(conc S/conc A)); } //not tested function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSB(get Float("bconc") * get Float("btype")); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HSB( (init Mol - burette Vol * get Float("aconc") ) / tot Vol ); } else if (burette Vol > get Float("avol") ) { return p HAB( ( burette Vol * get Float("aconc") - init Mol ) , init Mol ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( get Float("bvol") * get Float("bconc") * get Float("btype") / get Float("aconc") ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==false && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Wea <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + Math.log10(conc S/conc A); } function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWA(); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HAB( parse Float( init Mol - burette Vol * get Float("bconc") * get Float("btype") ), parse Float(burette Vol * get Float("bconc") * get Float("btype")) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( burette Vol * get Float("bconc") * get Float("btype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); } function update Neutralisation() { set Float("bvol", (( get Float("avol") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc")))); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <link rel="stylesheet" href="cs/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWB(); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HBB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ), (burette Vol * get Float("aconc") * get Float("atype")) ); } else if (burette Vol > get Float("avol") ) { return p HSA( ( burette Vol * get Float("aconc") * get Float("atype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( ( get Float("bvol") * get Float("bconc") ) / ( get Float("atype") * get Float("aconc") ) ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <d preview image

1. Watch or Launch

Teacher Demonstration

Use the live model as a shared screen demonstration before students try their own predictions and observations.

Launch the Interactive

Open the simulation, adjust the controls, and compare what changes on screen before answering the concept-check questions.

Launch Interactive

Advertisement

2. Big Ideas

Key idea This interactive model helps learners test a prediction, observe the result, and explain the relationship shown in Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, tooltip: {is Html: true}, // This MUST be set to true for your chart to show. line Width: 3, colors: ['black'], // Ensure responsiveness width: '100%', height: '100%' // Let container control height }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); if (!chart_div) return; // Exit if chart div not found var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists // Clear previous chart drawings to prevent memory leaks on resize google.visualization.events.add Listener(chart, 'ready', function() { var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var svg = chart_div.query Selector('svg'); // Get the SVG element if (svg) { // Check if SVG exists var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); svg.insert Before(defs, svg.first Child); } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); $(svg).find("[clip-path]").parent().find("rect").first().attr("fill", "url(#fx)").attr("fill-opacity", "1"); change Chart Color($("#indtype").val()); } }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return 7.0; } else if (burette Vol < get Float("bvol") ) { return p HSA( ( init Mol - burette Vol * get Float("bconc") * get Float("btype") ) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( (burette Vol*get Float("bconc")*get Float("btype")-init Mol) ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; tooltip Charts HTML = {}; generate Graph For Current Burette Volume(); } function generate Graph For Current Burette Volume() { var tot Acid Mol = get Float("aconc") * get Float("avol") * get Float("atype") / 1000; var acid Mol = tot Acid Mol - burette Vol * get Float("bconc") * get Float("btype") / 1000; var salt Mol = burette Vol * get Float("bconc") * get Float("btype") / 1000; if (salt Mol > tot Acid Mol) salt Mol = tot Acid Mol; var data = new google.visualization.Data Table(); data.add Column('string', 'Species Type'); data.add Column('number', 'Mols'); data.add Rows([ ["strong acid", acid Mol > 0 ? acid Mol : 0], ["salt", salt Mol], ["xs strong base", acid Mol < 0 ? -acid Mol : 0] ]); var hidden Div = document.get Element By Id('hidden_div'); if (!hidden Div) return; // Exit if hidden div not found var tooltip Chart = new google.visualization.Column Chart(hidden Div); var cur Burette Vol = burette Vol.to Fixed(2); // As the following function is a callback, it means that by the time it is called burette Vol may have changed. So we fixed it in a variable now google.visualization.events.add Listener(tooltip Chart, 'ready', function() { // Get the PNG of the chart and set it as the src of an img tag, to be displayed as HTML tooltip Charts HTML[cur Burette Vol] = '<img src="' + tooltip Chart.get Image URI() + '">';; }); var tooltip Options = { title: 'Amount of each species present', v Axis: { title: 'Amount / mol', title Text Style: {color: 'black', bold: 1, italic: 0, font Size: 10, font Name: 'Lucida Sans Unicode' }, view Window: { min: 0, max: get Float("aconc") * get Float("avol") * get Float("atype") / 1000 }, }, legend: {position: 'none'}, axes: { y: { 0: {label: "Amount / mol"} } } }; tooltip Chart.draw(data, tooltip Options); } function titrate Step() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); generate Graph For Current Burette Volume( ); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); // Scroll to bottom of table var table Div = $("#titable").parent(); if (table Div.length) { table Div.scroll Top(table Div[0].scroll Height); } } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("atype") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { resu <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <link rel="stylesheet" href="cs/bootstrap.min.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSA(get Float("aconc") * get Float("atype")); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HSA( (init Mol - burette Vol * get Float("bconc")) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HBB( ( burette Vol * get Float("bconc") - init Mol ), (init Mol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("aconc") * get Float("atype") ) / ( get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==false && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base <span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="container mt-4" sty <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); // Tooltip generation logic removed for brevity as it's not used in this chart type directly for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { set Float( "p X", data.get Value(selected Item.row, 0) ); set Float( "p Y", data.get Value(selected Item.row, 1) ); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ){ return 7.0; } else if (burette Vol < get Float("avol") ) { return p HSB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ) / (tot Vol) ); } else if (burette Vol > get Float("avol") ) { return p HSA(( ( burette Vol * get Float("aconc") * get Float("atype") ) - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { set Float("avol", get Float("bvol") * get Float("btype") * get Float("bconc") / (get Float("atype") * get Float("aconc")) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: What is the nature of the salt formed?'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <div class="container mt-4" style="max-width: 95%;"> <!-- Added max-width style --> <div class="hover_img mb-3 text-center"> <p style="font-size:20px"><b>Titration Curve of Strong Base against Strong Acid</b> <a href="#">(image)<span><img src="SBSA.png" height=500 border=2 alt="Example titration curve for Strong Base vs Strong Acid"></span></a></p> </div> <div class="row"> <div class="col-lg-2 mb-3"> <!-- Column for Image --> <img src="SBSA.png" class="img-fluid mb-3" alt="Titration curve for Strong Base vs Strong Acid"> </div> <div class="col-lg-4 mb-3"> <!-- Column for Inputs - Wider --> <table class="table table-bordered table-sm"> <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + (Math.log10(conc S/conc A)); } //not tested function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSB(get Float("bconc") * get Float("btype")); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HSB( (init Mol - burette Vol * get Float("aconc") ) / tot Vol ); } else if (burette Vol > get Float("avol") ) { return p HAB( ( burette Vol * get Float("aconc") - init Mol ) , init Mol ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( get Float("bvol") * get Float("bconc") * get Float("btype") / get Float("aconc") ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==false && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Wea <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + Math.log10(conc S/conc A); } function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWA(); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HAB( parse Float( init Mol - burette Vol * get Float("bconc") * get Float("btype") ), parse Float(burette Vol * get Float("bconc") * get Float("btype")) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( burette Vol * get Float("bconc") * get Float("btype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); } function update Neutralisation() { set Float("bvol", (( get Float("avol") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc")))); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <link rel="stylesheet" href="cs/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWB(); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HBB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ), (burette Vol * get Float("aconc") * get Float("atype")) ); } else if (burette Vol > get Float("avol") ) { return p HSA( ( burette Vol * get Float("aconc") * get Float("atype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( ( get Float("bvol") * get Float("bconc") ) / ( get Float("atype") * get Float("aconc") ) ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <d.

What Students Can Learn

  • Identify the main controls and the visible output.
  • Change one setting at a time.
  • Compare two cases using evidence from the screen.
  • State the concept or rule shown by the model.

Guiding Question

What relationship does the model help you see more clearly?

3. Try the Investigation

Predict

Choose one control and predict what will happen before changing it.

Observe

Change one setting and describe exactly what changes on screen.

Compare

Test a second setting and compare the two outcomes.

Explain

Use the evidence from the model to explain the concept or rule being illustrated.

4. Teacher Notes

Lesson Use

Use the simulation as a short inquiry activity: predict first, change one control, observe the result, then explain the relationship shown by the model.

Discussion Prompts

Ask learners what changed, what stayed constant, what evidence they used, and how the model helps them explain the concept more clearly.

5. Concept Check

These questions are generated from the topic and the concept illustrated by the simulation. Use them after students have explored the model.

Concept Score

Correct first attempts build a streak and unlock higher point multipliers on this device.

0page points
0current streak
x1multiplier
0best streak
Answer each question once to build your streak.

1. What should learners do first when using Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, tooltip: {is Html: true}, // This MUST be set to true for your chart to show. line Width: 3, colors: ['black'], // Ensure responsiveness width: '100%', height: '100%' // Let container control height }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); if (!chart_div) return; // Exit if chart div not found var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists // Clear previous chart drawings to prevent memory leaks on resize google.visualization.events.add Listener(chart, 'ready', function() { var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var svg = chart_div.query Selector('svg'); // Get the SVG element if (svg) { // Check if SVG exists var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); svg.insert Before(defs, svg.first Child); } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); $(svg).find("[clip-path]").parent().find("rect").first().attr("fill", "url(#fx)").attr("fill-opacity", "1"); change Chart Color($("#indtype").val()); } }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return 7.0; } else if (burette Vol < get Float("bvol") ) { return p HSA( ( init Mol - burette Vol * get Float("bconc") * get Float("btype") ) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( (burette Vol*get Float("bconc")*get Float("btype")-init Mol) ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; tooltip Charts HTML = {}; generate Graph For Current Burette Volume(); } function generate Graph For Current Burette Volume() { var tot Acid Mol = get Float("aconc") * get Float("avol") * get Float("atype") / 1000; var acid Mol = tot Acid Mol - burette Vol * get Float("bconc") * get Float("btype") / 1000; var salt Mol = burette Vol * get Float("bconc") * get Float("btype") / 1000; if (salt Mol > tot Acid Mol) salt Mol = tot Acid Mol; var data = new google.visualization.Data Table(); data.add Column('string', 'Species Type'); data.add Column('number', 'Mols'); data.add Rows([ ["strong acid", acid Mol > 0 ? acid Mol : 0], ["salt", salt Mol], ["xs strong base", acid Mol < 0 ? -acid Mol : 0] ]); var hidden Div = document.get Element By Id('hidden_div'); if (!hidden Div) return; // Exit if hidden div not found var tooltip Chart = new google.visualization.Column Chart(hidden Div); var cur Burette Vol = burette Vol.to Fixed(2); // As the following function is a callback, it means that by the time it is called burette Vol may have changed. So we fixed it in a variable now google.visualization.events.add Listener(tooltip Chart, 'ready', function() { // Get the PNG of the chart and set it as the src of an img tag, to be displayed as HTML tooltip Charts HTML[cur Burette Vol] = '<img src="' + tooltip Chart.get Image URI() + '">';; }); var tooltip Options = { title: 'Amount of each species present', v Axis: { title: 'Amount / mol', title Text Style: {color: 'black', bold: 1, italic: 0, font Size: 10, font Name: 'Lucida Sans Unicode' }, view Window: { min: 0, max: get Float("aconc") * get Float("avol") * get Float("atype") / 1000 }, }, legend: {position: 'none'}, axes: { y: { 0: {label: "Amount / mol"} } } }; tooltip Chart.draw(data, tooltip Options); } function titrate Step() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); generate Graph For Current Burette Volume( ); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); // Scroll to bottom of table var table Div = $("#titable").parent(); if (table Div.length) { table Div.scroll Top(table Div[0].scroll Height); } } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("atype") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#SA").prop('checked')==false && $("#NS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SA").prop('checked')==true && $("#NS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { resu <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <link rel="stylesheet" href="cs/bootstrap.min.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSA(get Float("aconc") * get Float("atype")); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HSA( (init Mol - burette Vol * get Float("bconc")) / (tot Vol) ); } else if (burette Vol > get Float("bvol") ) { return p HBB( ( burette Vol * get Float("bconc") - init Mol ), (init Mol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol") * get Float("atype"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#bvol").val( ( ( get Float("avol") * get Float("aconc") * get Float("atype") ) / ( get Float("bconc") ) ).to Fixed(2) ); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==false && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base <span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="container mt-4" sty <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); // Tooltip generation logic removed for brevity as it's not used in this chart type directly for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { set Float( "p X", data.get Value(selected Item.row, 0) ); set Float( "p Y", data.get Value(selected Item.row, 1) ); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function p HSA(conc) { return -Math.log10(conc); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ){ return 7.0; } else if (burette Vol < get Float("avol") ) { return p HSB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ) / (tot Vol) ); } else if (burette Vol > get Float("avol") ) { return p HSA(( ( burette Vol * get Float("aconc") * get Float("atype") ) - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { set Float("avol", get Float("bvol") * get Float("btype") * get Float("bconc") / (get Float("atype") * get Float("aconc")) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#SB").prop('checked')==false && $("#NS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == 0 && $("#SB").prop('checked')==true && $("#NS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); // Use a small tolerance for floating point comparison if (Math.abs(parse Float(answer) - 7.0) < 0.01) { result Element.text Content = 'Correct! The p H at the equivalence point is 7.0.'; result Element.class Name = 'mt-2 text-success'; } else if (answer.trim() === '') { result Element.text Content = 'Please enter an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: What is the nature of the salt formed?'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <div class="container mt-4" style="max-width: 95%;"> <!-- Added max-width style --> <div class="hover_img mb-3 text-center"> <p style="font-size:20px"><b>Titration Curve of Strong Base against Strong Acid</b> <a href="#">(image)<span><img src="SBSA.png" height=500 border=2 alt="Example titration curve for Strong Base vs Strong Acid"></span></a></p> </div> <div class="row"> <div class="col-lg-2 mb-3"> <!-- Column for Image --> <img src="SBSA.png" class="img-fluid mb-3" alt="Titration curve for Strong Base vs Strong Acid"> </div> <div class="col-lg-4 mb-3"> <!-- Column for Inputs - Wider --> <table class="table table-bordered table-sm"> <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of weak acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + (Math.log10(conc S/conc A)); } //not tested function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HSB(get Float("bconc") * get Float("btype")); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HSB( (init Mol - burette Vol * get Float("aconc") ) / tot Vol ); } else if (burette Vol > get Float("avol") ) { return p HAB( ( burette Vol * get Float("aconc") - init Mol ) , init Mol ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol") * get Float("btype"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( get Float("bvol") * get Float("bconc") * get Float("btype") / get Float("aconc") ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==false && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA.html">Wea <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="https://rawgit.com/jmosbech/Sticky Table Headers/master/js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong base added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Ka() { var x = (- Math.log10(get Float("Ka"))).to Fixed(2); $("#p Ka").val(x); if(get Float("p Ka")<2 || get Float("p Ka")>10) {alert("check Ka value, use scientific notation");} } function p HWA() { return -Math.log10(Math.sqrt( get Float("Ka") * get Float("aconc") )); } function p HAB(conc A, conc S) { return -Math.log10(get Float("Ka")) + Math.log10(conc S/conc A); } function p HWB(conc) { return 14+Math.log10(Math.sqrt(1e-14/get Float("Ka")*conc)); } function p HSB(conc) { return 14 + Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWA(); } else if (burette Vol.to Fixed(2) == get Float("bvol").to Fixed(2) ) { return p HWB(init Mol/tot Vol); } else if (burette Vol < get Float("bvol") ) { return p HAB( parse Float( init Mol - burette Vol * get Float("bconc") * get Float("btype") ), parse Float(burette Vol * get Float("bconc") * get Float("btype")) ); } else if (burette Vol > get Float("bvol") ) { return p HSB( ( burette Vol * get Float("bconc") * get Float("btype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("aconc") * get Float("avol"); tot Vol = get Float("avol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); } function update Neutralisation() { set Float("bvol", (( get Float("avol") * get Float("aconc") ) / ( get Float("btype") * get Float("bconc")))); if (get Float("bvol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("bvol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==false && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("bvol") && get Float("p X") > 0 && $("#WA").prop('checked')==true && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("bvol") && $("#WA").prop('checked')==false && $("#BS").prop('checked')==true && $("#SB").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( get Float("p Y") > (get Float("p Ka")-1) && get Float("p Y") < (get Float("p Ka")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } if (get Float("p Y") < (get Float("p Ka")-1) || get Float("p Y") > (get Float("p Ka")+1)) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'basic') { result Element.text Content = 'Correct! The salt formed (conjugate base of the weak acid) hydrolyzes water to produce OH-, making the solution basic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item active"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="WBSA <html> <style type='text/css'> p {font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; margin-top: 20px; margin-left:20px;} /* #main Table { width: 100%; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif} */ /* #main Table td { vertical-align:top; font-size: 10pt; } */ .button { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 120%; padding: 10px; width: 100% } .box { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size: 100%; padding: 2px; } #titable th { padding: 5px; margin: 5px;} #titable td { text-align : center } .greenbg { background-color: #66FF66 !important; } .redbg { background-color: pink !important; } .inputbg { background-color: #FFFF00 !important; } .titlebg { background-color: #ccddff !important; font-weight: bold; line-height: 200%; text-align : center; padding: 5px; margin: 5px; width: 100%; text-transform: uppercase;} #fx stop:nth-child(1){ stop-color: white; } #fx stop:nth-child(2){ stop-color: white; } #fx stop:nth-child(3){ stop-color: white; } /* Removed old ul/li styles */ .hover_img a { position:relative;} .hover_img a span { position:absolute; display:none; z-index:99; background-color: #ffffff; width: 300px; padding: 10px; left:50%; -webkit-transform: translate X(-50%); -ms-transform: translate X(-50%); transform: translate X(-50%);} .hover_img a:hover span { display:block; } </style> <link rel="stylesheet" href="cs/jquery-ui.css"> <script src="js/jquery-3.6.0.min.js"></script> <!-- Use full j Query --> <script src="js/jquery-ui.js"></script> <!-- Load j Query UI after j Query --> <script src="js/jquery.ui.touch-punch.min.js"></script> <!-- Add Touch Punch --> <script src="js/jquery.stickytableheaders.min.js"></script> <script type="text/javascript" src="js/loader.js"></script> <link rel="stylesheet" href="cs/bootstrap.min.css"> <!-- Popper.js and Bootstrap JS remain --> <script src="js/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> <!-- Google Analytics --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.data Layer = window.data Layer || []; function gtag(){data Layer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <!-- Google Ad Sense --> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); // Load the Visualization API and the corechart package. google.charts.set On Load Callback(first Load); // Set a callback to run when the Google Visualization API is loaded. var burette Vol = 0; var init Mol = -1; var tot Vol = 0; var page Loaded = false; // Added page Loaded flag function create SVG(n,a,b){ var xmlns = "http://www.w3.org/2000/svg"; var e = document.create Element NS (xmlns, n); for(var k in a){ e.set Attribute NS (null, k,a[k]); } for(var k in b){ e.set Attribute (k,b[k]); } return e; }; function first Load() { $(document).ready( function() { $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); update Neutralisation(); // $('#titable').sticky Table Headers({ scrollable Area: $('#titable').parent() , fixed Offset:-30 }); // Consider re-enabling if needed $( "#acid Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("aconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#base Slider" ).slider({ value:100, min: 5, max: 200, step: 5, slide: function( event, ui ) { set Float("bconc", ui.value / 100); }, stop: function( event, ui ) { update Neutralisation(); } }); $( "#stop TSlider" ).slider({ value:500, min: 10, max: 500, step: 10, slide: function( event, ui ) { set Float("stopt", ui.value / 10); } }); page Loaded = true; // Set flag when page is ready // Initialize Bootstrap tooltips $(function () { $('[data-toggle="tooltip"]').tooltip() }); // Redraw chart on window resize for responsiveness $(window).resize(function(){ draw Chart(); }); // Initial chart draw draw Chart(); }); } function draw Chart() { // Create the data table. var data = new google.visualization.Data Table(); data.add Column('number', 'Volume'); data.add Column('number', 'p H'); var rows = $("#titable tbody tr"); for (i = 0; i < rows.length; i++) data.add Row([ parse Float($( rows[i] ).children()[0].inner HTML), parse Float( $( rows[i] ).children()[1].inner HTML ) ]); // Set chart options - Removed fixed width/height var options = { h Axis: { title: 'Volume of strong acid added / cm3', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 50 }, ticks: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]}, v Axis: { title: 'p H', title Text Style: {color: '#FF0000', bold: 1, italic: 0, font Size: 16, font Name: 'Lucida Sans Unicode' }, // Smaller font view Window: { min: 0, max: 14 }, ticks: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] }, chart Area: { top: 20, width: '80%', height: '75%' }, // Adjusted chart area legend: {position: 'none'}, width: '100%', // Make chart responsive height: '100%', // Let container control height line Width: 3, colors: ['black'] }; // Instantiate and draw our chart, passing in some options. var chart_div = document.get Element By Id('chart_div'); var chart = new google.visualization.Line Chart(chart_div); // Ensure chart_div exists google.visualization.events.add Listener(chart, 'ready', function() { // Add a small delay to ensure SVG is rendered, or check repeatedly set Timeout(function() { var svg = chart_div.query Selector('svg'); if (!svg) { console.error("SVG element not found in chart_div after ready event."); return; // Exit if SVG not found } var gradient = create SVG('linear Gradient', {x1:0,y1:0, x2:0, y1:1}, {id:'fx'}); var defs = svg.query Selector('defs'); if (!defs) { defs = create SVG('defs', {}, {}); // Ensure there's a first child to insert before, otherwise just append if (svg.first Child) { svg.insert Before(defs, svg.first Child); } else { svg.append Child(defs); } } // Clear existing gradients if any to avoid duplicates on resize var existing Grad = defs.query Selector('#fx'); if (existing Grad) { defs.remove Child(existing Grad); } defs.append Child(gradient); gradient.append Child(create SVG('stop',{offset:'0%'})); gradient.append Child(create SVG('stop',{offset:'25%'})); gradient.append Child(create SVG('stop',{offset:'50%'})); gradient.append Child(create SVG('stop',{offset:'100%'})); // Safely apply gradient fill var rect Element = $(svg).find("[clip-path]").parent().find("rect").first(); if (rect Element.length > 0) { rect Element.attr("fill", "url(#fx)").attr("fill-opacity", "1"); } else { console.warn("Could not find the rectangle element to apply gradient fill."); } change Chart Color($("#indtype").val()); }, 100); // Small delay (100ms) - adjust if needed }); function select Handler() { var selected Item = chart.get Selection()[0]; if (selected Item) { var p X = data.get Value(selected Item.row, 0).to Fixed(2); var p Y = data.get Value(selected Item.row, 1).to Fixed(2); $("#p X").val(p X); $("#p Y").val(p Y); } } google.visualization.events.add Listener(chart, 'select', select Handler); chart.draw(data, options) } function get Float(id) { return parse Float( $("#"+id).val() ); } function set Float(id, v) { $("#"+id).val( parse Float(v).to Fixed(2) ) ; } function calculatep Kb() { var x = (-Math.log10(get Float("Kb"))).to Fixed(2); $("#p Kb").val(x); if(get Float("p Kb")<2 || get Float("p Kb")>10) {alert("check Kb value, use scientific notation");} } function p HWB() { return 14 + Math.log10(Math.sqrt( get Float("Kb") * get Float("bconc") )); } function p HBB(conc B, conc S) { return 14 - (-Math.log10(get Float("Kb")) + (Math.log10(conc S/conc B))); } function p HWA(conc) { return -Math.log10(Math.sqrt(1e-14/get Float("Kb")*conc)); } function p HSA(conc) { return -Math.log10(conc) } function calculate PH() { if ( burette Vol.to Fixed(2) == 0 ) { return p HWB(); } else if (burette Vol.to Fixed(2) == get Float("avol").to Fixed(2) ) { return p HWA(init Mol/tot Vol); } else if (burette Vol < get Float("avol") ) { return p HBB( ( init Mol - burette Vol * get Float("aconc") * get Float("atype") ), (burette Vol * get Float("aconc") * get Float("atype")) ); } else if (burette Vol > get Float("avol") ) { return p HSA( ( burette Vol * get Float("aconc") * get Float("atype") - init Mol ) / (tot Vol) ); } } function init Vars() { init Mol = get Float("bconc") * get Float("bvol"); tot Vol = get Float("bvol"); burette Vol = 0; } function titrate Step() { if (init Mol == -1) init Vars(); burette Vol += get Float("inc"); tot Vol += get Float("inc"); $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); $("#titable").parent().scroll Top( $("#titable").height() ) } function update Neutralisation() { $("#avol").val( ( ( get Float("bvol") * get Float("bconc") ) / ( get Float("atype") * get Float("aconc") ) ).to Fixed(2) ); if (get Float("avol") > 50) {alert("Titre volume cannot exceed maximum capacity of burette!");} else if (get Float("avol") < 15) {alert("Titre volume too small, leads to large percentage error!");} reset Titrate(); } function auto Titrate() { // Added check for page Loaded if (page Loaded == false) { alert("Please wait for a while, page scripts still loading."); return; } // Changed loop to use set Timeout for better responsiveness function do Step() { if (burette Vol < get Float("stopt")) { titrate Step(); window.set Timeout(do Step, 1); // Schedule next step } else { draw Chart(); // Draw chart when done } } do Step(); // Start the process } function reset Titrate() { $("#titable tbody").html( "" ) init Vars(); // Re-initialize variables $("#titable tbody").html( $("#titable tbody").html() + "<tr><td>" + burette Vol.to Fixed(2) + "</td><td>" + calculate PH().to Fixed(2) + "</td><td>" + tot Vol.to Fixed(2) + "</td></tr>"); draw Chart(); // Redraw chart after reset } var chart Col = {'0': ["white", "white", "white", "white"], '1': ["red", "orange", "#ffff33", "#ffff33"], '2': ["#990099", "grey", "#009933", "#009933"], '3': ["white", "white", "white","fuchsia"], '4': ["white", "white", "white","#2c5ba5"], }; function change Chart Color(ind Type) { $("#fx stop:nth-child(1)").css("stop-color",chart Col[ind Type][0]) $("#fx stop:nth-child(2)").css("stop-color",chart Col[ind Type][1]) $("#fx stop:nth-child(3)").css("stop-color",chart Col[ind Type][2]) $("#fx stop:nth-child(4)").css("stop-color",chart Col[ind Type][3]) } function check Boxes() { if (get Float("p X") == 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==false && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") < get Float("avol") && get Float("p X") > 0 && $("#WB").prop('checked')==true && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else if (get Float("p X") > get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==true) {alert("Good job!");} else if (get Float("p X") == get Float("avol") && $("#WB").prop('checked')==false && $("#AS").prop('checked')==true && $("#SA").prop('checked')==false) {alert("Good job!");} else {alert("Please try again.");} } function check Buffer() { if ( (14-get Float("p Y")) > (get Float("p Kb")-1) && (14-get Float("p Y")) < (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==true) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } else if ( (14-get Float("p Y")) < (get Float("p Kb")-1) || (14-get Float("p Y")) > (get Float("p Kb")+1) ) { if($("#buffer").prop('checked')==false) {alert("Good job!");} else {alert("Please try again. What are the 2 components required in large excess to form a buffer?");} } } function check Quiz() { const answer = document.get Element By Id('quiz Q1').value; const result Element = document.get Element By Id('quiz Result'); if (answer === 'acidic') { result Element.text Content = 'Correct! The salt formed (conjugate acid of the weak base) hydrolyzes water to produce H+, making the solution acidic.'; result Element.class Name = 'mt-2 text-success'; } else if (answer === '') { result Element.text Content = 'Please select an answer.'; result Element.class Name = 'mt-2 text-warning'; } else { result Element.text Content = 'Incorrect. Try again. Hint: Consider the hydrolysis of the salt formed.'; result Element.class Name = 'mt-2 text-danger'; } } </script> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Titration Curve Generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar Nav" aria-controls="navbar Nav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar Nav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.html">Introduction</a> </li> <li class="nav-item"> <a class="nav-link" href="SASB.html">Strong Acid - Strong Base</a> </li> <li class="nav-item"> <a class="nav-link" href="SBSA.html">Strong Base - Strong Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="WASB.html">Weak Acid - Strong Base</a> </li> <li class="nav-item active"> <a class="nav-link" href="WBSA.html">Weak Base - Strong Acid <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="SBWA.html">Strong Base - Weak Acid</a> </li> <li class="nav-item"> <a class="nav-link" href="SAWB.html">Strong Acid - Weak Base</a> </li> </ul> </div> </nav> <d?

2. Which approach best supports concept learning?

3. Why should only one variable be changed at a time?

4. What evidence should students include in their explanation?

5. What makes a good conclusion after using the model?

7. Learning Pulse

Anonymous activity shows this resource is being discovered, revisited, and used by learners in different places.

--currently viewing
--total page views

Where Recent Learners Are From

Country or region is inferred anonymously from server location headers when available. No names, accounts, or IP addresses are shown.

Detecting locations...
Updating anonymous page activity...