Sindbad~EG File Manager

Current Path : /home/beeson/public_html/WebMathXpert/ThreeBodyWeb/
Upload File :
Current File : //home/beeson/public_html/WebMathXpert/ThreeBodyWeb/ThreeBodyControls.js

// ThreeBodyControls.js
// to create and handle the tools in the left pane of DrawSolution.php

document.addEventListener("DOMContentLoaded", function() {
    // Create a control panel div for the slider and Save button in the left 65px of the window.
    var controlPanel = document.createElement("div");
    controlPanel.id = "controlPanel";
    controlPanel.style.position = "absolute";
    controlPanel.style.top = "0";
    controlPanel.style.left = "0";
    controlPanel.style.width = "65px";
    controlPanel.style.height = "100%";
    controlPanel.style.backgroundColor = "#eee"; // light gray background for visibility
	 controlPanel.style.zIndex = "2"; // ensure it stays on top
    document.body.appendChild(controlPanel);

    // Create the slider (an <input type="range"> element)
    var slider = document.createElement("input");
    slider.type = "range";
    slider.id = "timeSlider";
	 // Make the slider vertical and in the control panel
	 slider.style.transform = "rotate(-90deg) translateX(-200px) translateY(-65px)";
	 slider.style.width = "200px"; // Adjust as needed
	 slider.style.height = "20px"; // Adjust as needed
    controlPanel.appendChild(slider);
	 
	if(! indatabase){
		// Create the Save button
		var saveButton = document.createElement("button");
		saveButton.style.width = "62px";
		saveButton.style.height = "32px";
		saveButton.style.backgroundColor = "darkblue";
		saveButton.style.color = "white";
		saveButton.style.fontFamily = "Arial";
		saveButton.textContent = "Save";
		saveButton.id = "save";
		// Append the Save button to the control panel
		controlPanel.appendChild(saveButton);
 	}
    // Create the Edit button
    var editButton = document.createElement("button");
    editButton.style.width = "62px";
    editButton.style.height = "32px";
    editButton.style.backgroundColor = "darkblue";
    editButton.style.color = "white";
    editButton.style.fontFamily = "Arial";
    editButton.textContent = "Edit";
	 editButton.id = "edit";
    
    // Append the  Edit button to the control panel
    controlPanel.appendChild(editButton);
	 
	async function SaveButtonHandler(event) {
	     event.preventDefault();
	     // Ask for caption (optional, max 127 chars)
		  const caption = await GetCaption();
		     if (caption === null || caption === "") return;  // User canceled
		  // Create a hidden form to POST data to SaveThreeBody.php.
	     var form = document.createElement("form");
	     form.method = "POST";
	     form.action = "SaveThreeBody.php";

	     // Retrieve document-level data.
	     // These elements (if they exist) hold the user-entered tmax value.
		  // tmax and caption should be defined before including this file

	     // Assume the bodies array is available globally.
	     var bodiesArray = window.bodies || [];
	     var nbodies = bodiesArray.length;

	     // Use "Pending" as a placeholder since the new SVG filename is constructed in SaveThreeBody.php.
	     var imageFilename = "Pending";
	
	     // Create hidden inputs for document-level fields.
	     var docFields = {
	         caption: caption,
	         tmax: tmax,
	         nbodies: nbodies,
			   integrationMethod: integrationMethod
	     };
	     for (var key in docFields) {
	         var input = document.createElement("input");
	         input.type = "hidden";
	         input.name = key;
	         input.value = docFields[key];
	         form.appendChild(input);
	     }

	     // For each body, create hidden inputs for its properties.
	     bodiesArray.forEach(function(body) {
	         ["mass", "color", "r", "x0", "y0", "p0", "q0"].forEach(function(prop) {
	             var input = document.createElement("input");
	             input.type = "hidden";
	             input.name = prop + "[]";
	             input.value = body[prop];
	             form.appendChild(input);
	         });
	     });

	     // Append the form to the document and submit it.
	     document.body.appendChild(form);
	     form.submit();
	 }
	 
	 function EditButtonHandler(event) {
	     event.preventDefault();
        // Build a hidden form.
        const form = document.createElement("form");
        form.method = "post";
        form.action = "ThreeBody.php";
      
	     caption = document.getElementById("caption") ? document.getElementById("caption").value : "";
	     tmax = document.getElementById("tmax") ? document.getElementById("tmax").value : "1000";
		  integrationMethod= document.getElementById("integrationMethod") ? document.getElementById("integrationMethod").value : "rk4";
        // document-level fields.
	     var docFields = {
	         caption: caption,
	         tmax: tmax,
	         nbodies: nbodies,
			   integrationMethod: integrationMethod
	     };
		 //  var image_filename = document.getElementById("image_filenameInput") ? document.getElementById("image_filenameInput").value : "oops";
	     // Assume the bodies array is available globally.
	     var bodiesArray = window.bodies || [];
	     var nbodies = bodiesArray.length;
		  console.log(bodiesArray);

	     // Create hidden inputs for document-level fields.
	   
	     for (var key in docFields) {
	         var input = document.createElement("input");
	         input.type = "hidden";
	         input.name = key;
	         input.value = docFields[key];
	         form.appendChild(input);
	     }
      
        // Populate body data as arrays (e.g., mass[], color[], etc.).
        const bodyFields = ["mass", "color", "r", "x0", "y0", "p0", "q0"];
        if (bodiesArray && bodiesArray.length > 0) {
          bodiesArray.forEach(body => {
            bodyFields.forEach(field => {
              const input = document.createElement("input");
              input.type = "hidden";
              input.name = field + "[]";
              input.value = (body[field] !== null && body[field] !== undefined) ? body[field] : "";
              form.appendChild(input);
            });
          });
        }     
        document.body.appendChild(form);
		  // console.log(form);
        form.submit();
	 }
    
    // Attach the event handlers to the Save and Edit buttons
	if(!indatabase){
		saveButton.addEventListener("click", SaveButtonHandler);
	}
	editButton.addEventListener("click", EditButtonHandler);
	 
	// Add an "Animate" button to the control panel.
	//  This doesn't (yet) work very well so I commented it out.
	//  var animateButton = document.createElement("button");
	//  animateButton.textContent = "Animate";
	//  controlPanel.appendChild(animateButton);

	// Get the SVG container element.
	var svgContainer = document.getElementById("svgContainer");
	if (!svgContainer) {
		console.error("SVG container with id 'svgContainer' not found.");
		return;
	}

    // Find all <path> elements with a "body" attribute inside the svgContainer.
    var pathElems = svgContainer.querySelectorAll("path[body]");
    
    // We'll build two objects:
    // - bodyPaths: maps a numeric body id to an array of points [{x, y}, ...]
    // - bodyCircles: maps a numeric body id to its corresponding SVG circle element.
    var bodyPaths = {};
    var bodyCircles = {};
    var numPoints = 0; // assume all paths have the same number of points

    // Function to parse the "d" attribute of a path.
    // Expected format: "M x1 y1 L x2 y2 L x3 y3 ..."
    function parsePathPoints(d) {
        var points = [];
        // Replace commas with spaces and split on "M" or "L"
        d = d.replace(/,/g, " ");
        var parts = d.split(/[ML]/i);
        for (var i = 0; i < parts.length; i++) {
            var part = parts[i].trim();
            if (!part) continue;
            var coords = part.split(/\s+/);
            if (coords.length >= 2) {
                var x = parseFloat(coords[0]);
                var y = parseFloat(coords[1]);
                points.push({ x: x, y: y });
            }
        }
        return points;
    }

    // Process each path element.
    pathElems.forEach(function(elem) {
        var bodyIdStr = elem.getAttribute("body");
        var bodyId = parseInt(bodyIdStr, 10);    // these will be 1,2,...
        var d = elem.getAttribute("d");
        var points = parsePathPoints(d);
        bodyPaths[bodyId] = points;
        if (numPoints === 0) {
            numPoints = points.length;
        } else if (points.length !== numPoints) {
            console.warn("Path for body " + bodyId + " has a different number of points.");
        }
    });

    // Set up the slider range.
    slider.min = 0;
    slider.max = numPoints - 1;
    slider.value = 0;

    // Create a circle for each body.
    // Assumes global array "bodies" exists where bodies[id].radius and bodies[id].color exist.
    for (var id in bodyPaths) {
        var bodyId = parseInt(id, 10);
        // Create an SVG circle element using the proper namespace.
        var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        
        // Use the radius and color from the bodies array; if not available, use defaults.
        var bodyObj = (typeof bodies !== "undefined" && bodies[bodyId-1])
                      ? bodies[bodyId-1]   
                      : { radius: 5, color: "#000" };
        // Ensure the radius is a valid number (fallback to 5 if invalid)
        var radius = (typeof bodyObj.r === "number" && bodyObj.r > 0)
                     ? bodyObj.r
                     : 5;
                     
        // Set the radius attribute properly.
        circle.setAttribute("r", radius);
		  let colorstring = bodyObj.color;  // Now the Engine sends them in rgb(r,g,b) form as strings
		 //  let red = colorNumber & 0xff;  // this is the way they come from the Engine, red not shifted
		 //  let green = colorNumber & 0xff00;
		 //  let blue = colorNumber & 0xff0000;
		//   let colorstring = "rgb("+red+ "," + green + "," + blue + ")";
        circle.setAttribute("fill", colorstring);
        circle.setAttribute("id", "bodyCircle" + bodyId);
		  circle.style.display = 'block';
        
        // Initially position the circle at the first point of the corresponding path.
        var pt = bodyPaths[bodyId][0];
        circle.setAttribute("cx", pt.x);
        circle.setAttribute("cy", pt.y);
        graph0 = document.getElementById('graph0');
        // Append the circle to that svg element
        graph0.appendChild(circle);
        bodyCircles[bodyId] = circle;
		 
    }

    // Function to update all circles to a given index along their paths.
    function updateCircles(index) {
        for (var id in bodyPaths) {
            var points = bodyPaths[id];
            if (index < 0) index = 0;
            if (index >= points.length) index = points.length - 1;
            var pt = points[index];
            var circle = bodyCircles[id];
            if (circle && pt) {
                circle.setAttribute("cx", pt.x);
                circle.setAttribute("cy", pt.y);
            }
        }
    }

    // Attach an event listener to the slider.
    slider.addEventListener("input", function() {
        var idx = parseInt(slider.value, 10);
        updateCircles(idx);
    });
 // Set up animation variables.
    var animationInterval = null;
    var duration = 1; // 1 seconds per full cycle
    var minVal = parseInt(slider.min, 10);
    var maxVal = parseInt(slider.max, 10);
    var steps = maxVal - minVal;
    var stepDuration = steps > 0 ? duration / steps : duration;
/*
    // Animate button toggles the animation on/off.
	 animateButton.addEventListener("click", function() {
	     if (animationInterval === null) {
	         // Recalculate stepDuration each time you start the animation.
	         var duration = 1; // change this value as desired
	         var minVal = parseInt(slider.min, 10);
	         var maxVal = parseInt(slider.max, 10);
	         var steps = maxVal - minVal;
	         var stepDuration = steps > 0 ? duration / steps : duration;

	         animationInterval = setInterval(function() {
	             var current = parseInt(slider.value, 10);
	             if (current < maxVal) {
	                 slider.value = current + 1;
	             } else {
	                 slider.value = minVal;
	             }
	             updateCircles(parseInt(slider.value, 10));
	         }, stepDuration);
	         animateButton.textContent = "Stop Animation";
	     } else {
	         clearInterval(animationInterval);
	         animationInterval = null;
	         animateButton.textContent = "Animate";
	     }
	 });
*/
});

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists