diff --git a/packages/doenetml-worker/src/components/dynamicalSystems/CobwebPolyline.js b/packages/doenetml-worker/src/components/dynamicalSystems/CobwebPolyline.js
index 0325e6477..919292f01 100644
--- a/packages/doenetml-worker/src/components/dynamicalSystems/CobwebPolyline.js
+++ b/packages/doenetml-worker/src/components/dynamicalSystems/CobwebPolyline.js
@@ -129,7 +129,10 @@ export default class CobwebPolyline extends Polyline {
let essentialInitialPoint = {};
for (let arrayKey of arrayKeys) {
let varEnding = Number(arrayKey) + 1;
- if (dependencyValuesByKey[arrayKey].initialPointAttr) {
+ if (
+ dependencyValuesByKey[arrayKey].initialPointAttr
+ ?.stateValues["x" + varEnding]
+ ) {
initialPoint[arrayKey] =
dependencyValuesByKey[
arrayKey
diff --git a/packages/doenetml/src/Viewer/renderers/cobwebPolyline.jsx b/packages/doenetml/src/Viewer/renderers/cobwebPolyline.jsx
index 46cb45d2d..1053df7d4 100644
--- a/packages/doenetml/src/Viewer/renderers/cobwebPolyline.jsx
+++ b/packages/doenetml/src/Viewer/renderers/cobwebPolyline.jsx
@@ -79,20 +79,9 @@ export default React.memo(function CobwebPolyline(props) {
diagonalAttributes,
);
- let validCoords = true;
-
- for (let coords of SVs.numericalVertices) {
- if (!Number.isFinite(coords[0])) {
- validCoords = false;
- }
- if (!Number.isFinite(coords[1])) {
- validCoords = false;
- }
- }
-
let jsxPolylineAttributes = {
name: SVs.labelForGraph,
- visible: !SVs.hidden && validCoords,
+ visible: !SVs.hidden,
withLabel: SVs.labelForGraph !== "",
fixed: true,
layer: 10 * SVs.layer + LINE_LAYER_OFFSET,
@@ -112,7 +101,7 @@ export default React.memo(function CobwebPolyline(props) {
jsxPointAttributes.current = {
fixed: !SVs.draggable || SVs.fixed,
- visible: !SVs.hidden && validCoords && SVs.draggable,
+ visible: !SVs.hidden && SVs.draggable,
withLabel: true,
name: "A",
layer: 10 * SVs.layer + VERTEX_LAYER_OFFSET,
@@ -142,13 +131,13 @@ export default React.memo(function CobwebPolyline(props) {
if (i === 0) {
pointAttributes.name = `(${varName}_0,0)`;
} else if (i % 2 === 1) {
- pointAttributes.name = `(${varName}_${
+ pointAttributes.name = `(${varName}_{${
(i - 1) / 2
- }, ${varName}_${(i + 1) / 2})`;
+ }}, ${varName}_{${(i + 1) / 2}})`;
} else {
- pointAttributes.name = `(${varName}_${i / 2}, ${varName}_${
+ pointAttributes.name = `(${varName}_{${i / 2}}, ${varName}_{${
i / 2
- })`;
+ }})`;
}
if (i !== SVs.numPoints - 1) {
pointAttributes.visible = false;
@@ -299,17 +288,6 @@ export default React.memo(function CobwebPolyline(props) {
curveJXG.current.needsUpdate = true;
curveJXG.current.updateCurve();
- let validCoords = true;
-
- for (let coords of SVs.numericalVertices) {
- if (!Number.isFinite(coords[0])) {
- validCoords = false;
- }
- if (!Number.isFinite(coords[1])) {
- validCoords = false;
- }
- }
-
let varName = SVs.variable.toString();
// add or delete points as required and change data array size
@@ -322,13 +300,13 @@ export default React.memo(function CobwebPolyline(props) {
if (i === 0) {
pointAttributes.name = `(${varName}_0,0)`;
} else if (i % 2 === 1) {
- pointAttributes.name = `(${varName}_${
+ pointAttributes.name = `(${varName}_{${
(i - 1) / 2
- }, ${varName}_${(i + 1) / 2})`;
+ }}, ${varName}_{${(i + 1) / 2}})`;
} else {
- pointAttributes.name = `(${varName}_${
+ pointAttributes.name = `(${varName}_{${
i / 2
- }, ${varName}_${i / 2})`;
+ }}, ${varName}_{${i / 2}})`;
}
if (i !== SVs.numPoints - 1) {
pointAttributes.visible = false;
@@ -386,33 +364,21 @@ export default React.memo(function CobwebPolyline(props) {
let visible = !SVs.hidden;
- if (validCoords) {
- polylineJXG.current.visProp["visible"] = visible;
- polylineJXG.current.visPropCalc["visible"] = visible;
- // polylineJXG.current.setAttribute({visible: visible})
+ polylineJXG.current.visProp["visible"] = visible;
+ polylineJXG.current.visPropCalc["visible"] = visible;
+ // polylineJXG.current.setAttribute({visible: visible})
- for (let i = 0; i < SVs.numPoints - 1; i++) {
- pointsJXG.current[i].visProp["visible"] = false;
- pointsJXG.current[i].visPropCalc["visible"] = false;
- }
- if (SVs.numPoints > 0) {
- if (SVs.draggable) {
- pointsJXG.current[SVs.numPoints - 1].visProp[
- "visible"
- ] = visible;
- pointsJXG.current[SVs.numPoints - 1].visPropCalc[
- "visible"
- ] = visible;
- }
- }
- } else {
- polylineJXG.current.visProp["visible"] = false;
- polylineJXG.current.visPropCalc["visible"] = false;
- // polylineJXG.current.setAttribute({visible: false})
-
- for (let i = 0; i < SVs.numPoints; i++) {
- pointsJXG.current[i].visProp["visible"] = false;
- pointsJXG.current[i].visPropCalc["visible"] = false;
+ for (let i = 0; i < SVs.numPoints - 1; i++) {
+ pointsJXG.current[i].visProp["visible"] = false;
+ pointsJXG.current[i].visPropCalc["visible"] = false;
+ }
+ if (SVs.numPoints > 0) {
+ if (SVs.draggable) {
+ pointsJXG.current[SVs.numPoints - 1].visProp["visible"] =
+ visible;
+ pointsJXG.current[SVs.numPoints - 1].visPropCalc[
+ "visible"
+ ] = visible;
}
}
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
index 9fc3a9d67..e7d4c3bf6 100644
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
+++ b/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
@@ -2737,4 +2737,75 @@ describe("CobwebPolyline Tag Tests", function () {
cy.get(cesc2("#/cobwebTutorial/next_button")).should("be.disabled");
cy.get(cesc2("#/ca")).should("have.text", "1");
});
+
+ it("handle bad initial point, lock to solution", () => {
+ cy.window().then(async (win) => {
+ win.postMessage(
+ {
+ doenetML: `
+
Initial point:
Vertices: $cobweb.vertices
+ + + `, + }, + "*", + ); + }); + + cy.get(cesc2("#/_p1")).should("have.text", "Initial point: "); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(0) + .should("have.text", "(_,0)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(3) + .should("have.text", "(NaN,NaN)"); + + cy.get(cesc2("#/x0") + " textarea").type("0.9{enter}", { force: true }); + + cy.get(cesc2("#/_p2") + " .mjx-mrow").should("contain.text", "(0.9,0)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(0) + .should("have.text", "(0.9,0)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(2) + .should("have.text", "(0.9,0.81)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(100) + .should("have.text", "(0,0)"); + + cy.get(cesc2("#/x0") + " textarea").type( + "{end}{backspace}{backspace}{backspace}(1.1,3){enter}", + { + force: true, + }, + ); + + cy.get(cesc2("#/_p2") + " .mjx-mrow").should("contain.text", "(1.1,3)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(0) + .should("have.text", "(1.1,3)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(2) + .should("have.text", "(1.1,1.21)"); + + cy.get(cesc2("#/_p2") + " .mjx-mrow") + .eq(100) + .should("have.text", "(∞,∞)"); + }); });