@doenet/doenetml 0.6.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (549) hide show
  1. package/.prettierrc +3 -0
  2. package/LICENSE +661 -0
  3. package/README.md +146 -0
  4. package/cypress/e2e/ActivityViewer/activityVariants.cy.js +1770 -0
  5. package/cypress/e2e/ActivityViewer/compiledActivity.cy.js +83 -0
  6. package/cypress/e2e/ActivityViewer/relationshipsAmongPages.cy.js +697 -0
  7. package/cypress/e2e/answerValidation/errorinnumbers.cy.js +2125 -0
  8. package/cypress/e2e/answerValidation/factoring.cy.js +1945 -0
  9. package/cypress/e2e/answerValidation/factoringOldAlgorithm.cy.js +892 -0
  10. package/cypress/e2e/answerValidation/functionanswers.cy.js +314 -0
  11. package/cypress/e2e/answerValidation/matchingpatterns.cy.js +287 -0
  12. package/cypress/e2e/answerValidation/matchpartial.cy.js +6711 -0
  13. package/cypress/e2e/answerValidation/pointlocation.cy.js +3989 -0
  14. package/cypress/e2e/answerValidation/symbolicequality.cy.js +1893 -0
  15. package/cypress/e2e/answerValidation/videoProgress.cy.js +210 -0
  16. package/cypress/e2e/assignNames/basiccopy.cy.js +2376 -0
  17. package/cypress/e2e/assignNames/collections.cy.js +9247 -0
  18. package/cypress/e2e/assignNames/selects.cy.js +105 -0
  19. package/cypress/e2e/assignNames/sequences.cy.js +1964 -0
  20. package/cypress/e2e/baseComponent/basecomponentproperties.cy.js +999 -0
  21. package/cypress/e2e/baseComponent/doenetMLtext.cy.js +427 -0
  22. package/cypress/e2e/chemistry/atom.cy.js +201 -0
  23. package/cypress/e2e/chemistry/ion.cy.js +608 -0
  24. package/cypress/e2e/chemistry/ioniccompound.cy.js +133 -0
  25. package/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js +2653 -0
  26. package/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js +311 -0
  27. package/cypress/e2e/dynamicalsystem/equilibriumline.cy.js +279 -0
  28. package/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js +283 -0
  29. package/cypress/e2e/dynamicalsystem/odesystem.cy.js +1834 -0
  30. package/cypress/e2e/equality/mathexpressions.cy.js +948 -0
  31. package/cypress/e2e/graphing/graphreferences.cy.js +978 -0
  32. package/cypress/e2e/graphing/graphreferences2.cy.js +615 -0
  33. package/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js +401 -0
  34. package/cypress/e2e/tagSpecific/angle.cy.js +3898 -0
  35. package/cypress/e2e/tagSpecific/animatefromsequence.cy.js +2306 -0
  36. package/cypress/e2e/tagSpecific/answer.cy.js +31647 -0
  37. package/cypress/e2e/tagSpecific/bestfitline.cy.js +612 -0
  38. package/cypress/e2e/tagSpecific/blockquote.cy.js +30 -0
  39. package/cypress/e2e/tagSpecific/boolean.cy.js +742 -0
  40. package/cypress/e2e/tagSpecific/booleaninput.cy.js +1283 -0
  41. package/cypress/e2e/tagSpecific/booleanlist.cy.js +588 -0
  42. package/cypress/e2e/tagSpecific/booleanoperators.cy.js +596 -0
  43. package/cypress/e2e/tagSpecific/booleanoperatorsonmath.cy.js +498 -0
  44. package/cypress/e2e/tagSpecific/callaction.cy.js +2835 -0
  45. package/cypress/e2e/tagSpecific/choiceinput.cy.js +3205 -0
  46. package/cypress/e2e/tagSpecific/circle.cy.js +22036 -0
  47. package/cypress/e2e/tagSpecific/codeeditor.cy.js +1995 -0
  48. package/cypress/e2e/tagSpecific/collect.cy.js +5035 -0
  49. package/cypress/e2e/tagSpecific/componentsize.cy.js +502 -0
  50. package/cypress/e2e/tagSpecific/conditionalcontent.cy.js +3495 -0
  51. package/cypress/e2e/tagSpecific/contentBrowser.cy.js +335 -0
  52. package/cypress/e2e/tagSpecific/contentpicker.cy.js +261 -0
  53. package/cypress/e2e/tagSpecific/copy.cy.js +12627 -0
  54. package/cypress/e2e/tagSpecific/copy2.cy.js +5698 -0
  55. package/cypress/e2e/tagSpecific/curve.bezier.cy.js +12440 -0
  56. package/cypress/e2e/tagSpecific/curve.cy.js +1716 -0
  57. package/cypress/e2e/tagSpecific/curve.function.cy.js +1471 -0
  58. package/cypress/e2e/tagSpecific/curve.parametrized.cy.js +920 -0
  59. package/cypress/e2e/tagSpecific/document.cy.js +234 -0
  60. package/cypress/e2e/tagSpecific/endpoint.cy.js +197 -0
  61. package/cypress/e2e/tagSpecific/evaluate.cy.js +8895 -0
  62. package/cypress/e2e/tagSpecific/extract.cy.js +2282 -0
  63. package/cypress/e2e/tagSpecific/feedback.cy.js +2941 -0
  64. package/cypress/e2e/tagSpecific/function.cy.js +9450 -0
  65. package/cypress/e2e/tagSpecific/functioniterates.cy.js +1178 -0
  66. package/cypress/e2e/tagSpecific/functionoperators.cy.js +4047 -0
  67. package/cypress/e2e/tagSpecific/graph.cy.js +2491 -0
  68. package/cypress/e2e/tagSpecific/group.cy.js +683 -0
  69. package/cypress/e2e/tagSpecific/hint.cy.js +204 -0
  70. package/cypress/e2e/tagSpecific/image.cy.js +770 -0
  71. package/cypress/e2e/tagSpecific/integer.cy.js +206 -0
  72. package/cypress/e2e/tagSpecific/label.cy.js +800 -0
  73. package/cypress/e2e/tagSpecific/legend.cy.js +1001 -0
  74. package/cypress/e2e/tagSpecific/line.cy.js +12167 -0
  75. package/cypress/e2e/tagSpecific/linesegment.cy.js +4749 -0
  76. package/cypress/e2e/tagSpecific/lorem.cy.js +289 -0
  77. package/cypress/e2e/tagSpecific/map.cy.js +4476 -0
  78. package/cypress/e2e/tagSpecific/matchespattern.cy.js +693 -0
  79. package/cypress/e2e/tagSpecific/math.cy.js +10990 -0
  80. package/cypress/e2e/tagSpecific/mathdisplay.cy.js +2689 -0
  81. package/cypress/e2e/tagSpecific/mathinput.cy.js +15628 -0
  82. package/cypress/e2e/tagSpecific/mathinputgraph.cy.js +566 -0
  83. package/cypress/e2e/tagSpecific/mathlist.cy.js +4073 -0
  84. package/cypress/e2e/tagSpecific/mathoperators.cy.js +13851 -0
  85. package/cypress/e2e/tagSpecific/matrix.cy.js +8825 -0
  86. package/cypress/e2e/tagSpecific/matrixinput.cy.js +16277 -0
  87. package/cypress/e2e/tagSpecific/module.cy.js +1771 -0
  88. package/cypress/e2e/tagSpecific/number.cy.js +2221 -0
  89. package/cypress/e2e/tagSpecific/numberlist.cy.js +1285 -0
  90. package/cypress/e2e/tagSpecific/p.cy.js +72 -0
  91. package/cypress/e2e/tagSpecific/paginator.cy.js +2983 -0
  92. package/cypress/e2e/tagSpecific/parabola.cy.js +14331 -0
  93. package/cypress/e2e/tagSpecific/paragraphmarkup.cy.js +104 -0
  94. package/cypress/e2e/tagSpecific/periodicset.cy.js +1439 -0
  95. package/cypress/e2e/tagSpecific/piecewisefunction.cy.js +1055 -0
  96. package/cypress/e2e/tagSpecific/pluralize.cy.js +274 -0
  97. package/cypress/e2e/tagSpecific/point.cy.js +8895 -0
  98. package/cypress/e2e/tagSpecific/point2.cy.js +10259 -0
  99. package/cypress/e2e/tagSpecific/polygon.cy.js +5039 -0
  100. package/cypress/e2e/tagSpecific/polyline.cy.js +4704 -0
  101. package/cypress/e2e/tagSpecific/problem.cy.js +2768 -0
  102. package/cypress/e2e/tagSpecific/ray.cy.js +10770 -0
  103. package/cypress/e2e/tagSpecific/rectangle.cy.js +2143 -0
  104. package/cypress/e2e/tagSpecific/ref.cy.js +420 -0
  105. package/cypress/e2e/tagSpecific/regularPolygon.cy.js +1006 -0
  106. package/cypress/e2e/tagSpecific/regularPolygon2.cy.js +100 -0
  107. package/cypress/e2e/tagSpecific/regularPolygon3.cy.js +777 -0
  108. package/cypress/e2e/tagSpecific/samplerandomnumbers.cy.js +3619 -0
  109. package/cypress/e2e/tagSpecific/sectioning.cy.js +3530 -0
  110. package/cypress/e2e/tagSpecific/select.cy.js +5376 -0
  111. package/cypress/e2e/tagSpecific/selectfromsequence.cy.js +3846 -0
  112. package/cypress/e2e/tagSpecific/selectrandomnumbers.cy.js +2914 -0
  113. package/cypress/e2e/tagSpecific/sequence.cy.js +2093 -0
  114. package/cypress/e2e/tagSpecific/shuffle.cy.js +490 -0
  115. package/cypress/e2e/tagSpecific/sidebyside.cy.js +8057 -0
  116. package/cypress/e2e/tagSpecific/singlecharactercomponents.cy.js +72 -0
  117. package/cypress/e2e/tagSpecific/slider.cy.js +914 -0
  118. package/cypress/e2e/tagSpecific/solution.cy.js +109 -0
  119. package/cypress/e2e/tagSpecific/solveequations.cy.js +1026 -0
  120. package/cypress/e2e/tagSpecific/sort.cy.js +1685 -0
  121. package/cypress/e2e/tagSpecific/spreadsheet.cy.js +5971 -0
  122. package/cypress/e2e/tagSpecific/subsetofreals.cy.js +2725 -0
  123. package/cypress/e2e/tagSpecific/substitute.cy.js +2646 -0
  124. package/cypress/e2e/tagSpecific/tabular.cy.js +36 -0
  125. package/cypress/e2e/tagSpecific/text.cy.js +975 -0
  126. package/cypress/e2e/tagSpecific/textinput.cy.js +2177 -0
  127. package/cypress/e2e/tagSpecific/textlist.cy.js +369 -0
  128. package/cypress/e2e/tagSpecific/triangle.cy.js +1936 -0
  129. package/cypress/e2e/tagSpecific/triggerset.cy.js +2023 -0
  130. package/cypress/e2e/tagSpecific/updatevalue.cy.js +3288 -0
  131. package/cypress/e2e/tagSpecific/vector.cy.js +20183 -0
  132. package/cypress/e2e/tagSpecific/video.cy.js +612 -0
  133. package/cypress/e2e/tagSpecific/when.cy.js +202 -0
  134. package/cypress/e2e/variants/specifysinglevariant.cy.js +6726 -0
  135. package/cypress/e2e/variants/uniquevariants.cy.js +4846 -0
  136. package/cypress/fixtures/example.json +5 -0
  137. package/cypress/support/commands.js +32 -0
  138. package/cypress/support/e2e.js +31 -0
  139. package/cypress.config.js +18 -0
  140. package/docs/codeSnippet.jsx +11 -0
  141. package/docs/index.html +133 -0
  142. package/docs/index.jsx +138 -0
  143. package/docs/prism.css +3 -0
  144. package/index.html +14 -0
  145. package/index.js +21 -0
  146. package/media/answer_example.png +0 -0
  147. package/media/graph_example.png +0 -0
  148. package/media/graph_markup_example.png +0 -0
  149. package/package.json +83 -0
  150. package/public/favicon.ico +0 -0
  151. package/public/fonts/files/open-sans-v18-latin-700.woff +0 -0
  152. package/public/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  153. package/public/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  154. package/public/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  155. package/public/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  156. package/public/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  157. package/public/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  158. package/public/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  159. package/public/fonts/files/open-sans-v18-latin-light.woff +0 -0
  160. package/public/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  161. package/public/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  162. package/public/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  163. package/src/Core/ComponentTypes.js +426 -0
  164. package/src/Core/Core.js +11852 -0
  165. package/src/Core/CoreWorker.js +127 -0
  166. package/src/Core/Dependencies.js +8226 -0
  167. package/src/Core/Numerics.js +473 -0
  168. package/src/Core/ParameterStack.js +36 -0
  169. package/src/Core/ReadOnlyProxyHandler.js +41 -0
  170. package/src/Core/StateProxyHandler.js +88 -0
  171. package/src/Core/components/Aliases.js +67 -0
  172. package/src/Core/components/Angle.js +758 -0
  173. package/src/Core/components/AnimateFromSequence.js +922 -0
  174. package/src/Core/components/Answer.js +2087 -0
  175. package/src/Core/components/AsList.js +83 -0
  176. package/src/Core/components/AttractTo.js +245 -0
  177. package/src/Core/components/AttractToAngles.js +262 -0
  178. package/src/Core/components/AttractToConstraint.js +104 -0
  179. package/src/Core/components/AttractToGrid.js +315 -0
  180. package/src/Core/components/Award.js +906 -0
  181. package/src/Core/components/BestFitLine.js +318 -0
  182. package/src/Core/components/BezierControls.js +719 -0
  183. package/src/Core/components/BlockQuote.js +35 -0
  184. package/src/Core/components/Boolean.js +500 -0
  185. package/src/Core/components/BooleanInput.js +330 -0
  186. package/src/Core/components/BooleanList.js +396 -0
  187. package/src/Core/components/BooleanOperators.js +35 -0
  188. package/src/Core/components/BooleanOperatorsOfMath.js +148 -0
  189. package/src/Core/components/CallAction.js +261 -0
  190. package/src/Core/components/Caption.js +73 -0
  191. package/src/Core/components/Case.js +56 -0
  192. package/src/Core/components/Cell.js +439 -0
  193. package/src/Core/components/CellBlock.js +64 -0
  194. package/src/Core/components/Chart.js +795 -0
  195. package/src/Core/components/Choice.js +266 -0
  196. package/src/Core/components/ChoiceInput.js +1407 -0
  197. package/src/Core/components/Circle.js +2884 -0
  198. package/src/Core/components/CodeEditor.js +647 -0
  199. package/src/Core/components/CodeViewer.js +294 -0
  200. package/src/Core/components/CollaborateGroupSetup.js +46 -0
  201. package/src/Core/components/CollaborateGroups.js +119 -0
  202. package/src/Core/components/Collect.js +850 -0
  203. package/src/Core/components/Column.js +608 -0
  204. package/src/Core/components/ConditionalContent.js +468 -0
  205. package/src/Core/components/ConsiderAsResponses.js +49 -0
  206. package/src/Core/components/ConstrainTo.js +161 -0
  207. package/src/Core/components/ConstrainToAngles.js +244 -0
  208. package/src/Core/components/ConstrainToGraph.js +142 -0
  209. package/src/Core/components/ConstrainToGrid.js +175 -0
  210. package/src/Core/components/ConstraintUnion.js +119 -0
  211. package/src/Core/components/Constraints.js +497 -0
  212. package/src/Core/components/ContentBrowser.js +441 -0
  213. package/src/Core/components/ContentPicker.js +263 -0
  214. package/src/Core/components/ControlVectors.js +25 -0
  215. package/src/Core/components/Coords.js +63 -0
  216. package/src/Core/components/Copy.js +3412 -0
  217. package/src/Core/components/Curve.js +4130 -0
  218. package/src/Core/components/CustomAttribute.js +175 -0
  219. package/src/Core/components/DataFrame.js +357 -0
  220. package/src/Core/components/DiscreteSimulationResultList.js +342 -0
  221. package/src/Core/components/DiscreteSimulationResultPolyline.js +581 -0
  222. package/src/Core/components/Divisions.js +55 -0
  223. package/src/Core/components/Document.js +888 -0
  224. package/src/Core/components/Embed.js +65 -0
  225. package/src/Core/components/Endpoint.js +62 -0
  226. package/src/Core/components/Evaluate.js +321 -0
  227. package/src/Core/components/Extract.js +656 -0
  228. package/src/Core/components/Extrema.js +556 -0
  229. package/src/Core/components/Feedback.js +200 -0
  230. package/src/Core/components/FeedbackDefinitions.js +97 -0
  231. package/src/Core/components/Figure.js +148 -0
  232. package/src/Core/components/Footnote.js +73 -0
  233. package/src/Core/components/Function.js +5344 -0
  234. package/src/Core/components/FunctionIterates.js +306 -0
  235. package/src/Core/components/FunctionOperators.js +702 -0
  236. package/src/Core/components/Graph.js +1679 -0
  237. package/src/Core/components/Group.js +7 -0
  238. package/src/Core/components/HasSameFactoring.js +407 -0
  239. package/src/Core/components/Hint.js +241 -0
  240. package/src/Core/components/Image.js +524 -0
  241. package/src/Core/components/Indexing.js +79 -0
  242. package/src/Core/components/IntComma.js +64 -0
  243. package/src/Core/components/Integer.js +81 -0
  244. package/src/Core/components/Intersection.js +328 -0
  245. package/src/Core/components/Interval.js +29 -0
  246. package/src/Core/components/Label.js +492 -0
  247. package/src/Core/components/Latex.js +104 -0
  248. package/src/Core/components/Legend.js +329 -0
  249. package/src/Core/components/Line.js +2040 -0
  250. package/src/Core/components/LineSegment.js +882 -0
  251. package/src/Core/components/Lists.js +180 -0
  252. package/src/Core/components/Lorem.js +249 -0
  253. package/src/Core/components/MMeMen.js +377 -0
  254. package/src/Core/components/Map.js +873 -0
  255. package/src/Core/components/Markers.js +101 -0
  256. package/src/Core/components/MatchesPattern.js +339 -0
  257. package/src/Core/components/Math.js +2552 -0
  258. package/src/Core/components/MathInput.js +948 -0
  259. package/src/Core/components/MathList.js +828 -0
  260. package/src/Core/components/MathOperators.js +1286 -0
  261. package/src/Core/components/Matrix.js +497 -0
  262. package/src/Core/components/MatrixInput.js +3157 -0
  263. package/src/Core/components/MdMdnMrow.js +394 -0
  264. package/src/Core/components/Module.js +16 -0
  265. package/src/Core/components/Number.js +1031 -0
  266. package/src/Core/components/NumberList.js +550 -0
  267. package/src/Core/components/Option.js +24 -0
  268. package/src/Core/components/P.js +71 -0
  269. package/src/Core/components/Paginator.js +338 -0
  270. package/src/Core/components/Panel.js +126 -0
  271. package/src/Core/components/Parabola.js +1561 -0
  272. package/src/Core/components/ParagraphMarkup.js +59 -0
  273. package/src/Core/components/Pegboard.js +43 -0
  274. package/src/Core/components/PeriodicSet.js +291 -0
  275. package/src/Core/components/PiecewiseFunction.js +832 -0
  276. package/src/Core/components/Pluralize.js +198 -0
  277. package/src/Core/components/Point.js +1295 -0
  278. package/src/Core/components/Polygon.js +408 -0
  279. package/src/Core/components/Polyline.js +841 -0
  280. package/src/Core/components/RandomizedTextList.js +225 -0
  281. package/src/Core/components/Ray.js +1737 -0
  282. package/src/Core/components/Rectangle.js +1535 -0
  283. package/src/Core/components/Ref.js +350 -0
  284. package/src/Core/components/RegionBetweenCurveXAxis.js +124 -0
  285. package/src/Core/components/RegionHalfPlane.js +107 -0
  286. package/src/Core/components/RegularPolygon.js +2118 -0
  287. package/src/Core/components/RenderDoenetML.js +181 -0
  288. package/src/Core/components/Row.js +780 -0
  289. package/src/Core/components/SampleRandomNumbers.js +653 -0
  290. package/src/Core/components/Sectioning.js +303 -0
  291. package/src/Core/components/Select.js +947 -0
  292. package/src/Core/components/SelectFromSequence.js +1242 -0
  293. package/src/Core/components/SelectRandomNumbers.js +225 -0
  294. package/src/Core/components/Sequence.js +444 -0
  295. package/src/Core/components/Setup.js +53 -0
  296. package/src/Core/components/Shuffle.js +470 -0
  297. package/src/Core/components/SideBySide.js +2130 -0
  298. package/src/Core/components/SingleCharacterComponents.js +41 -0
  299. package/src/Core/components/Slider.js +819 -0
  300. package/src/Core/components/SolutionContainer.js +67 -0
  301. package/src/Core/components/Solutions.js +334 -0
  302. package/src/Core/components/SolveEquations.js +568 -0
  303. package/src/Core/components/Sort.js +398 -0
  304. package/src/Core/components/Sources.js +108 -0
  305. package/src/Core/components/Split.js +205 -0
  306. package/src/Core/components/Spreadsheet.js +1507 -0
  307. package/src/Core/components/StyleDefinitions.js +111 -0
  308. package/src/Core/components/SubsetOfReals.js +348 -0
  309. package/src/Core/components/SubsetOfRealsInput.js +1474 -0
  310. package/src/Core/components/Substitute.js +496 -0
  311. package/src/Core/components/SummaryStatistics.js +652 -0
  312. package/src/Core/components/Table.js +145 -0
  313. package/src/Core/components/Tabular.js +384 -0
  314. package/src/Core/components/Template.js +360 -0
  315. package/src/Core/components/Text.js +341 -0
  316. package/src/Core/components/TextInput.js +566 -0
  317. package/src/Core/components/TextList.js +442 -0
  318. package/src/Core/components/TextListFromString.js +137 -0
  319. package/src/Core/components/TextOperatorsOfMath.js +21 -0
  320. package/src/Core/components/Triangle.js +280 -0
  321. package/src/Core/components/TriggerSet.js +189 -0
  322. package/src/Core/components/TupleList.js +43 -0
  323. package/src/Core/components/UpdateValue.js +435 -0
  324. package/src/Core/components/VariantControl.js +36 -0
  325. package/src/Core/components/Vector.js +2478 -0
  326. package/src/Core/components/Verbatim.js +125 -0
  327. package/src/Core/components/Video.js +673 -0
  328. package/src/Core/components/When.js +198 -0
  329. package/src/Core/components/abstract/AngleListComponent.js +140 -0
  330. package/src/Core/components/abstract/BaseComponent.js +1496 -0
  331. package/src/Core/components/abstract/BlockComponent.js +5 -0
  332. package/src/Core/components/abstract/BooleanBaseOperator.js +88 -0
  333. package/src/Core/components/abstract/BooleanBaseOperatorOfMath.js +100 -0
  334. package/src/Core/components/abstract/BooleanBaseOperatorOneInput.js +44 -0
  335. package/src/Core/components/abstract/ComponentSize.js +789 -0
  336. package/src/Core/components/abstract/ComponentWithSelectableType.js +537 -0
  337. package/src/Core/components/abstract/CompositeComponent.js +142 -0
  338. package/src/Core/components/abstract/ConstraintComponent.js +19 -0
  339. package/src/Core/components/abstract/FunctionBaseOperator.js +680 -0
  340. package/src/Core/components/abstract/GraphicalComponent.js +56 -0
  341. package/src/Core/components/abstract/InlineComponent.js +5 -0
  342. package/src/Core/components/abstract/InlineRenderInlineChildren.js +63 -0
  343. package/src/Core/components/abstract/Input.js +192 -0
  344. package/src/Core/components/abstract/IntervalListComponent.js +218 -0
  345. package/src/Core/components/abstract/LineListComponent.js +114 -0
  346. package/src/Core/components/abstract/MathBaseOperator.js +631 -0
  347. package/src/Core/components/abstract/MathBaseOperatorOneInput.js +112 -0
  348. package/src/Core/components/abstract/PointListComponent.js +238 -0
  349. package/src/Core/components/abstract/SectioningComponent.js +1262 -0
  350. package/src/Core/components/abstract/SingleCharacterInline.js +23 -0
  351. package/src/Core/components/abstract/TextBaseOperatorOfMath.js +47 -0
  352. package/src/Core/components/abstract/TextOrInline.js +66 -0
  353. package/src/Core/components/abstract/VariableName.js +31 -0
  354. package/src/Core/components/abstract/VariableNameList.js +83 -0
  355. package/src/Core/components/abstract/VectorListComponent.js +235 -0
  356. package/src/Core/components/chemistry/Atom.js +910 -0
  357. package/src/Core/components/chemistry/ElectronConfiguration.js +36 -0
  358. package/src/Core/components/chemistry/Ion.js +684 -0
  359. package/src/Core/components/chemistry/IonicCompound.js +189 -0
  360. package/src/Core/components/chemistry/OrbitalDiagram.js +175 -0
  361. package/src/Core/components/chemistry/OrbitalDiagramInput.js +753 -0
  362. package/src/Core/components/chemistry/index.js +6 -0
  363. package/src/Core/components/commonsugar/breakstrings.js +627 -0
  364. package/src/Core/components/commonsugar/lists.js +177 -0
  365. package/src/Core/components/dynamicalSystems/CobwebPolyline.js +913 -0
  366. package/src/Core/components/dynamicalSystems/EquilibriumCurve.js +95 -0
  367. package/src/Core/components/dynamicalSystems/EquilibriumLine.js +93 -0
  368. package/src/Core/components/dynamicalSystems/EquilibriumPoint.js +93 -0
  369. package/src/Core/components/dynamicalSystems/ODESystem.js +943 -0
  370. package/src/Core/components/dynamicalSystems/index.js +5 -0
  371. package/src/Core/components/linearAlgebra/EigenDecomposition.js +294 -0
  372. package/src/Core/utils/array.js +30 -0
  373. package/src/Core/utils/booleanLogic.js +965 -0
  374. package/src/Core/utils/checkEquality.js +818 -0
  375. package/src/Core/utils/cid.js +29 -0
  376. package/src/Core/utils/componentInfoObjects.js +100 -0
  377. package/src/Core/utils/constraints.js +23 -0
  378. package/src/Core/utils/copy.js +572 -0
  379. package/src/Core/utils/deepFunctions.js +173 -0
  380. package/src/Core/utils/descendants.js +252 -0
  381. package/src/Core/utils/enumeration.js +234 -0
  382. package/src/Core/utils/feedback.js +84 -0
  383. package/src/Core/utils/function.js +1343 -0
  384. package/src/Core/utils/graphical.js +196 -0
  385. package/src/Core/utils/label.js +396 -0
  386. package/src/Core/utils/math.js +1056 -0
  387. package/src/Core/utils/naming.js +45 -0
  388. package/src/Core/utils/periodicSetEquality.js +403 -0
  389. package/src/Core/utils/randomNumbers.js +70 -0
  390. package/src/Core/utils/retrieveMedia.js +98 -0
  391. package/src/Core/utils/retrieveTextFile.js +140 -0
  392. package/src/Core/utils/returnAllPossibleVariants.js +73 -0
  393. package/src/Core/utils/rounding.js +316 -0
  394. package/src/Core/utils/sequence.js +754 -0
  395. package/src/Core/utils/serializedStateProcessing.js +4049 -0
  396. package/src/Core/utils/size.js +22 -0
  397. package/src/Core/utils/stateVariables.js +138 -0
  398. package/src/Core/utils/style.js +535 -0
  399. package/src/Core/utils/subset-of-reals.js +796 -0
  400. package/src/Core/utils/table.js +41 -0
  401. package/src/Core/utils/text.js +16 -0
  402. package/src/Core/utils/triggering.js +167 -0
  403. package/src/Core/utils/variants.js +477 -0
  404. package/src/DoenetML.css +308 -0
  405. package/src/DoenetML.jsx +201 -0
  406. package/src/Parser/doenet.grammar +90 -0
  407. package/src/Parser/doenet.js +33 -0
  408. package/src/Parser/doenet.terms.js +20 -0
  409. package/src/Parser/parser.js +266 -0
  410. package/src/Parser/tokens.js +129 -0
  411. package/src/Tools/CodeMirror.jsx +440 -0
  412. package/src/Tools/DarkmodeController.jsx +21 -0
  413. package/src/Tools/Footers/MathInputSelector.jsx +34 -0
  414. package/src/Tools/Footers/VirtualKeyboard.jsx +751 -0
  415. package/src/Tools/cypressTest/CypressTest.jsx +341 -0
  416. package/src/Tools/cypressTest/index.html +102 -0
  417. package/src/Tools/cypressTest/index.jsx +40 -0
  418. package/src/Viewer/ActivityViewer.jsx +1461 -0
  419. package/src/Viewer/PageViewer.jsx +1329 -0
  420. package/src/Viewer/renderers/alert.jsx +17 -0
  421. package/src/Viewer/renderers/angle.jsx +209 -0
  422. package/src/Viewer/renderers/answer.jsx +206 -0
  423. package/src/Viewer/renderers/asList.jsx +25 -0
  424. package/src/Viewer/renderers/blockQuote.jsx +41 -0
  425. package/src/Viewer/renderers/boolean.jsx +17 -0
  426. package/src/Viewer/renderers/booleanInput.css +105 -0
  427. package/src/Viewer/renderers/booleanInput.jsx +636 -0
  428. package/src/Viewer/renderers/button.jsx +369 -0
  429. package/src/Viewer/renderers/c.jsx +17 -0
  430. package/src/Viewer/renderers/callAction.jsx +18 -0
  431. package/src/Viewer/renderers/cell.jsx +59 -0
  432. package/src/Viewer/renderers/chart.jsx +83 -0
  433. package/src/Viewer/renderers/choiceInput.css +223 -0
  434. package/src/Viewer/renderers/choiceInput.jsx +535 -0
  435. package/src/Viewer/renderers/circle.jsx +990 -0
  436. package/src/Viewer/renderers/cobwebPolyline.jsx +442 -0
  437. package/src/Viewer/renderers/codeEditor.jsx +248 -0
  438. package/src/Viewer/renderers/codeViewer.jsx +105 -0
  439. package/src/Viewer/renderers/containerBlock.jsx +41 -0
  440. package/src/Viewer/renderers/containerInline.jsx +17 -0
  441. package/src/Viewer/renderers/contentBrowser.jsx +159 -0
  442. package/src/Viewer/renderers/contentPicker.jsx +160 -0
  443. package/src/Viewer/renderers/curve.jsx +1072 -0
  444. package/src/Viewer/renderers/ellipsis.jsx +17 -0
  445. package/src/Viewer/renderers/em.jsx +17 -0
  446. package/src/Viewer/renderers/embed.jsx +110 -0
  447. package/src/Viewer/renderers/feedback.jsx +74 -0
  448. package/src/Viewer/renderers/figure.jsx +131 -0
  449. package/src/Viewer/renderers/footnote.jsx +52 -0
  450. package/src/Viewer/renderers/graph.jsx +925 -0
  451. package/src/Viewer/renderers/hint.jsx +142 -0
  452. package/src/Viewer/renderers/image.jsx +581 -0
  453. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs +2 -0
  454. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs.map +1 -0
  455. package/src/Viewer/renderers/label.jsx +470 -0
  456. package/src/Viewer/renderers/legend.jsx +306 -0
  457. package/src/Viewer/renderers/line.jsx +511 -0
  458. package/src/Viewer/renderers/lineSegment.jsx +754 -0
  459. package/src/Viewer/renderers/list.jsx +111 -0
  460. package/src/Viewer/renderers/lq.jsx +12 -0
  461. package/src/Viewer/renderers/lsq.jsx +12 -0
  462. package/src/Viewer/renderers/math.jsx +582 -0
  463. package/src/Viewer/renderers/mathInput.css +10 -0
  464. package/src/Viewer/renderers/mathInput.jsx +425 -0
  465. package/src/Viewer/renderers/mathInputog.jsx +534 -0
  466. package/src/Viewer/renderers/mathList.jsx +39 -0
  467. package/src/Viewer/renderers/matrixInput.jsx +317 -0
  468. package/src/Viewer/renderers/mdash.jsx +12 -0
  469. package/src/Viewer/renderers/nbsp.jsx +12 -0
  470. package/src/Viewer/renderers/ndash.jsx +12 -0
  471. package/src/Viewer/renderers/number.jsx +454 -0
  472. package/src/Viewer/renderers/numberList.jsx +35 -0
  473. package/src/Viewer/renderers/orbitalDiagram.jsx +247 -0
  474. package/src/Viewer/renderers/orbitalDiagramInput.jsx +450 -0
  475. package/src/Viewer/renderers/p.jsx +38 -0
  476. package/src/Viewer/renderers/paginatorControls.jsx +41 -0
  477. package/src/Viewer/renderers/pegboard.jsx +239 -0
  478. package/src/Viewer/renderers/point.jsx +649 -0
  479. package/src/Viewer/renderers/polygon.jsx +612 -0
  480. package/src/Viewer/renderers/polyline.jsx +608 -0
  481. package/src/Viewer/renderers/pre.jsx +34 -0
  482. package/src/Viewer/renderers/q.jsx +17 -0
  483. package/src/Viewer/renderers/ray.jsx +410 -0
  484. package/src/Viewer/renderers/ref.jsx +149 -0
  485. package/src/Viewer/renderers/regionBetweenCurveXAxis.jsx +182 -0
  486. package/src/Viewer/renderers/renderDoenetML.jsx +56 -0
  487. package/src/Viewer/renderers/row.jsx +31 -0
  488. package/src/Viewer/renderers/rq.jsx +12 -0
  489. package/src/Viewer/renderers/rsq.jsx +12 -0
  490. package/src/Viewer/renderers/section.jsx +427 -0
  491. package/src/Viewer/renderers/sideBySide.jsx +80 -0
  492. package/src/Viewer/renderers/slider.jsx +800 -0
  493. package/src/Viewer/renderers/solution.jsx +134 -0
  494. package/src/Viewer/renderers/spreadsheet.jsx +83 -0
  495. package/src/Viewer/renderers/sq.jsx +17 -0
  496. package/src/Viewer/renderers/styles/global.css +14 -0
  497. package/src/Viewer/renderers/subsetOfRealsInput.jsx +392 -0
  498. package/src/Viewer/renderers/summaryStatistics.jsx +83 -0
  499. package/src/Viewer/renderers/table.jsx +78 -0
  500. package/src/Viewer/renderers/tabular.jsx +58 -0
  501. package/src/Viewer/renderers/tag.jsx +26 -0
  502. package/src/Viewer/renderers/text.jsx +439 -0
  503. package/src/Viewer/renderers/textInput.jsx +774 -0
  504. package/src/Viewer/renderers/textList.jsx +30 -0
  505. package/src/Viewer/renderers/triggerSet.jsx +52 -0
  506. package/src/Viewer/renderers/updateValue.jsx +30 -0
  507. package/src/Viewer/renderers/utils/css.js +13 -0
  508. package/src/Viewer/renderers/utils/graph.js +159 -0
  509. package/src/Viewer/renderers/utils/offGraphIndicators.js +91 -0
  510. package/src/Viewer/renderers/vector.jsx +678 -0
  511. package/src/Viewer/renderers/video.jsx +494 -0
  512. package/src/Viewer/useDoenetRenderer.jsx +128 -0
  513. package/src/main.jsx +16 -0
  514. package/src/media/fonts/files/open-sans-v18-latin-700.woff +0 -0
  515. package/src/media/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  516. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  517. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  518. package/src/media/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  519. package/src/media/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  520. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  521. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  522. package/src/media/fonts/files/open-sans-v18-latin-light.woff +0 -0
  523. package/src/media/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  524. package/src/media/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  525. package/src/media/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  526. package/src/test/testCode.doenet +26 -0
  527. package/src/test/testViewer.jsx +158 -0
  528. package/src/uiComponents/ActionButton.jsx +157 -0
  529. package/src/uiComponents/ActionButtonGroup.jsx +93 -0
  530. package/src/uiComponents/Button.jsx +160 -0
  531. package/src/uiComponents/ButtonGroup.jsx +56 -0
  532. package/src/uiComponents/ToggleButton.jsx +194 -0
  533. package/src/uiComponents/ToggleButtonGroup.jsx +77 -0
  534. package/src/utils/activityUtils.js +713 -0
  535. package/src/utils/array.js +17 -0
  536. package/src/utils/cid.js +34 -0
  537. package/src/utils/componentInfoObjects.js +89 -0
  538. package/src/utils/deepFunctions.js +165 -0
  539. package/src/utils/enumeration.js +226 -0
  540. package/src/utils/math.js +624 -0
  541. package/src/utils/naming.js +44 -0
  542. package/src/utils/retrieveTextFile.js +156 -0
  543. package/src/utils/returnAllPossibleVariants.js +81 -0
  544. package/src/utils/sequence.js +715 -0
  545. package/src/utils/serialize.js +29 -0
  546. package/src/utils/serializedStateProcessing.js +2587 -0
  547. package/src/utils/subset-of-reals.js +783 -0
  548. package/src/utils/url.js +19 -0
  549. package/vite.config.js +14 -0
@@ -0,0 +1,4704 @@
1
+ import me from "math-expressions";
2
+ import { cesc, cesc2 } from "../../../../src/utils/url";
3
+
4
+ function nInDOM(n) {
5
+ if (n < 0) {
6
+ return `−${Math.abs(n)}`;
7
+ } else {
8
+ return String(n);
9
+ }
10
+ }
11
+
12
+ async function testPolylineCopiedTwice({
13
+ vertices,
14
+ polylineName = "/pg",
15
+ graph1Name = "/g1",
16
+ graph2Name = "/g2",
17
+ graph3Name = "/g3",
18
+ pointsInDomPrefix = "/p",
19
+ }) {
20
+ for (let i in vertices) {
21
+ let ind = Number(i) + 1;
22
+ if (Number.isFinite(vertices[i][0])) {
23
+ cy.get(`#${cesc2(pointsInDomPrefix + ind)} .mjx-mrow`).should(
24
+ "contain.text",
25
+ `(${nInDOM(
26
+ Math.round(vertices[i][0] * 100000000) / 100000000,
27
+ ).substring(0, 6)}`,
28
+ );
29
+ }
30
+ if (Number.isFinite(vertices[i][1])) {
31
+ cy.get(`#${cesc2(pointsInDomPrefix + ind)} .mjx-mrow`).should(
32
+ "contain.text",
33
+ `,${nInDOM(
34
+ Math.round(vertices[i][1] * 100000000) / 100000000,
35
+ ).substring(0, 6)}`,
36
+ );
37
+ }
38
+ }
39
+ cy.get(`#${cesc2(pointsInDomPrefix + (vertices.length + 1))}`).should(
40
+ "not.exist",
41
+ );
42
+
43
+ cy.window().then(async (win) => {
44
+ let stateVariables = await win.returnAllStateVariables1();
45
+ expect(
46
+ stateVariables[graph1Name + polylineName].stateValues.numVertices,
47
+ ).eqls(vertices.length);
48
+ expect(
49
+ stateVariables[graph2Name + polylineName].stateValues.numVertices,
50
+ ).eqls(vertices.length);
51
+ expect(
52
+ stateVariables[graph3Name + polylineName].stateValues.numVertices,
53
+ ).eqls(vertices.length);
54
+
55
+ for (let i in vertices) {
56
+ if (Number.isFinite(vertices[i][0])) {
57
+ expect(
58
+ me
59
+ .fromAst(
60
+ stateVariables[graph1Name + polylineName].stateValues.vertices[
61
+ i
62
+ ][0],
63
+ )
64
+ .evaluate_to_constant(),
65
+ ).closeTo(vertices[i][0], 1e-12);
66
+ expect(
67
+ me
68
+ .fromAst(
69
+ stateVariables[graph2Name + polylineName].stateValues.vertices[
70
+ i
71
+ ][0],
72
+ )
73
+ .evaluate_to_constant(),
74
+ ).closeTo(vertices[i][0], 1e-12);
75
+ expect(
76
+ me
77
+ .fromAst(
78
+ stateVariables[graph3Name + polylineName].stateValues.vertices[
79
+ i
80
+ ][0],
81
+ )
82
+ .evaluate_to_constant(),
83
+ ).closeTo(vertices[i][0], 1e-12);
84
+ } else {
85
+ expect(
86
+ stateVariables[graph1Name + polylineName].stateValues.vertices[i][0],
87
+ ).eq(vertices[i][0]);
88
+ expect(
89
+ stateVariables[graph2Name + polylineName].stateValues.vertices[i][0],
90
+ ).eq(vertices[i][0]);
91
+ expect(
92
+ stateVariables[graph3Name + polylineName].stateValues.vertices[i][0],
93
+ ).eq(vertices[i][0]);
94
+ }
95
+ if (Number.isFinite(vertices[i][1])) {
96
+ expect(
97
+ me
98
+ .fromAst(
99
+ stateVariables[graph1Name + polylineName].stateValues.vertices[
100
+ i
101
+ ][1],
102
+ )
103
+ .evaluate_to_constant(),
104
+ ).closeTo(vertices[i][1], 1e-12);
105
+ expect(
106
+ me
107
+ .fromAst(
108
+ stateVariables[graph2Name + polylineName].stateValues.vertices[
109
+ i
110
+ ][1],
111
+ )
112
+ .evaluate_to_constant(),
113
+ ).closeTo(vertices[i][1], 1e-12);
114
+ expect(
115
+ me
116
+ .fromAst(
117
+ stateVariables[graph3Name + polylineName].stateValues.vertices[
118
+ i
119
+ ][1],
120
+ )
121
+ .evaluate_to_constant(),
122
+ ).closeTo(vertices[i][1], 1e-12);
123
+ } else {
124
+ expect(
125
+ stateVariables[graph1Name + polylineName].stateValues.vertices[i][1],
126
+ ).eq(vertices[i][1]);
127
+ expect(
128
+ stateVariables[graph2Name + polylineName].stateValues.vertices[i][1],
129
+ ).eq(vertices[i][1]);
130
+ expect(
131
+ stateVariables[graph3Name + polylineName].stateValues.vertices[i][1],
132
+ ).eq(vertices[i][1]);
133
+ }
134
+ }
135
+ });
136
+ }
137
+
138
+ describe("Polyline Tag Tests", function () {
139
+ beforeEach(() => {
140
+ cy.clearIndexedDB();
141
+ cy.visit("/src/Tools/cypressTest/");
142
+ });
143
+
144
+ it("Polyline vertices and copied points", () => {
145
+ cy.window().then(async (win) => {
146
+ win.postMessage(
147
+ {
148
+ doenetML: `
149
+ <text>a</text>
150
+ <graph name="g1" newNamespace>
151
+ <point>(3,5)</point>
152
+ <point>(-4,-1)</point>
153
+ <point>(5,2)</point>
154
+ <point>(-3,4)</point>
155
+ <polyline vertices="$_point1 $_point2 $_point3 $_point4" name="pg" />
156
+ </graph>
157
+ <graph name="g2" newNamespace>
158
+ <copy target="../g1/pg" assignNames="pg" />
159
+ </graph>
160
+ <copy target="g2" assignNames="g3" />
161
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
162
+ `,
163
+ },
164
+ "*",
165
+ );
166
+ });
167
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
168
+
169
+ let vertices = [
170
+ [3, 5],
171
+ [-4, -1],
172
+ [5, 2],
173
+ [-3, 4],
174
+ ];
175
+
176
+ testPolylineCopiedTwice({ vertices });
177
+
178
+ cy.log("move individual vertex");
179
+ cy.window().then(async (win) => {
180
+ vertices[1] = [4, 7];
181
+
182
+ win.callAction1({
183
+ actionName: "movePolyline",
184
+ componentName: "/g1/pg",
185
+ args: {
186
+ pointCoords: { 1: vertices[1] },
187
+ },
188
+ });
189
+
190
+ testPolylineCopiedTwice({ vertices });
191
+ });
192
+
193
+ cy.log("move copied polyline up and to the right");
194
+ cy.window().then(async (win) => {
195
+ let moveX = 3;
196
+ let moveY = 2;
197
+
198
+ for (let i = 0; i < vertices.length; i++) {
199
+ vertices[i][0] = vertices[i][0] + moveX;
200
+ vertices[i][1] = vertices[i][1] + moveY;
201
+ }
202
+
203
+ win.callAction1({
204
+ actionName: "movePolyline",
205
+ componentName: "/g2/pg",
206
+ args: {
207
+ pointCoords: vertices,
208
+ },
209
+ });
210
+
211
+ testPolylineCopiedTwice({ vertices });
212
+ });
213
+
214
+ cy.log("move double copied individual vertex");
215
+ cy.window().then(async (win) => {
216
+ vertices[2] = [-9, -8];
217
+
218
+ win.callAction1({
219
+ actionName: "movePolyline",
220
+ componentName: "/g3/pg",
221
+ args: {
222
+ pointCoords: { 2: vertices[2] },
223
+ },
224
+ });
225
+
226
+ testPolylineCopiedTwice({ vertices });
227
+ });
228
+ });
229
+
230
+ it("Polyline string points in vertices", () => {
231
+ cy.window().then(async (win) => {
232
+ win.postMessage(
233
+ {
234
+ doenetML: `
235
+ <text>a</text>
236
+ <math>-1</math>
237
+ <graph name="g1" newNamespace>
238
+ <polyline vertices="(3,5) (-4,$(../_math1)) (5,2) (-3,4)" name="pg" />
239
+ </graph>
240
+ <graph name="g2" newNamespace>
241
+ <copy target="../g1/pg" assignNames="pg" />
242
+ </graph>
243
+ <copy target="g2" assignNames="g3" />
244
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
245
+ `,
246
+ },
247
+ "*",
248
+ );
249
+ });
250
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
251
+
252
+ let vertices = [
253
+ [3, 5],
254
+ [-4, -1],
255
+ [5, 2],
256
+ [-3, 4],
257
+ ];
258
+
259
+ testPolylineCopiedTwice({ vertices });
260
+
261
+ cy.log("move individual vertex");
262
+ cy.window().then(async (win) => {
263
+ vertices[1] = [4, 7];
264
+
265
+ win.callAction1({
266
+ actionName: "movePolyline",
267
+ componentName: "/g1/pg",
268
+ args: {
269
+ pointCoords: { 1: vertices[1] },
270
+ },
271
+ });
272
+
273
+ testPolylineCopiedTwice({ vertices });
274
+ });
275
+
276
+ cy.log("move copied polyline up and to the right");
277
+ cy.window().then(async (win) => {
278
+ let moveX = 3;
279
+ let moveY = 2;
280
+
281
+ for (let i = 0; i < vertices.length; i++) {
282
+ vertices[i][0] = vertices[i][0] + moveX;
283
+ vertices[i][1] = vertices[i][1] + moveY;
284
+ }
285
+
286
+ win.callAction1({
287
+ actionName: "movePolyline",
288
+ componentName: "/g2/pg",
289
+ args: {
290
+ pointCoords: vertices,
291
+ },
292
+ });
293
+
294
+ testPolylineCopiedTwice({ vertices });
295
+ });
296
+
297
+ cy.log("move double copied individual vertex");
298
+ cy.window().then(async (win) => {
299
+ vertices[2] = [-9, -8];
300
+
301
+ win.callAction1({
302
+ actionName: "movePolyline",
303
+ componentName: "/g3/pg",
304
+ args: {
305
+ pointCoords: { 2: vertices[2] },
306
+ },
307
+ });
308
+
309
+ testPolylineCopiedTwice({ vertices });
310
+ });
311
+ });
312
+
313
+ it("dynamic polyline with vertices from copied map, initially zero, copied", () => {
314
+ cy.window().then(async (win) => {
315
+ win.postMessage(
316
+ {
317
+ doenetML: `
318
+ <text>a</text>
319
+
320
+ <mathinput name="length" prefill="0" />
321
+ <graph name="g1" newNamespace>
322
+ <map>
323
+ <template><point>($x, 5sin($x))</point></template>
324
+ <sources alias="x"><sequence from="0" length="$(../length)" /></sources>
325
+ </map>
326
+ <polyline vertices="$_map1" name="pg" />
327
+ </graph>
328
+ <graph name="g2" newNamespace>
329
+ <copy target="../g1/pg" assignNames="pg" />
330
+ </graph>
331
+ <copy target="g2" assignNames="g3" />
332
+ <map assignNames="(p1) (p2) (p3) (p4) (p5) (p6) (p7) (p8) (p9) (p10)" >
333
+ <template><round numDecimals="8">$v</round></template>
334
+ <sources alias="v"><copy target="g1/pg" prop="vertices" /></sources>
335
+ </map>
336
+ `,
337
+ },
338
+ "*",
339
+ );
340
+ });
341
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
342
+
343
+ let vertices = [];
344
+ testPolylineCopiedTwice({ vertices });
345
+
346
+ cy.get(cesc("#\\/length") + " textarea")
347
+ .type("{end}{backspace}1{enter}", { force: true })
348
+ .then(() => {
349
+ vertices[0] = [0, 5 * Math.sin(0)];
350
+ testPolylineCopiedTwice({ vertices });
351
+ });
352
+
353
+ cy.get(cesc("#\\/length") + " textarea")
354
+ .type("{end}{backspace}2{enter}", { force: true })
355
+ .then(() => {
356
+ vertices[1] = [1, 5 * Math.sin(1)];
357
+ testPolylineCopiedTwice({ vertices });
358
+ });
359
+
360
+ cy.get(cesc("#\\/length") + " textarea")
361
+ .type("{end}{backspace}3{enter}", { force: true })
362
+ .then(() => {
363
+ vertices[2] = [2, 5 * Math.sin(2)];
364
+ testPolylineCopiedTwice({ vertices });
365
+ });
366
+
367
+ cy.get(cesc("#\\/length") + " textarea")
368
+ .type("{end}{backspace}2{enter}", { force: true })
369
+ .then(() => {
370
+ vertices.splice(2, 1);
371
+ testPolylineCopiedTwice({ vertices });
372
+ });
373
+
374
+ cy.get(cesc("#\\/length") + " textarea")
375
+ .type("{end}{backspace}0{enter}", { force: true })
376
+ .then(() => {
377
+ vertices = [];
378
+ testPolylineCopiedTwice({ vertices });
379
+ });
380
+
381
+ cy.get(cesc("#\\/length") + " textarea")
382
+ .type("{end}{backspace}5{enter}", { force: true })
383
+ .then(() => {
384
+ for (let i = 0; i < 5; i++) {
385
+ vertices.push([i, 5 * Math.sin(i)]);
386
+ }
387
+ testPolylineCopiedTwice({ vertices });
388
+ });
389
+
390
+ cy.log("start over and begin with big increment");
391
+ cy.window().then(async (win) => {
392
+ win.postMessage(
393
+ {
394
+ doenetML: `
395
+ <text>b</text>
396
+
397
+ <mathinput name="length" prefill="0" />
398
+ <graph name="g1" newNamespace>
399
+ <map>
400
+ <template><point>($x, 5sin($x))</point></template>
401
+ <sources alias="x"><sequence from="0" length="$(../length)" /></sources>
402
+ </map>
403
+ <polyline vertices="$_map1" name="pg" />
404
+ </graph>
405
+ <graph name="g2" newNamespace>
406
+ <copy target="../g1/pg" assignNames="pg" />
407
+ </graph>
408
+ <copy target="g2" assignNames="g3" />
409
+ <map assignNames="(p1) (p2) (p3) (p4) (p5) (p6) (p7) (p8) (p9) (p10)" >
410
+ <template><round numDecimals="8">$v</round></template>
411
+ <sources alias="v"><copy target="g1/pg" prop="vertices" /></sources>
412
+ </map>
413
+ `,
414
+ },
415
+ "*",
416
+ );
417
+ });
418
+ cy.get(cesc("#\\/_text1")).should("have.text", "b"); //wait for page to load
419
+
420
+ cy.window().then(async (win) => {
421
+ vertices = [];
422
+ testPolylineCopiedTwice({ vertices });
423
+ });
424
+
425
+ cy.get(cesc("#\\/length") + " textarea")
426
+ .type("{end}{backspace}10{enter}", { force: true })
427
+ .then(() => {
428
+ for (let i = 0; i < 10; i++) {
429
+ vertices.push([i, 5 * Math.sin(i)]);
430
+ }
431
+ testPolylineCopiedTwice({ vertices });
432
+ });
433
+
434
+ cy.get(cesc("#\\/length") + " textarea")
435
+ .type("{end}{backspace}{backspace}1{enter}", { force: true })
436
+ .then(() => {
437
+ vertices = [[0, 5 * Math.sin(0)]];
438
+ testPolylineCopiedTwice({ vertices });
439
+ });
440
+ });
441
+
442
+ it("polyline with initially undefined point", () => {
443
+ cy.window().then(async (win) => {
444
+ win.postMessage(
445
+ {
446
+ doenetML: `
447
+ <text>a</text>
448
+ <mathinput/>
449
+
450
+ <graph name="g1" newNamespace>
451
+ <polyline vertices="(1,2) (-1,5) ($(../_mathinput1),7) (3,-5) (-4,-3)" name="pg" />
452
+ </graph>
453
+ <graph name="g2" newNamespace>
454
+ <copy target="../g1/pg" assignNames="pg" />
455
+ </graph>
456
+ <copy target="g2" assignNames="g3" />
457
+ <map assignNames="(p1) (p2) (p3) (p4) (p5)" >
458
+ <template><round numDecimals="8">$v</round></template>
459
+ <sources alias="v"><copy target="g1/pg" prop="vertices" /></sources>
460
+ </map>
461
+ `,
462
+ },
463
+ "*",
464
+ );
465
+ });
466
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
467
+
468
+ let vertices = [
469
+ [1, 2],
470
+ [-1, 5],
471
+ ["\uff3f", 7],
472
+ [3, -5],
473
+ [-4, -3],
474
+ ];
475
+ testPolylineCopiedTwice({ vertices });
476
+
477
+ cy.get(cesc("#\\/_mathinput1") + " textarea")
478
+ .type("{end}{backspace}-2{enter}", { force: true })
479
+ .then(() => {
480
+ vertices[2][0] = -2;
481
+ testPolylineCopiedTwice({ vertices });
482
+ });
483
+ });
484
+
485
+ it(`can't move polyline based on map`, () => {
486
+ cy.window().then(async (win) => {
487
+ win.postMessage(
488
+ {
489
+ doenetML: `
490
+ <text>a</text>
491
+
492
+ <graph name="g1" newNamespace>
493
+ <map hide assignNames="(mp1) (mp2) (mp3) (mp4) (mp5) (mp6) (mp7) (mp8) (mp9) (mp10) (mp11)" >
494
+ <template><point>($x, 5sin($x))</point></template>
495
+ <sources alias="x"><sequence from="-5" to="5"/></sources>
496
+ </map>
497
+ <polyline vertices="$_map1" name="pg" />
498
+ </graph>
499
+ <graph name="g2" newNamespace>
500
+ <copy target="../g1/pg" assignNames="pg" />
501
+ </graph>
502
+ <copy target="g2" assignNames="g3" />
503
+ <map assignNames="(p1) (p2) (p3) (p4) (p5) (p6) (p7) (p8) (p9) (p10) (p11)" >
504
+ <template><round numDecimals="8">$v</round></template>
505
+ <sources alias="v"><copy target="g1/pg" prop="vertices" /></sources>
506
+ </map>
507
+ <textinput name="ti" />
508
+ <copy target="ti" prop="value" assignNames="t" />
509
+ `,
510
+ },
511
+ "*",
512
+ );
513
+ });
514
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
515
+
516
+ let vertices = [];
517
+ for (let i = -5; i <= 5; i++) {
518
+ vertices.push([i, 5 * Math.sin(i)]);
519
+ }
520
+ testPolylineCopiedTwice({ vertices });
521
+
522
+ cy.log("can't move points");
523
+ cy.window().then(async (win) => {
524
+ win.callAction1({
525
+ actionName: "movePoint",
526
+ componentName: "/g1/mp1",
527
+ args: { x: 9, y: -8 },
528
+ });
529
+ win.callAction1({
530
+ actionName: "movePoint",
531
+ componentName: "/g1/mp9",
532
+ args: { x: -8, y: 4 },
533
+ });
534
+
535
+ // since core could be delayed and we can't tell that no change occurred,
536
+ // change value of textinput and wait for the change to be processed by core
537
+ cy.get(cesc("#\\/ti_input")).type("wait{enter}");
538
+ cy.get(cesc("#\\/t"))
539
+ .should("have.text", "wait")
540
+ .then(() => {
541
+ testPolylineCopiedTwice({ vertices });
542
+ });
543
+ });
544
+
545
+ cy.log("can't move polyline1");
546
+ cy.window().then(async (win) => {
547
+ let moveX = 3;
548
+ let moveY = 2;
549
+
550
+ let vertices2 = vertices.map((v) => [v[0] + moveX, v[1] + moveY]);
551
+
552
+ win.callAction1({
553
+ actionName: "movePolyline",
554
+ componentName: "/g1/pg",
555
+ args: {
556
+ pointCoords: vertices2,
557
+ },
558
+ });
559
+
560
+ cy.get(cesc("#\\/ti_input")).clear().type("more{enter}");
561
+ cy.get(cesc("#\\/t"))
562
+ .should("have.text", "more")
563
+ .then(() => {
564
+ testPolylineCopiedTwice({ vertices });
565
+ });
566
+ });
567
+
568
+ cy.log("can't move polyline2");
569
+ cy.window().then(async (win) => {
570
+ let moveX = -5;
571
+ let moveY = 6;
572
+
573
+ let vertices2 = vertices.map((v) => [v[0] + moveX, v[1] + moveY]);
574
+
575
+ win.callAction1({
576
+ actionName: "movePolyline",
577
+ componentName: "/g2/pg",
578
+ args: {
579
+ pointCoords: vertices2,
580
+ },
581
+ });
582
+
583
+ cy.get(cesc("#\\/ti_input")).clear().type("less{enter}");
584
+ cy.get(cesc("#\\/t"))
585
+ .should("have.text", "less")
586
+ .then(() => {
587
+ testPolylineCopiedTwice({ vertices });
588
+ });
589
+ });
590
+
591
+ cy.log("can't move polyline3");
592
+ cy.window().then(async (win) => {
593
+ let moveX = 7;
594
+ let moveY = -4;
595
+
596
+ let vertices2 = vertices.map((v) => [v[0] + moveX, v[1] + moveY]);
597
+
598
+ win.callAction1({
599
+ actionName: "movePolyline",
600
+ componentName: "/g3/pg",
601
+ args: {
602
+ pointCoords: vertices2,
603
+ },
604
+ });
605
+
606
+ cy.get(cesc("#\\/ti_input")).clear().type("last{enter}");
607
+ cy.get(cesc("#\\/t"))
608
+ .should("have.text", "last")
609
+ .then(() => {
610
+ testPolylineCopiedTwice({ vertices });
611
+ });
612
+ });
613
+ });
614
+
615
+ it(`create moveable polyline based on map`, () => {
616
+ cy.window().then(async (win) => {
617
+ win.postMessage(
618
+ {
619
+ doenetML: `
620
+ <text>a</text>
621
+
622
+ <graph name="g1" newNamespace>
623
+ <map hide assignNames="(mp1) (mp2) (mp3) (mp4) (mp5) (mp6) (mp7) (mp8) (mp9) (mp10) (mp11)" >
624
+ <template><point>($x + <math>0</math>, 5sin($x) + <math>0</math>)</point></template>
625
+ <sources alias="x"><sequence from="-5" to="5"/></sources>
626
+ </map>
627
+ <polyline vertices="$_map1" name="pg" />
628
+ </graph>
629
+ <graph name="g2" newNamespace>
630
+ <copy target="../g1/pg" assignNames="pg" />
631
+ </graph>
632
+ <copy target="g2" assignNames="g3" />
633
+ <map assignNames="(p1) (p2) (p3) (p4) (p5) (p6) (p7) (p8) (p9) (p10) (p11)" >
634
+ <template><round numDecimals="8">$v</round></template>
635
+ <sources alias="v"><copy target="g1/pg" prop="vertices" /></sources>
636
+ </map>
637
+ <textinput name="ti" />
638
+ <copy target="ti" prop="value" assignNames="t" />
639
+ `,
640
+ },
641
+ "*",
642
+ );
643
+ });
644
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
645
+
646
+ let vertices = [];
647
+ for (let i = -5; i <= 5; i++) {
648
+ vertices.push([i, 5 * Math.sin(i)]);
649
+ }
650
+ testPolylineCopiedTwice({ vertices });
651
+
652
+ cy.log("can move points");
653
+
654
+ cy.window().then(async (win) => {
655
+ vertices[0] = [9, -8];
656
+ vertices[8] = [-8, 4];
657
+
658
+ win.callAction1({
659
+ actionName: "movePoint",
660
+ componentName: "/g1/mp1",
661
+ args: { x: vertices[0][0], y: vertices[0][1] },
662
+ });
663
+ win.callAction1({
664
+ actionName: "movePoint",
665
+ componentName: "/g1/mp9",
666
+ args: { x: vertices[8][0], y: vertices[8][1] },
667
+ });
668
+
669
+ testPolylineCopiedTwice({ vertices });
670
+ });
671
+
672
+ cy.log("can move polyline1");
673
+ cy.window().then(async (win) => {
674
+ let moveX = 3;
675
+ let moveY = 2;
676
+
677
+ for (let i = 0; i < vertices.length; i++) {
678
+ vertices[i][0] += moveX;
679
+ vertices[i][1] += moveY;
680
+ }
681
+
682
+ win.callAction1({
683
+ actionName: "movePolyline",
684
+ componentName: "/g1/pg",
685
+ args: {
686
+ pointCoords: vertices,
687
+ },
688
+ });
689
+
690
+ testPolylineCopiedTwice({ vertices });
691
+ });
692
+
693
+ cy.log("can move polyline2");
694
+ cy.window().then(async (win) => {
695
+ let moveX = -5;
696
+ let moveY = 6;
697
+
698
+ for (let i = 0; i < vertices.length; i++) {
699
+ vertices[i][0] += moveX;
700
+ vertices[i][1] += moveY;
701
+ }
702
+
703
+ win.callAction1({
704
+ actionName: "movePolyline",
705
+ componentName: "/g2/pg",
706
+ args: {
707
+ pointCoords: vertices,
708
+ },
709
+ });
710
+
711
+ testPolylineCopiedTwice({ vertices });
712
+ });
713
+
714
+ cy.log("can move polyline3");
715
+ cy.window().then(async (win) => {
716
+ let moveX = 7;
717
+ let moveY = -4;
718
+
719
+ for (let i = 0; i < vertices.length; i++) {
720
+ vertices[i][0] += moveX;
721
+ vertices[i][1] += moveY;
722
+ }
723
+
724
+ win.callAction1({
725
+ actionName: "movePolyline",
726
+ componentName: "/g2/pg",
727
+ args: {
728
+ pointCoords: vertices,
729
+ },
730
+ });
731
+
732
+ testPolylineCopiedTwice({ vertices });
733
+ });
734
+ });
735
+
736
+ it("copy vertices of polyline", () => {
737
+ cy.window().then(async (win) => {
738
+ win.postMessage(
739
+ {
740
+ doenetML: `
741
+ <text>a</text>
742
+ <graph>
743
+ <polyline vertices="(-3,-1) (1,2) (3,4) (6,-2)" />
744
+ </graph>
745
+ <graph>
746
+ <copy assignNames="v1" prop="vertex1" target="_polyline1" />
747
+ <copy assignNames="v2" prop="vertex2" target="_polyline1" />
748
+ <copy assignNames="v3" prop="vertex3" target="_polyline1" />
749
+ <copy assignNames="v4" prop="vertex4" target="_polyline1" />
750
+ </graph>
751
+ <graph>
752
+ <copy assignNames="v1a v2a v3a v4a" prop="vertices" target="_polyline1" />
753
+ </graph>
754
+ <copy assignNames="v4b" prop="vertex4" target="_polyline1" />
755
+ `,
756
+ },
757
+ "*",
758
+ );
759
+ });
760
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
761
+
762
+ cy.window().then(async (win) => {
763
+ let stateVariables = await win.returnAllStateVariables1();
764
+ let ps = [
765
+ [-3, -1],
766
+ [1, 2],
767
+ [3, 4],
768
+ [6, -2],
769
+ ];
770
+
771
+ for (let i = 0; i < 4; i++) {
772
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[0]).eq(ps[i][0]);
773
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[0]).eq(ps[i][0]);
774
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[1]).eq(ps[i][1]);
775
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[1]).eq(ps[i][1]);
776
+ }
777
+
778
+ cy.get(cesc("#\\/v4b") + " .mjx-mrow").should(
779
+ "contain.text",
780
+ `(${nInDOM(ps[3][0])},${nInDOM(ps[3][1])})`,
781
+ );
782
+ });
783
+
784
+ cy.log("move individually copied vertices");
785
+ cy.window().then(async (win) => {
786
+ let ps = [
787
+ [-5, 3],
788
+ [-2, 7],
789
+ [0, -8],
790
+ [9, -6],
791
+ ];
792
+
793
+ for (let i = 0; i < 4; i++) {
794
+ win.callAction1({
795
+ actionName: "movePoint",
796
+ componentName: `/v${i + 1}`,
797
+ args: { x: ps[i][0], y: ps[i][1] },
798
+ });
799
+ }
800
+
801
+ cy.get(cesc("#\\/v4b") + " .mjx-mrow").should(
802
+ "contain.text",
803
+ `(${nInDOM(ps[3][0])},${nInDOM(ps[3][1])})`,
804
+ );
805
+
806
+ cy.window().then(async (win) => {
807
+ let stateVariables = await win.returnAllStateVariables1();
808
+ for (let i = 0; i < 4; i++) {
809
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[0]).eq(ps[i][0]);
810
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[0]).eq(ps[i][0]);
811
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[1]).eq(ps[i][1]);
812
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[1]).eq(ps[i][1]);
813
+ }
814
+ });
815
+ });
816
+
817
+ cy.log("move array-copied vertices");
818
+ cy.window().then(async (win) => {
819
+ let ps = [
820
+ [-7, -1],
821
+ [-3, 5],
822
+ [2, 4],
823
+ [6, 0],
824
+ ];
825
+
826
+ for (let i = 0; i < 4; i++) {
827
+ win.callAction1({
828
+ actionName: "movePoint",
829
+ componentName: `/v${i + 1}a`,
830
+ args: { x: ps[i][0], y: ps[i][1] },
831
+ });
832
+ }
833
+
834
+ cy.get(cesc("#\\/v4b") + " .mjx-mrow").should(
835
+ "contain.text",
836
+ `(${nInDOM(ps[3][0])},${nInDOM(ps[3][1])})`,
837
+ );
838
+
839
+ cy.window().then(async (win) => {
840
+ let stateVariables = await win.returnAllStateVariables1();
841
+ for (let i = 0; i < 4; i++) {
842
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[0]).eq(ps[i][0]);
843
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[0]).eq(ps[i][0]);
844
+ expect(stateVariables[`/v${i + 1}`].stateValues.xs[1]).eq(ps[i][1]);
845
+ expect(stateVariables[`/v${i + 1}a`].stateValues.xs[1]).eq(ps[i][1]);
846
+ }
847
+ });
848
+ });
849
+ });
850
+
851
+ it("new polyline from copied vertices of polyline", () => {
852
+ cy.window().then(async (win) => {
853
+ win.postMessage(
854
+ {
855
+ doenetML: `
856
+ <text>a</text>
857
+ <graph name="g1" newNamespace>
858
+ <polyline vertices="(-9,6) (-3,7) (4,0) (8,5)" name="pg" />
859
+ </graph>
860
+ <graph name="g2" newNamespace>
861
+ <polyline vertices="$(../g1/pg.vertices)" name="pg" />
862
+ </graph>
863
+ <copy target="g2" assignNames="g3" />
864
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
865
+ `,
866
+ },
867
+ "*",
868
+ );
869
+ });
870
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
871
+
872
+ let vertices = [
873
+ [-9, 6],
874
+ [-3, 7],
875
+ [4, 0],
876
+ [8, 5],
877
+ ];
878
+
879
+ testPolylineCopiedTwice({ vertices });
880
+
881
+ cy.log("move first polyline up and to the right");
882
+ cy.window().then(async (win) => {
883
+ let moveX = 4;
884
+ let moveY = 2;
885
+
886
+ for (let i = 0; i < vertices.length; i++) {
887
+ vertices[i][0] += moveX;
888
+ vertices[i][1] += moveY;
889
+ }
890
+
891
+ win.callAction1({
892
+ actionName: "movePolyline",
893
+ componentName: "/g1/pg",
894
+ args: {
895
+ pointCoords: vertices,
896
+ },
897
+ });
898
+
899
+ testPolylineCopiedTwice({ vertices });
900
+ });
901
+
902
+ cy.log("move copied polyline up and to the left");
903
+ cy.window().then(async (win) => {
904
+ let moveX = -7;
905
+ let moveY = 3;
906
+
907
+ for (let i = 0; i < vertices.length; i++) {
908
+ vertices[i][0] += moveX;
909
+ vertices[i][1] += moveY;
910
+ }
911
+
912
+ win.callAction1({
913
+ actionName: "movePolyline",
914
+ componentName: "/g2/pg",
915
+ args: {
916
+ pointCoords: vertices,
917
+ },
918
+ });
919
+
920
+ testPolylineCopiedTwice({ vertices });
921
+ });
922
+
923
+ cy.log("move dobule copied polyline down and to the left");
924
+ cy.window().then(async (win) => {
925
+ let moveX = -1;
926
+ let moveY = -4;
927
+
928
+ for (let i = 0; i < vertices.length; i++) {
929
+ vertices[i][0] += moveX;
930
+ vertices[i][1] += moveY;
931
+ }
932
+
933
+ win.callAction1({
934
+ actionName: "movePolyline",
935
+ componentName: "/g3/pg",
936
+ args: {
937
+ pointCoords: vertices,
938
+ },
939
+ });
940
+
941
+ testPolylineCopiedTwice({ vertices });
942
+ });
943
+ });
944
+
945
+ it("new polyline as translated version of polyline", () => {
946
+ cy.window().then(async (win) => {
947
+ win.postMessage(
948
+ {
949
+ doenetML: `
950
+ <text>a</text>
951
+ <mathinput prefill="5" name="transx" />
952
+ <mathinput prefill="7" name="transy" />
953
+ <graph>
954
+ <polyline vertices=" (0,0) (3,-4) (1,-6) (-5,-6) " />
955
+ <map hide>
956
+ <template newNamespace>
957
+ <point>(<extract prop="x"><copy target="x" fixed="false"/></extract>+
958
+ <copy prop="value" modifyIndirectly="false" target="../transx" />,
959
+ <extract prop="y"><copy target="x" fixed="false" /></extract>+
960
+ <copy prop="value" modifyIndirectly="false" target="../transy" />)
961
+ </point>
962
+ </template>
963
+ <sources alias="x">
964
+ <copy prop="vertices" name="vs" target="_polyline1" />
965
+ </sources>
966
+ </map>
967
+ <polyline vertices="$_map1" />
968
+ </graph>
969
+ <copy target="_polyline2" prop="vertices" assignNames="p1 p2 p3 p4" />
970
+
971
+ `,
972
+ },
973
+ "*",
974
+ );
975
+ });
976
+
977
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
978
+
979
+ async function testPolylines({ vertices, transX, transY }) {
980
+ let vertices2 = vertices.map((v) => [v[0] + transX, v[1] + transY]);
981
+
982
+ for (let i in vertices) {
983
+ let ind = Number(i) + 1;
984
+ cy.get(`#${cesc2("/p" + ind)} .mjx-mrow`).should(
985
+ "contain.text",
986
+ `(${nInDOM(
987
+ Math.round(vertices2[i][0] * 100000000) / 100000000,
988
+ ).substring(0, 6)}`,
989
+ );
990
+ cy.get(`#${cesc2("/p" + ind)} .mjx-mrow`).should(
991
+ "contain.text",
992
+ `,${nInDOM(
993
+ Math.round(vertices2[i][1] * 100000000) / 100000000,
994
+ ).substring(0, 6)}`,
995
+ );
996
+ }
997
+ cy.get(`#${cesc2("/p" + (vertices.length + 1))}`).should("not.exist");
998
+
999
+ cy.window().then(async (win) => {
1000
+ let stateVariables = await win.returnAllStateVariables1();
1001
+ expect(stateVariables["/_polyline1"].stateValues.numVertices).eqls(
1002
+ vertices.length,
1003
+ );
1004
+ expect(stateVariables["/_polyline2"].stateValues.numVertices).eqls(
1005
+ vertices.length,
1006
+ );
1007
+
1008
+ for (let i in vertices) {
1009
+ if (Number.isFinite(vertices[i][0])) {
1010
+ expect(
1011
+ me
1012
+ .fromAst(
1013
+ stateVariables["/_polyline1"].stateValues.vertices[i][0],
1014
+ )
1015
+ .evaluate_to_constant(),
1016
+ ).closeTo(vertices[i][0], 1e-12);
1017
+ expect(
1018
+ me
1019
+ .fromAst(
1020
+ stateVariables["/_polyline2"].stateValues.vertices[i][0],
1021
+ )
1022
+ .evaluate_to_constant(),
1023
+ ).closeTo(vertices2[i][0], 1e-12);
1024
+ } else {
1025
+ expect(stateVariables["/_polyline1"].stateValues.vertices[i][0]).eq(
1026
+ vertices[i][0],
1027
+ );
1028
+ expect(stateVariables["/_polyline2"].stateValues.vertices[i][0]).eq(
1029
+ vertices2[i][0],
1030
+ );
1031
+ }
1032
+ if (Number.isFinite(vertices[i][1])) {
1033
+ expect(
1034
+ me
1035
+ .fromAst(
1036
+ stateVariables["/_polyline1"].stateValues.vertices[i][1],
1037
+ )
1038
+ .evaluate_to_constant(),
1039
+ ).closeTo(vertices[i][1], 1e-12);
1040
+ expect(
1041
+ me
1042
+ .fromAst(
1043
+ stateVariables["/_polyline2"].stateValues.vertices[i][1],
1044
+ )
1045
+ .evaluate_to_constant(),
1046
+ ).closeTo(vertices2[i][1], 1e-12);
1047
+ } else {
1048
+ expect(stateVariables["/_polyline1"].stateValues.vertices[i][1]).eq(
1049
+ vertices[i][1],
1050
+ );
1051
+ expect(stateVariables["/_polyline2"].stateValues.vertices[i][1]).eq(
1052
+ vertices2[i][1],
1053
+ );
1054
+ }
1055
+ }
1056
+ });
1057
+ }
1058
+
1059
+ let vertices = [
1060
+ [0, 0],
1061
+ [3, -4],
1062
+ [1, -6],
1063
+ [-5, -6],
1064
+ ];
1065
+ let transX = 5;
1066
+ let transY = 7;
1067
+
1068
+ testPolylines({ vertices, transX, transY });
1069
+
1070
+ cy.log("move points on first polyline");
1071
+ cy.window().then(async (win) => {
1072
+ vertices = [
1073
+ [1, -1],
1074
+ [-3, 2],
1075
+ [-1, 7],
1076
+ [6, 3],
1077
+ ];
1078
+
1079
+ win.callAction1({
1080
+ actionName: "movePolyline",
1081
+ componentName: "/_polyline1",
1082
+ args: {
1083
+ pointCoords: vertices,
1084
+ },
1085
+ });
1086
+
1087
+ testPolylines({ vertices, transX, transY });
1088
+ });
1089
+
1090
+ cy.log("move points on second polyline");
1091
+ cy.window().then(async (win) => {
1092
+ let vertices2 = [
1093
+ [-3, 4],
1094
+ [1, 0],
1095
+ [9, 6],
1096
+ [2, -1],
1097
+ ];
1098
+
1099
+ win.callAction1({
1100
+ actionName: "movePolyline",
1101
+ componentName: "/_polyline2",
1102
+ args: {
1103
+ pointCoords: vertices2,
1104
+ },
1105
+ });
1106
+
1107
+ vertices = vertices2.map((v) => [v[0] - transX, v[1] - transY]);
1108
+
1109
+ testPolylines({ vertices, transX, transY });
1110
+ });
1111
+
1112
+ cy.log("change translation");
1113
+ cy.get(cesc("#\\/transx") + " textarea").type("{end}{backspace}2{enter}", {
1114
+ force: true,
1115
+ });
1116
+ cy.get(cesc("#\\/transy") + " textarea").type("{end}{backspace}10{enter}", {
1117
+ force: true,
1118
+ });
1119
+ cy.window().then(async (win) => {
1120
+ transX = 2;
1121
+ transY = 10;
1122
+
1123
+ testPolylines({ vertices, transX, transY });
1124
+ });
1125
+ });
1126
+
1127
+ it("open parallelogram based on three points", () => {
1128
+ cy.window().then(async (win) => {
1129
+ win.postMessage(
1130
+ {
1131
+ doenetML: `
1132
+ <text>a</text>
1133
+ <graph>
1134
+ <polyline name="parallelogram" vertices="(1,2) (3,4) (-5,6) ($(parallelogram.vertexX1_1{fixed})+$(parallelogram.vertexX3_1{fixed})-$(parallelogram.vertexX2_1), $(parallelogram.vertexX1_2{fixed})+$(parallelogram.vertexX3_2{fixed})-$(parallelogram.vertexX2_2))" />
1135
+ </graph>
1136
+
1137
+ <copy target="parallelogram" prop="vertices" assignNames="p1 p2 p3 p4" />
1138
+
1139
+ `,
1140
+ },
1141
+ "*",
1142
+ );
1143
+ });
1144
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1145
+
1146
+ let A = [1, 2];
1147
+ let B = [3, 4];
1148
+ let C = [-5, 6];
1149
+ let D = [A[0] + C[0] - B[0], A[1] + C[1] - B[1]];
1150
+
1151
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1152
+ "contain.text",
1153
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1154
+ );
1155
+
1156
+ cy.window().then(async (win) => {
1157
+ let stateVariables = await win.returnAllStateVariables1();
1158
+ expect(stateVariables["/parallelogram"].stateValues.vertices[0]).eqls(A);
1159
+ expect(stateVariables["/parallelogram"].stateValues.vertices[1]).eqls(B);
1160
+ expect(stateVariables["/parallelogram"].stateValues.vertices[2]).eqls(C);
1161
+ expect(stateVariables["/parallelogram"].stateValues.vertices[3]).eqls(D);
1162
+ });
1163
+
1164
+ cy.log("move first vertex");
1165
+ cy.window().then(async (win) => {
1166
+ A = [-4, -1];
1167
+ D = [A[0] + C[0] - B[0], A[1] + C[1] - B[1]];
1168
+
1169
+ win.callAction1({
1170
+ actionName: "movePolyline",
1171
+ componentName: "/parallelogram",
1172
+ args: {
1173
+ pointCoords: { 0: A },
1174
+ },
1175
+ });
1176
+
1177
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1178
+ "contain.text",
1179
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1180
+ );
1181
+
1182
+ cy.window().then(async (win) => {
1183
+ let stateVariables = await win.returnAllStateVariables1();
1184
+ expect(stateVariables["/parallelogram"].stateValues.vertices[0]).eqls(
1185
+ A,
1186
+ );
1187
+ expect(stateVariables["/parallelogram"].stateValues.vertices[1]).eqls(
1188
+ B,
1189
+ );
1190
+ expect(stateVariables["/parallelogram"].stateValues.vertices[2]).eqls(
1191
+ C,
1192
+ );
1193
+ expect(stateVariables["/parallelogram"].stateValues.vertices[3]).eqls(
1194
+ D,
1195
+ );
1196
+ });
1197
+ });
1198
+
1199
+ cy.log("move second vertex");
1200
+ cy.window().then(async (win) => {
1201
+ B = [8, 9];
1202
+ D = [A[0] + C[0] - B[0], A[1] + C[1] - B[1]];
1203
+
1204
+ win.callAction1({
1205
+ actionName: "movePolyline",
1206
+ componentName: "/parallelogram",
1207
+ args: {
1208
+ pointCoords: { 1: B },
1209
+ },
1210
+ });
1211
+
1212
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
1213
+ "contain.text",
1214
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
1215
+ );
1216
+
1217
+ cy.window().then(async (win) => {
1218
+ let stateVariables = await win.returnAllStateVariables1();
1219
+ expect(stateVariables["/parallelogram"].stateValues.vertices[0]).eqls(
1220
+ A,
1221
+ );
1222
+ expect(stateVariables["/parallelogram"].stateValues.vertices[1]).eqls(
1223
+ B,
1224
+ );
1225
+ expect(stateVariables["/parallelogram"].stateValues.vertices[2]).eqls(
1226
+ C,
1227
+ );
1228
+ expect(stateVariables["/parallelogram"].stateValues.vertices[3]).eqls(
1229
+ D,
1230
+ );
1231
+ });
1232
+ });
1233
+
1234
+ cy.log("move third vertex");
1235
+ cy.window().then(async (win) => {
1236
+ C = [-3, 7];
1237
+ D = [A[0] + C[0] - B[0], A[1] + C[1] - B[1]];
1238
+
1239
+ win.callAction1({
1240
+ actionName: "movePolyline",
1241
+ componentName: "/parallelogram",
1242
+ args: {
1243
+ pointCoords: { 2: C },
1244
+ },
1245
+ });
1246
+
1247
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
1248
+ "contain.text",
1249
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
1250
+ );
1251
+
1252
+ cy.window().then(async (win) => {
1253
+ let stateVariables = await win.returnAllStateVariables1();
1254
+ expect(stateVariables["/parallelogram"].stateValues.vertices[0]).eqls(
1255
+ A,
1256
+ );
1257
+ expect(stateVariables["/parallelogram"].stateValues.vertices[1]).eqls(
1258
+ B,
1259
+ );
1260
+ expect(stateVariables["/parallelogram"].stateValues.vertices[2]).eqls(
1261
+ C,
1262
+ );
1263
+ expect(stateVariables["/parallelogram"].stateValues.vertices[3]).eqls(
1264
+ D,
1265
+ );
1266
+ });
1267
+ });
1268
+
1269
+ cy.log("move fourth vertex");
1270
+ cy.window().then(async (win) => {
1271
+ D = [7, 0];
1272
+ B = [A[0] + C[0] - D[0], A[1] + C[1] - D[1]];
1273
+
1274
+ win.callAction1({
1275
+ actionName: "movePolyline",
1276
+ componentName: "/parallelogram",
1277
+ args: {
1278
+ pointCoords: { 3: D },
1279
+ },
1280
+ });
1281
+
1282
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
1283
+ "contain.text",
1284
+ `(${nInDOM(D[0])},${nInDOM(D[1])})`,
1285
+ );
1286
+
1287
+ cy.window().then(async (win) => {
1288
+ let stateVariables = await win.returnAllStateVariables1();
1289
+ expect(stateVariables["/parallelogram"].stateValues.vertices[0]).eqls(
1290
+ A,
1291
+ );
1292
+ expect(stateVariables["/parallelogram"].stateValues.vertices[1]).eqls(
1293
+ B,
1294
+ );
1295
+ expect(stateVariables["/parallelogram"].stateValues.vertices[2]).eqls(
1296
+ C,
1297
+ );
1298
+ expect(stateVariables["/parallelogram"].stateValues.vertices[3]).eqls(
1299
+ D,
1300
+ );
1301
+ });
1302
+ });
1303
+ });
1304
+
1305
+ it("new polyline from copied vertices, some flipped", () => {
1306
+ cy.window().then(async (win) => {
1307
+ win.postMessage(
1308
+ {
1309
+ doenetML: `
1310
+ <text>a</text>
1311
+ <graph>
1312
+ <polyline vertices="(-9,6) (-3,7) (4,0) (8,5)" />
1313
+ </graph>
1314
+ <graph>
1315
+ <polyline vertices="$(_polyline1.vertex1) ($(_polyline1.vertexX2_2), $(_polyline1.vertexX2_1)) $(_polyline1.vertex3) ($(_polyline1.vertexX4_2), $(_polyline1.vertexX4_1))" />
1316
+ </graph>
1317
+ <copy target="_polyline2" prop="vertices" assignNames="p1 p2 p3 p4" />
1318
+ `,
1319
+ },
1320
+ "*",
1321
+ );
1322
+ });
1323
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1324
+
1325
+ async function testPolylines({ vertices }) {
1326
+ let vertices2 = [...vertices];
1327
+ vertices2[1] = [vertices2[1][1], vertices2[1][0]];
1328
+ vertices2[3] = [vertices2[3][1], vertices2[3][0]];
1329
+
1330
+ for (let i in vertices) {
1331
+ let ind = Number(i) + 1;
1332
+ cy.get(`#${cesc2("/p" + ind)} .mjx-mrow`).should(
1333
+ "contain.text",
1334
+ `(${nInDOM(
1335
+ Math.round(vertices2[i][0] * 100000000) / 100000000,
1336
+ ).substring(0, 6)}`,
1337
+ );
1338
+ cy.get(`#${cesc2("/p" + ind)} .mjx-mrow`).should(
1339
+ "contain.text",
1340
+ `,${nInDOM(
1341
+ Math.round(vertices2[i][1] * 100000000) / 100000000,
1342
+ ).substring(0, 6)}`,
1343
+ );
1344
+ }
1345
+ cy.get(`#${cesc2("/p" + (vertices.length + 1))}`).should("not.exist");
1346
+
1347
+ cy.window().then(async (win) => {
1348
+ let stateVariables = await win.returnAllStateVariables1();
1349
+ expect(stateVariables["/_polyline1"].stateValues.numVertices).eqls(
1350
+ vertices.length,
1351
+ );
1352
+ expect(stateVariables["/_polyline2"].stateValues.numVertices).eqls(
1353
+ vertices.length,
1354
+ );
1355
+
1356
+ for (let i in vertices) {
1357
+ if (Number.isFinite(vertices[i][0])) {
1358
+ expect(
1359
+ me
1360
+ .fromAst(
1361
+ stateVariables["/_polyline1"].stateValues.vertices[i][0],
1362
+ )
1363
+ .evaluate_to_constant(),
1364
+ ).closeTo(vertices[i][0], 1e-12);
1365
+ expect(
1366
+ me
1367
+ .fromAst(
1368
+ stateVariables["/_polyline2"].stateValues.vertices[i][0],
1369
+ )
1370
+ .evaluate_to_constant(),
1371
+ ).closeTo(vertices2[i][0], 1e-12);
1372
+ } else {
1373
+ expect(stateVariables["/_polyline1"].stateValues.vertices[i][0]).eq(
1374
+ vertices[i][0],
1375
+ );
1376
+ expect(stateVariables["/_polyline2"].stateValues.vertices[i][0]).eq(
1377
+ vertices2[i][0],
1378
+ );
1379
+ }
1380
+ if (Number.isFinite(vertices[i][1])) {
1381
+ expect(
1382
+ me
1383
+ .fromAst(
1384
+ stateVariables["/_polyline1"].stateValues.vertices[i][1],
1385
+ )
1386
+ .evaluate_to_constant(),
1387
+ ).closeTo(vertices[i][1], 1e-12);
1388
+ expect(
1389
+ me
1390
+ .fromAst(
1391
+ stateVariables["/_polyline2"].stateValues.vertices[i][1],
1392
+ )
1393
+ .evaluate_to_constant(),
1394
+ ).closeTo(vertices2[i][1], 1e-12);
1395
+ } else {
1396
+ expect(stateVariables["/_polyline1"].stateValues.vertices[i][1]).eq(
1397
+ vertices[i][1],
1398
+ );
1399
+ expect(stateVariables["/_polyline2"].stateValues.vertices[i][1]).eq(
1400
+ vertices2[i][1],
1401
+ );
1402
+ }
1403
+ }
1404
+ });
1405
+ }
1406
+
1407
+ let vertices = [
1408
+ [-9, 6],
1409
+ [-3, 7],
1410
+ [4, 0],
1411
+ [8, 5],
1412
+ ];
1413
+
1414
+ testPolylines({ vertices });
1415
+
1416
+ cy.log("move first polyline verticies");
1417
+ cy.window().then(async (win) => {
1418
+ vertices = [
1419
+ [7, 2],
1420
+ [1, -3],
1421
+ [2, 9],
1422
+ [-4, -3],
1423
+ ];
1424
+
1425
+ win.callAction1({
1426
+ actionName: "movePolyline",
1427
+ componentName: "/_polyline1",
1428
+ args: {
1429
+ pointCoords: vertices,
1430
+ },
1431
+ });
1432
+
1433
+ testPolylines({ vertices });
1434
+ });
1435
+
1436
+ cy.log("move second polyline verticies");
1437
+ cy.window().then(async (win) => {
1438
+ let vertices2 = [
1439
+ [-1, 9],
1440
+ [5, 7],
1441
+ [-8, 1],
1442
+ [-7, 6],
1443
+ ];
1444
+
1445
+ win.callAction1({
1446
+ actionName: "movePolyline",
1447
+ componentName: "/_polyline2",
1448
+ args: {
1449
+ pointCoords: vertices2,
1450
+ },
1451
+ });
1452
+
1453
+ vertices = [...vertices2];
1454
+ vertices[1] = [vertices[1][1], vertices[1][0]];
1455
+ vertices[3] = [vertices[3][1], vertices[3][0]];
1456
+
1457
+ testPolylines({ vertices });
1458
+ });
1459
+ });
1460
+
1461
+ it("four vertex polyline based on three points", () => {
1462
+ cy.window().then(async (win) => {
1463
+ win.postMessage(
1464
+ {
1465
+ doenetML: `
1466
+ <text>a</text>
1467
+ <graph>
1468
+ <polyline vertices="(1,2) (3,4) (-5,6) ($(_polyline1.vertexX3_1{fixed})+$(_polyline1.vertexX2_1{fixed})-$(_polyline1.vertexX1_1), $(_polyline1.vertexX3_2{fixed})+$(_polyline1.vertexX2_2{fixed})-$(_polyline1.vertexX1_2))" />
1469
+ </graph>
1470
+ <copy target="_polyline1" prop="vertices" assignNames="p1 p2 p3 p4" />
1471
+
1472
+ `,
1473
+ },
1474
+ "*",
1475
+ );
1476
+ });
1477
+
1478
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1479
+
1480
+ let A = [1, 2];
1481
+ let B = [3, 4];
1482
+ let C = [-5, 6];
1483
+ let D = [C[0] + B[0] - A[0], C[1] + B[1] - A[1]];
1484
+
1485
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1486
+ "contain.text",
1487
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1488
+ );
1489
+
1490
+ cy.window().then(async (win) => {
1491
+ let stateVariables = await win.returnAllStateVariables1();
1492
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1493
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1494
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1495
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(D);
1496
+ });
1497
+
1498
+ cy.log("move first vertex");
1499
+ cy.window().then(async (win) => {
1500
+ A = [-4, -1];
1501
+ D = [C[0] + B[0] - A[0], C[1] + B[1] - A[1]];
1502
+
1503
+ win.callAction1({
1504
+ actionName: "movePolyline",
1505
+ componentName: "/_polyline1",
1506
+ args: {
1507
+ pointCoords: { 0: A },
1508
+ },
1509
+ });
1510
+
1511
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1512
+ "contain.text",
1513
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1514
+ );
1515
+
1516
+ cy.window().then(async (win) => {
1517
+ let stateVariables = await win.returnAllStateVariables1();
1518
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1519
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1520
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1521
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(D);
1522
+ });
1523
+ });
1524
+
1525
+ cy.log("move second vertex");
1526
+ cy.window().then(async (win) => {
1527
+ B = [8, 9];
1528
+ D = [C[0] + B[0] - A[0], C[1] + B[1] - A[1]];
1529
+
1530
+ win.callAction1({
1531
+ actionName: "movePolyline",
1532
+ componentName: "/_polyline1",
1533
+ args: {
1534
+ pointCoords: { 1: B },
1535
+ },
1536
+ });
1537
+
1538
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
1539
+ "contain.text",
1540
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
1541
+ );
1542
+
1543
+ cy.window().then(async (win) => {
1544
+ let stateVariables = await win.returnAllStateVariables1();
1545
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1546
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1547
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1548
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(D);
1549
+ });
1550
+ });
1551
+
1552
+ cy.log("move third vertex");
1553
+ cy.window().then(async (win) => {
1554
+ C = [-3, 7];
1555
+ D = [C[0] + B[0] - A[0], C[1] + B[1] - A[1]];
1556
+
1557
+ win.callAction1({
1558
+ actionName: "movePolyline",
1559
+ componentName: "/_polyline1",
1560
+ args: {
1561
+ pointCoords: { 2: C },
1562
+ },
1563
+ });
1564
+
1565
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
1566
+ "contain.text",
1567
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
1568
+ );
1569
+
1570
+ cy.window().then(async (win) => {
1571
+ let stateVariables = await win.returnAllStateVariables1();
1572
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1573
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1574
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1575
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(D);
1576
+ });
1577
+ });
1578
+
1579
+ cy.log("move fourth vertex");
1580
+ cy.window().then(async (win) => {
1581
+ D = [7, 0];
1582
+ A = [C[0] + B[0] - D[0], C[1] + B[1] - D[1]];
1583
+
1584
+ win.callAction1({
1585
+ actionName: "movePolyline",
1586
+ componentName: "/_polyline1",
1587
+ args: {
1588
+ pointCoords: { 3: D },
1589
+ },
1590
+ });
1591
+
1592
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
1593
+ "contain.text",
1594
+ `(${nInDOM(D[0])},${nInDOM(D[1])})`,
1595
+ );
1596
+
1597
+ cy.window().then(async (win) => {
1598
+ let stateVariables = await win.returnAllStateVariables1();
1599
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1600
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1601
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1602
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(D);
1603
+ });
1604
+ });
1605
+ });
1606
+
1607
+ it("fourth vertex depends on internal copy of first vertex", () => {
1608
+ cy.window().then(async (win) => {
1609
+ win.postMessage(
1610
+ {
1611
+ doenetML: `
1612
+ <text>a</text>
1613
+ <graph>
1614
+ <polyline vertices="(1,2) (3,4) (-5,6) $(_polyline1.vertex1{createComponentOfType='point'})" />
1615
+ </graph>
1616
+ <copy target="_polyline1" prop="vertices" assignNames="p1 p2 p3 p4" />
1617
+ `,
1618
+ },
1619
+ "*",
1620
+ );
1621
+ });
1622
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1623
+
1624
+ let A = [1, 2];
1625
+ let B = [3, 4];
1626
+ let C = [-5, 6];
1627
+
1628
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1629
+ "contain.text",
1630
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1631
+ );
1632
+
1633
+ cy.window().then(async (win) => {
1634
+ let stateVariables = await win.returnAllStateVariables1();
1635
+ expect(stateVariables["/_polyline1"].stateValues.numVertices).eq(4);
1636
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1637
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1638
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1639
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1640
+ });
1641
+
1642
+ cy.log("move first vertex");
1643
+ cy.window().then(async (win) => {
1644
+ A = [-4, -1];
1645
+
1646
+ win.callAction1({
1647
+ actionName: "movePolyline",
1648
+ componentName: "/_polyline1",
1649
+ args: {
1650
+ pointCoords: { 0: A },
1651
+ },
1652
+ });
1653
+
1654
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1655
+ "contain.text",
1656
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1657
+ );
1658
+
1659
+ cy.window().then(async (win) => {
1660
+ let stateVariables = await win.returnAllStateVariables1();
1661
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1662
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1663
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1664
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1665
+ });
1666
+ });
1667
+
1668
+ cy.log("move second vertex");
1669
+ cy.window().then(async (win) => {
1670
+ B = [8, 9];
1671
+
1672
+ win.callAction1({
1673
+ actionName: "movePolyline",
1674
+ componentName: "/_polyline1",
1675
+ args: {
1676
+ pointCoords: { 1: B },
1677
+ },
1678
+ });
1679
+
1680
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
1681
+ "contain.text",
1682
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
1683
+ );
1684
+
1685
+ cy.window().then(async (win) => {
1686
+ let stateVariables = await win.returnAllStateVariables1();
1687
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1688
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1689
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1690
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1691
+ });
1692
+ });
1693
+
1694
+ cy.log("move third vertex");
1695
+ cy.window().then(async (win) => {
1696
+ C = [-3, 7];
1697
+
1698
+ win.callAction1({
1699
+ actionName: "movePolyline",
1700
+ componentName: "/_polyline1",
1701
+ args: {
1702
+ pointCoords: { 2: C },
1703
+ },
1704
+ });
1705
+
1706
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
1707
+ "contain.text",
1708
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
1709
+ );
1710
+
1711
+ cy.window().then(async (win) => {
1712
+ let stateVariables = await win.returnAllStateVariables1();
1713
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1714
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1715
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1716
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1717
+ });
1718
+ });
1719
+
1720
+ cy.log("move fourth vertex");
1721
+ cy.window().then(async (win) => {
1722
+ A = [7, 0];
1723
+ win.callAction1({
1724
+ actionName: "movePolyline",
1725
+ componentName: "/_polyline1",
1726
+ args: {
1727
+ pointCoords: { 3: A },
1728
+ },
1729
+ });
1730
+
1731
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
1732
+ "contain.text",
1733
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1734
+ );
1735
+
1736
+ cy.window().then(async (win) => {
1737
+ let stateVariables = await win.returnAllStateVariables1();
1738
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1739
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1740
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1741
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1742
+ });
1743
+ });
1744
+ });
1745
+
1746
+ it("first vertex depends on internal copy of fourth vertex", () => {
1747
+ cy.window().then(async (win) => {
1748
+ win.postMessage(
1749
+ {
1750
+ doenetML: `
1751
+ <text>a</text>
1752
+ <graph>
1753
+ <polyline vertices="$(_polyline1.vertex4{ createComponentOfType='point' }) (3,4) (-5,6) (1,2)" />
1754
+ </graph>
1755
+ <copy target="_polyline1" prop="vertices" assignNames="p1 p2 p3 p4" />
1756
+
1757
+ `,
1758
+ },
1759
+ "*",
1760
+ );
1761
+ });
1762
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1763
+
1764
+ let A = [1, 2];
1765
+ let B = [3, 4];
1766
+ let C = [-5, 6];
1767
+
1768
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1769
+ "contain.text",
1770
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1771
+ );
1772
+
1773
+ cy.window().then(async (win) => {
1774
+ let stateVariables = await win.returnAllStateVariables1();
1775
+ expect(stateVariables["/_polyline1"].stateValues.numVertices).eq(4);
1776
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1777
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1778
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1779
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1780
+ });
1781
+
1782
+ cy.log("move first vertex");
1783
+ cy.window().then(async (win) => {
1784
+ A = [-4, -1];
1785
+
1786
+ win.callAction1({
1787
+ actionName: "movePolyline",
1788
+ componentName: "/_polyline1",
1789
+ args: {
1790
+ pointCoords: { 0: A },
1791
+ },
1792
+ });
1793
+
1794
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1795
+ "contain.text",
1796
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1797
+ );
1798
+
1799
+ cy.window().then(async (win) => {
1800
+ let stateVariables = await win.returnAllStateVariables1();
1801
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1802
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1803
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1804
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1805
+ });
1806
+ });
1807
+
1808
+ cy.log("move second vertex");
1809
+ cy.window().then(async (win) => {
1810
+ B = [8, 9];
1811
+
1812
+ win.callAction1({
1813
+ actionName: "movePolyline",
1814
+ componentName: "/_polyline1",
1815
+ args: {
1816
+ pointCoords: { 1: B },
1817
+ },
1818
+ });
1819
+
1820
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
1821
+ "contain.text",
1822
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
1823
+ );
1824
+
1825
+ cy.window().then(async (win) => {
1826
+ let stateVariables = await win.returnAllStateVariables1();
1827
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1828
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1829
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1830
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1831
+ });
1832
+ });
1833
+
1834
+ cy.log("move third vertex");
1835
+ cy.window().then(async (win) => {
1836
+ C = [-3, 7];
1837
+
1838
+ win.callAction1({
1839
+ actionName: "movePolyline",
1840
+ componentName: "/_polyline1",
1841
+ args: {
1842
+ pointCoords: { 2: C },
1843
+ },
1844
+ });
1845
+
1846
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
1847
+ "contain.text",
1848
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
1849
+ );
1850
+
1851
+ cy.window().then(async (win) => {
1852
+ let stateVariables = await win.returnAllStateVariables1();
1853
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1854
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1855
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1856
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1857
+ });
1858
+ });
1859
+
1860
+ cy.log("move fourth vertex");
1861
+ cy.window().then(async (win) => {
1862
+ A = [7, 0];
1863
+
1864
+ win.callAction1({
1865
+ actionName: "movePolyline",
1866
+ componentName: "/_polyline1",
1867
+ args: {
1868
+ pointCoords: { 3: A },
1869
+ },
1870
+ });
1871
+
1872
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
1873
+ "contain.text",
1874
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1875
+ );
1876
+
1877
+ cy.window().then(async (win) => {
1878
+ let stateVariables = await win.returnAllStateVariables1();
1879
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1880
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1881
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1882
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1883
+ });
1884
+ });
1885
+ });
1886
+
1887
+ it("first vertex depends fourth, formula for fifth", () => {
1888
+ cy.window().then(async (win) => {
1889
+ win.postMessage(
1890
+ {
1891
+ doenetML: `
1892
+ <text>a</text>
1893
+ <graph>
1894
+ <polyline vertices="$(_polyline1.vertex4{createComponentOfType='point'}) (3,4) (-5,6) (1,2) ($(_polyline1.vertexX1_1)+1,2)" />
1895
+ </graph>
1896
+ <copy target="_polyline1" prop="vertices" assignNames="p1 p2 p3 p4 p5" />
1897
+
1898
+ `,
1899
+ },
1900
+ "*",
1901
+ );
1902
+ });
1903
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
1904
+
1905
+ let A = [1, 2];
1906
+ let B = [3, 4];
1907
+ let C = [-5, 6];
1908
+ let D = [A[0] + 1, 2];
1909
+
1910
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1911
+ "contain.text",
1912
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1913
+ );
1914
+
1915
+ cy.window().then(async (win) => {
1916
+ let stateVariables = await win.returnAllStateVariables1();
1917
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1918
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1919
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1920
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1921
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
1922
+ });
1923
+
1924
+ cy.log("move first vertex");
1925
+ cy.window().then(async (win) => {
1926
+ A = [-4, -1];
1927
+ D[0] = A[0] + 1;
1928
+
1929
+ win.callAction1({
1930
+ actionName: "movePolyline",
1931
+ componentName: "/_polyline1",
1932
+ args: {
1933
+ pointCoords: { 0: A },
1934
+ },
1935
+ });
1936
+
1937
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
1938
+ "contain.text",
1939
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
1940
+ );
1941
+
1942
+ cy.window().then(async (win) => {
1943
+ let stateVariables = await win.returnAllStateVariables1();
1944
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1945
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1946
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1947
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1948
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
1949
+ });
1950
+ });
1951
+
1952
+ cy.log("move second vertex");
1953
+ cy.window().then(async (win) => {
1954
+ B = [8, 9];
1955
+
1956
+ win.callAction1({
1957
+ actionName: "movePolyline",
1958
+ componentName: "/_polyline1",
1959
+ args: {
1960
+ pointCoords: { 1: B },
1961
+ },
1962
+ });
1963
+
1964
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
1965
+ "contain.text",
1966
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
1967
+ );
1968
+
1969
+ cy.window().then(async (win) => {
1970
+ let stateVariables = await win.returnAllStateVariables1();
1971
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1972
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
1973
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
1974
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
1975
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
1976
+ });
1977
+ });
1978
+
1979
+ cy.log("move third vertex");
1980
+ cy.window().then(async (win) => {
1981
+ C = [-3, 7];
1982
+
1983
+ win.callAction1({
1984
+ actionName: "movePolyline",
1985
+ componentName: "/_polyline1",
1986
+ args: {
1987
+ pointCoords: { 2: C },
1988
+ },
1989
+ });
1990
+
1991
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
1992
+ "contain.text",
1993
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
1994
+ );
1995
+
1996
+ cy.window().then(async (win) => {
1997
+ let stateVariables = await win.returnAllStateVariables1();
1998
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
1999
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
2000
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
2001
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
2002
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
2003
+ });
2004
+ });
2005
+
2006
+ cy.log("move fourth vertex");
2007
+ cy.window().then(async (win) => {
2008
+ A = [7, 0];
2009
+ D[0] = A[0] + 1;
2010
+
2011
+ win.callAction1({
2012
+ actionName: "movePolyline",
2013
+ componentName: "/_polyline1",
2014
+ args: {
2015
+ pointCoords: { 3: A },
2016
+ },
2017
+ });
2018
+
2019
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
2020
+ "contain.text",
2021
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2022
+ );
2023
+
2024
+ cy.window().then(async (win) => {
2025
+ let stateVariables = await win.returnAllStateVariables1();
2026
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
2027
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
2028
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
2029
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
2030
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
2031
+ });
2032
+ });
2033
+
2034
+ cy.log("move fifth vertex");
2035
+ cy.window().then(async (win) => {
2036
+ D = [-5, 9];
2037
+ A[0] = D[0] - 1;
2038
+
2039
+ win.callAction1({
2040
+ actionName: "movePolyline",
2041
+ componentName: "/_polyline1",
2042
+ args: {
2043
+ pointCoords: { 4: D },
2044
+ },
2045
+ });
2046
+
2047
+ cy.get(cesc("#\\/p5") + " .mjx-mrow").should(
2048
+ "contain.text",
2049
+ `(${nInDOM(D[0])},${nInDOM(D[1])})`,
2050
+ );
2051
+
2052
+ cy.window().then(async (win) => {
2053
+ let stateVariables = await win.returnAllStateVariables1();
2054
+ expect(stateVariables["/_polyline1"].stateValues.vertices[0]).eqls(A);
2055
+ expect(stateVariables["/_polyline1"].stateValues.vertices[1]).eqls(B);
2056
+ expect(stateVariables["/_polyline1"].stateValues.vertices[2]).eqls(C);
2057
+ expect(stateVariables["/_polyline1"].stateValues.vertices[3]).eqls(A);
2058
+ expect(stateVariables["/_polyline1"].stateValues.vertices[4]).eqls(D);
2059
+ });
2060
+ });
2061
+ });
2062
+
2063
+ it("first, fourth, seventh vertex depends on fourth, seventh, tenth", () => {
2064
+ cy.window().then(async (win) => {
2065
+ win.postMessage(
2066
+ {
2067
+ doenetML: `
2068
+ <text>a</text>
2069
+ <graph>
2070
+ <polyline name="P" vertices="$(P.vertex4{createComponentOfType='point'}) (1,2) (3,4) $(P.vertex7{createComponentOfType='point'}) (5,7) (-5,7) $(P.vertex10{createComponentOfType='point'}) (3,1) (5,0) (-5,-1)" />
2071
+ </graph>
2072
+ <copy target="P" prop="vertices" assignNames="p1 p2 p3 p4 p5 p6 p7 p8 p9 p10" />
2073
+
2074
+ `,
2075
+ },
2076
+ "*",
2077
+ );
2078
+ });
2079
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
2080
+
2081
+ let A = [-5, -1];
2082
+ let B = [1, 2];
2083
+ let C = [3, 4];
2084
+ let D = [5, 7];
2085
+ let E = [-5, 7];
2086
+ let F = [3, 1];
2087
+ let G = [5, 0];
2088
+
2089
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
2090
+ "contain.text",
2091
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2092
+ );
2093
+
2094
+ cy.window().then(async (win) => {
2095
+ let stateVariables = await win.returnAllStateVariables1();
2096
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2097
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2098
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2099
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2100
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2101
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2102
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2103
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2104
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2105
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2106
+ });
2107
+
2108
+ cy.log("move first vertex");
2109
+ cy.window().then(async (win) => {
2110
+ A = [-4, -9];
2111
+
2112
+ win.callAction1({
2113
+ actionName: "movePolyline",
2114
+ componentName: "/P",
2115
+ args: {
2116
+ pointCoords: { 0: A },
2117
+ },
2118
+ });
2119
+
2120
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
2121
+ "contain.text",
2122
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2123
+ );
2124
+
2125
+ cy.window().then(async (win) => {
2126
+ let stateVariables = await win.returnAllStateVariables1();
2127
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2128
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2129
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2130
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2131
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2132
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2133
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2134
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2135
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2136
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2137
+ });
2138
+ });
2139
+
2140
+ cy.log("move second vertex");
2141
+ cy.window().then(async (win) => {
2142
+ B = [8, 9];
2143
+
2144
+ win.callAction1({
2145
+ actionName: "movePolyline",
2146
+ componentName: "/P",
2147
+ args: {
2148
+ pointCoords: { 1: B },
2149
+ },
2150
+ });
2151
+
2152
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
2153
+ "contain.text",
2154
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
2155
+ );
2156
+
2157
+ cy.window().then(async (win) => {
2158
+ let stateVariables = await win.returnAllStateVariables1();
2159
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2160
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2161
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2162
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2163
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2164
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2165
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2166
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2167
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2168
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2169
+ });
2170
+ });
2171
+
2172
+ cy.log("move third vertex");
2173
+ cy.window().then(async (win) => {
2174
+ C = [-3, 7];
2175
+
2176
+ win.callAction1({
2177
+ actionName: "movePolyline",
2178
+ componentName: "/P",
2179
+ args: {
2180
+ pointCoords: { 2: C },
2181
+ },
2182
+ });
2183
+
2184
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
2185
+ "contain.text",
2186
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
2187
+ );
2188
+
2189
+ cy.window().then(async (win) => {
2190
+ let stateVariables = await win.returnAllStateVariables1();
2191
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2192
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2193
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2194
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2195
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2196
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2197
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2198
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2199
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2200
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2201
+ });
2202
+ });
2203
+
2204
+ cy.log("move fourth vertex");
2205
+ cy.window().then(async (win) => {
2206
+ A = [7, 0];
2207
+
2208
+ win.callAction1({
2209
+ actionName: "movePolyline",
2210
+ componentName: "/P",
2211
+ args: {
2212
+ pointCoords: { 3: A },
2213
+ },
2214
+ });
2215
+
2216
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
2217
+ "contain.text",
2218
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2219
+ );
2220
+
2221
+ cy.window().then(async (win) => {
2222
+ let stateVariables = await win.returnAllStateVariables1();
2223
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2224
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2225
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2226
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2227
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2228
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2229
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2230
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2231
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2232
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2233
+ });
2234
+ });
2235
+
2236
+ cy.log("move fifth vertex");
2237
+ cy.window().then(async (win) => {
2238
+ D = [-9, 1];
2239
+
2240
+ win.callAction1({
2241
+ actionName: "movePolyline",
2242
+ componentName: "/P",
2243
+ args: {
2244
+ pointCoords: { 4: D },
2245
+ },
2246
+ });
2247
+
2248
+ cy.get(cesc("#\\/p5") + " .mjx-mrow").should(
2249
+ "contain.text",
2250
+ `(${nInDOM(D[0])},${nInDOM(D[1])})`,
2251
+ );
2252
+
2253
+ cy.window().then(async (win) => {
2254
+ let stateVariables = await win.returnAllStateVariables1();
2255
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2256
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2257
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2258
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2259
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2260
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2261
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2262
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2263
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2264
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2265
+ });
2266
+ });
2267
+
2268
+ cy.log("move sixth vertex");
2269
+ cy.window().then(async (win) => {
2270
+ E = [-3, 6];
2271
+
2272
+ win.callAction1({
2273
+ actionName: "movePolyline",
2274
+ componentName: "/P",
2275
+ args: {
2276
+ pointCoords: { 5: E },
2277
+ },
2278
+ });
2279
+
2280
+ cy.get(cesc("#\\/p6") + " .mjx-mrow").should(
2281
+ "contain.text",
2282
+ `(${nInDOM(E[0])},${nInDOM(E[1])})`,
2283
+ );
2284
+
2285
+ cy.window().then(async (win) => {
2286
+ let stateVariables = await win.returnAllStateVariables1();
2287
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2288
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2289
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2290
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2291
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2292
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2293
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2294
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2295
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2296
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2297
+ });
2298
+ });
2299
+
2300
+ cy.log("move seventh vertex");
2301
+ cy.window().then(async (win) => {
2302
+ A = [2, -4];
2303
+
2304
+ win.callAction1({
2305
+ actionName: "movePolyline",
2306
+ componentName: "/P",
2307
+ args: {
2308
+ pointCoords: { 6: A },
2309
+ },
2310
+ });
2311
+
2312
+ cy.get(cesc("#\\/p7") + " .mjx-mrow").should(
2313
+ "contain.text",
2314
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2315
+ );
2316
+
2317
+ cy.window().then(async (win) => {
2318
+ let stateVariables = await win.returnAllStateVariables1();
2319
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2320
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2321
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2322
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2323
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2324
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2325
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2326
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2327
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2328
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2329
+ });
2330
+ });
2331
+
2332
+ cy.log("move eighth vertex");
2333
+ cy.window().then(async (win) => {
2334
+ F = [6, 7];
2335
+
2336
+ win.callAction1({
2337
+ actionName: "movePolyline",
2338
+ componentName: "/P",
2339
+ args: {
2340
+ pointCoords: { 7: F },
2341
+ },
2342
+ });
2343
+
2344
+ cy.get(cesc("#\\/p8") + " .mjx-mrow").should(
2345
+ "contain.text",
2346
+ `(${nInDOM(F[0])},${nInDOM(F[1])})`,
2347
+ );
2348
+
2349
+ cy.window().then(async (win) => {
2350
+ let stateVariables = await win.returnAllStateVariables1();
2351
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2352
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2353
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2354
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2355
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2356
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2357
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2358
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2359
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2360
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2361
+ });
2362
+ });
2363
+
2364
+ cy.log("move nineth vertex");
2365
+ cy.window().then(async (win) => {
2366
+ G = [1, -8];
2367
+
2368
+ win.callAction1({
2369
+ actionName: "movePolyline",
2370
+ componentName: "/P",
2371
+ args: {
2372
+ pointCoords: { 8: G },
2373
+ },
2374
+ });
2375
+
2376
+ cy.get(cesc("#\\/p9") + " .mjx-mrow").should(
2377
+ "contain.text",
2378
+ `(${nInDOM(G[0])},${nInDOM(G[1])})`,
2379
+ );
2380
+
2381
+ cy.window().then(async (win) => {
2382
+ let stateVariables = await win.returnAllStateVariables1();
2383
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2384
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2385
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2386
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2387
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2388
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2389
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2390
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2391
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2392
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2393
+ });
2394
+ });
2395
+
2396
+ cy.log("move tenth vertex");
2397
+ cy.window().then(async (win) => {
2398
+ A = [-6, 10];
2399
+
2400
+ win.callAction1({
2401
+ actionName: "movePolyline",
2402
+ componentName: "/P",
2403
+ args: {
2404
+ pointCoords: { 9: A },
2405
+ },
2406
+ });
2407
+
2408
+ cy.get(cesc("#\\/p10") + " .mjx-mrow").should(
2409
+ "contain.text",
2410
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2411
+ );
2412
+
2413
+ cy.window().then(async (win) => {
2414
+ let stateVariables = await win.returnAllStateVariables1();
2415
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A);
2416
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2417
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2418
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A);
2419
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2420
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2421
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A);
2422
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2423
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2424
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2425
+ });
2426
+ });
2427
+ });
2428
+
2429
+ it("first, fourth, seventh vertex depends on shifted fourth, seventh, tenth", () => {
2430
+ cy.window().then(async (win) => {
2431
+ win.postMessage(
2432
+ {
2433
+ doenetML: `
2434
+ <text>a</text>
2435
+ <graph>
2436
+ <polyline name="P" vertices="($(P.vertexX4_1)+1,$(P.vertexX4_2)+1) (1,2) (3,4) ($(P.vertexX7_1)+1,$(P.vertexX7_2)+1) (5,7) (-5,7) ($(P.vertexX10_1)+1,$(P.vertexX10_2)+1) (3,1) (5,0) (-5,-1)" />
2437
+ </graph>
2438
+ <copy target="P" prop="vertices" assignNames="p1 p2 p3 p4 p5 p6 p7 p8 p9 p10" />
2439
+
2440
+ `,
2441
+ },
2442
+ "*",
2443
+ );
2444
+ });
2445
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
2446
+
2447
+ let A = [-5, -1];
2448
+ let B = [1, 2];
2449
+ let C = [3, 4];
2450
+ let D = [5, 7];
2451
+ let E = [-5, 7];
2452
+ let F = [3, 1];
2453
+ let G = [5, 0];
2454
+ let A1 = [A[0] + 1, A[1] + 1];
2455
+ let A2 = [A[0] + 2, A[1] + 2];
2456
+ let A3 = [A[0] + 3, A[1] + 3];
2457
+
2458
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
2459
+ "contain.text",
2460
+ `(${nInDOM(A3[0])},${nInDOM(A3[1])})`,
2461
+ );
2462
+
2463
+ cy.window().then(async (win) => {
2464
+ let stateVariables = await win.returnAllStateVariables1();
2465
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2466
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2467
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2468
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2469
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2470
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2471
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2472
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2473
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2474
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2475
+ });
2476
+
2477
+ cy.log("move first vertex");
2478
+ cy.window().then(async (win) => {
2479
+ A = [-4, -9];
2480
+ A1 = [A[0] + 1, A[1] + 1];
2481
+ A2 = [A[0] + 2, A[1] + 2];
2482
+ A3 = [A[0] + 3, A[1] + 3];
2483
+
2484
+ win.callAction1({
2485
+ actionName: "movePolyline",
2486
+ componentName: "/P",
2487
+ args: {
2488
+ pointCoords: { 0: A3 },
2489
+ },
2490
+ });
2491
+
2492
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
2493
+ "contain.text",
2494
+ `(${nInDOM(A3[0])},${nInDOM(A3[1])})`,
2495
+ );
2496
+
2497
+ cy.window().then(async (win) => {
2498
+ let stateVariables = await win.returnAllStateVariables1();
2499
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2500
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2501
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2502
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2503
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2504
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2505
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2506
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2507
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2508
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2509
+ });
2510
+ });
2511
+
2512
+ cy.log("move second vertex");
2513
+ cy.window().then(async (win) => {
2514
+ B = [8, 9];
2515
+
2516
+ win.callAction1({
2517
+ actionName: "movePolyline",
2518
+ componentName: "/P",
2519
+ args: {
2520
+ pointCoords: { 1: B },
2521
+ },
2522
+ });
2523
+
2524
+ cy.get(cesc("#\\/p2") + " .mjx-mrow").should(
2525
+ "contain.text",
2526
+ `(${nInDOM(B[0])},${nInDOM(B[1])})`,
2527
+ );
2528
+
2529
+ cy.window().then(async (win) => {
2530
+ let stateVariables = await win.returnAllStateVariables1();
2531
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2532
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2533
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2534
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2535
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2536
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2537
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2538
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2539
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2540
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2541
+ });
2542
+ });
2543
+
2544
+ cy.log("move third vertex");
2545
+ cy.window().then(async (win) => {
2546
+ C = [-3, 7];
2547
+
2548
+ win.callAction1({
2549
+ actionName: "movePolyline",
2550
+ componentName: "/P",
2551
+ args: {
2552
+ pointCoords: { 2: C },
2553
+ },
2554
+ });
2555
+
2556
+ cy.get(cesc("#\\/p3") + " .mjx-mrow").should(
2557
+ "contain.text",
2558
+ `(${nInDOM(C[0])},${nInDOM(C[1])})`,
2559
+ );
2560
+
2561
+ cy.window().then(async (win) => {
2562
+ let stateVariables = await win.returnAllStateVariables1();
2563
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2564
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2565
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2566
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2567
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2568
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2569
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2570
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2571
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2572
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2573
+ });
2574
+ });
2575
+
2576
+ cy.log("move fourth vertex");
2577
+ cy.window().then(async (win) => {
2578
+ A = [7, 0];
2579
+ A1 = [A[0] + 1, A[1] + 1];
2580
+ A2 = [A[0] + 2, A[1] + 2];
2581
+ A3 = [A[0] + 3, A[1] + 3];
2582
+
2583
+ win.callAction1({
2584
+ actionName: "movePolyline",
2585
+ componentName: "/P",
2586
+ args: {
2587
+ pointCoords: { 3: A2 },
2588
+ },
2589
+ });
2590
+
2591
+ cy.get(cesc("#\\/p4") + " .mjx-mrow").should(
2592
+ "contain.text",
2593
+ `(${nInDOM(A2[0])},${nInDOM(A2[1])})`,
2594
+ );
2595
+
2596
+ cy.window().then(async (win) => {
2597
+ let stateVariables = await win.returnAllStateVariables1();
2598
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2599
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2600
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2601
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2602
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2603
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2604
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2605
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2606
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2607
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2608
+ });
2609
+ });
2610
+
2611
+ cy.log("move fifth vertex");
2612
+ cy.window().then(async (win) => {
2613
+ D = [-9, 1];
2614
+
2615
+ win.callAction1({
2616
+ actionName: "movePolyline",
2617
+ componentName: "/P",
2618
+ args: {
2619
+ pointCoords: { 4: D },
2620
+ },
2621
+ });
2622
+
2623
+ cy.get(cesc("#\\/p5") + " .mjx-mrow").should(
2624
+ "contain.text",
2625
+ `(${nInDOM(D[0])},${nInDOM(D[1])})`,
2626
+ );
2627
+
2628
+ cy.window().then(async (win) => {
2629
+ let stateVariables = await win.returnAllStateVariables1();
2630
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2631
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2632
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2633
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2634
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2635
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2636
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2637
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2638
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2639
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2640
+ });
2641
+ });
2642
+
2643
+ cy.log("move sixth vertex");
2644
+ cy.window().then(async (win) => {
2645
+ E = [-3, 6];
2646
+
2647
+ win.callAction1({
2648
+ actionName: "movePolyline",
2649
+ componentName: "/P",
2650
+ args: {
2651
+ pointCoords: { 5: E },
2652
+ },
2653
+ });
2654
+
2655
+ cy.get(cesc("#\\/p6") + " .mjx-mrow").should(
2656
+ "contain.text",
2657
+ `(${nInDOM(E[0])},${nInDOM(E[1])})`,
2658
+ );
2659
+
2660
+ cy.window().then(async (win) => {
2661
+ let stateVariables = await win.returnAllStateVariables1();
2662
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2663
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2664
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2665
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2666
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2667
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2668
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2669
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2670
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2671
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2672
+ });
2673
+ });
2674
+
2675
+ cy.log("move seventh vertex");
2676
+ cy.window().then(async (win) => {
2677
+ A = [2, -4];
2678
+ A1 = [A[0] + 1, A[1] + 1];
2679
+ A2 = [A[0] + 2, A[1] + 2];
2680
+ A3 = [A[0] + 3, A[1] + 3];
2681
+
2682
+ win.callAction1({
2683
+ actionName: "movePolyline",
2684
+ componentName: "/P",
2685
+ args: {
2686
+ pointCoords: { 6: A1 },
2687
+ },
2688
+ });
2689
+
2690
+ cy.get(cesc("#\\/p7") + " .mjx-mrow").should(
2691
+ "contain.text",
2692
+ `(${nInDOM(A1[0])},${nInDOM(A1[1])})`,
2693
+ );
2694
+
2695
+ cy.window().then(async (win) => {
2696
+ let stateVariables = await win.returnAllStateVariables1();
2697
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2698
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2699
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2700
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2701
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2702
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2703
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2704
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2705
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2706
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2707
+ });
2708
+ });
2709
+
2710
+ cy.log("move eighth vertex");
2711
+ cy.window().then(async (win) => {
2712
+ F = [6, 7];
2713
+
2714
+ win.callAction1({
2715
+ actionName: "movePolyline",
2716
+ componentName: "/P",
2717
+ args: {
2718
+ pointCoords: { 7: F },
2719
+ },
2720
+ });
2721
+
2722
+ cy.get(cesc("#\\/p8") + " .mjx-mrow").should(
2723
+ "contain.text",
2724
+ `(${nInDOM(F[0])},${nInDOM(F[1])})`,
2725
+ );
2726
+
2727
+ cy.window().then(async (win) => {
2728
+ let stateVariables = await win.returnAllStateVariables1();
2729
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2730
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2731
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2732
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2733
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2734
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2735
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2736
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2737
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2738
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2739
+ });
2740
+ });
2741
+
2742
+ cy.log("move nineth vertex");
2743
+ cy.window().then(async (win) => {
2744
+ G = [1, -8];
2745
+
2746
+ win.callAction1({
2747
+ actionName: "movePolyline",
2748
+ componentName: "/P",
2749
+ args: {
2750
+ pointCoords: { 8: G },
2751
+ },
2752
+ });
2753
+
2754
+ cy.get(cesc("#\\/p9") + " .mjx-mrow").should(
2755
+ "contain.text",
2756
+ `(${nInDOM(G[0])},${nInDOM(G[1])})`,
2757
+ );
2758
+
2759
+ cy.window().then(async (win) => {
2760
+ let stateVariables = await win.returnAllStateVariables1();
2761
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2762
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2763
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2764
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2765
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2766
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2767
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2768
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2769
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2770
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2771
+ });
2772
+ });
2773
+
2774
+ cy.log("move tenth vertex");
2775
+ cy.window().then(async (win) => {
2776
+ A = [-6, 7];
2777
+ A1 = [A[0] + 1, A[1] + 1];
2778
+ A2 = [A[0] + 2, A[1] + 2];
2779
+ A3 = [A[0] + 3, A[1] + 3];
2780
+
2781
+ win.callAction1({
2782
+ actionName: "movePolyline",
2783
+ componentName: "/P",
2784
+ args: {
2785
+ pointCoords: { 9: A },
2786
+ },
2787
+ });
2788
+
2789
+ cy.get(cesc("#\\/p10") + " .mjx-mrow").should(
2790
+ "contain.text",
2791
+ `(${nInDOM(A[0])},${nInDOM(A[1])})`,
2792
+ );
2793
+
2794
+ cy.window().then(async (win) => {
2795
+ let stateVariables = await win.returnAllStateVariables1();
2796
+ expect(stateVariables["/P"].stateValues.vertices[0]).eqls(A3);
2797
+ expect(stateVariables["/P"].stateValues.vertices[1]).eqls(B);
2798
+ expect(stateVariables["/P"].stateValues.vertices[2]).eqls(C);
2799
+ expect(stateVariables["/P"].stateValues.vertices[3]).eqls(A2);
2800
+ expect(stateVariables["/P"].stateValues.vertices[4]).eqls(D);
2801
+ expect(stateVariables["/P"].stateValues.vertices[5]).eqls(E);
2802
+ expect(stateVariables["/P"].stateValues.vertices[6]).eqls(A1);
2803
+ expect(stateVariables["/P"].stateValues.vertices[7]).eqls(F);
2804
+ expect(stateVariables["/P"].stateValues.vertices[8]).eqls(G);
2805
+ expect(stateVariables["/P"].stateValues.vertices[9]).eqls(A);
2806
+ });
2807
+ });
2808
+ });
2809
+
2810
+ it("attract to polyline", () => {
2811
+ cy.window().then(async (win) => {
2812
+ win.postMessage(
2813
+ {
2814
+ doenetML: `
2815
+ <text>a</text>
2816
+ <graph>
2817
+ <polyline vertices=" (3,5) (-4,-1) (5,2)" />
2818
+ <point x="7" y="8">
2819
+ <constraints>
2820
+ <attractTo><copy target="_polyline1" /></attractTo>
2821
+ </constraints>
2822
+ </point>
2823
+ </graph>
2824
+ <copy target="_point1" assignNames="p1" displayDigits="8" />
2825
+ <copy target="_polyline1" prop="vertices" assignNames="v1 v2 v3" displayDigits="8" />
2826
+ `,
2827
+ },
2828
+ "*",
2829
+ );
2830
+ });
2831
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
2832
+
2833
+ let x1 = 3,
2834
+ x2 = -4,
2835
+ x3 = 5;
2836
+ let y1 = 5,
2837
+ y2 = -1,
2838
+ y3 = 2;
2839
+
2840
+ cy.log("point originally not attracted");
2841
+
2842
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(7,8)`);
2843
+
2844
+ cy.window().then(async (win) => {
2845
+ let stateVariables = await win.returnAllStateVariables1();
2846
+ expect(stateVariables["/_point1"].stateValues.coords).eqls([
2847
+ "vector",
2848
+ 7,
2849
+ 8,
2850
+ ]);
2851
+ });
2852
+
2853
+ cy.log("move point near segment 1");
2854
+ cy.window().then(async (win) => {
2855
+ let x = 1;
2856
+ let mseg1 = (y2 - y1) / (x2 - x1);
2857
+ let y = mseg1 * (x - x1) + y1 + 0.3;
2858
+
2859
+ win.callAction1({
2860
+ actionName: "movePoint",
2861
+ componentName: `/_point1`,
2862
+ args: { x, y },
2863
+ });
2864
+
2865
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(1.14`);
2866
+
2867
+ cy.window().then(async (win) => {
2868
+ let stateVariables = await win.returnAllStateVariables1();
2869
+
2870
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2871
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2872
+
2873
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
2874
+ });
2875
+ });
2876
+
2877
+ cy.log("move point near segment 2");
2878
+ cy.window().then(async (win) => {
2879
+ let x = 3;
2880
+ let mseg2 = (y2 - y3) / (x2 - x3);
2881
+ let y = mseg2 * (x - x2) + y2 + 0.4;
2882
+
2883
+ win.callAction1({
2884
+ actionName: "movePoint",
2885
+ componentName: `/_point1`,
2886
+ args: { x, y },
2887
+ });
2888
+
2889
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(3.12`);
2890
+
2891
+ cy.window().then(async (win) => {
2892
+ let stateVariables = await win.returnAllStateVariables1();
2893
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2894
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2895
+
2896
+ expect(py).closeTo(mseg2 * (px - x2) + y2, 1e-6);
2897
+ });
2898
+ });
2899
+
2900
+ cy.log("move point near segment between first and last vertices");
2901
+ cy.window().then(async (win) => {
2902
+ let x = 4;
2903
+ let mseg3 = (y1 - y3) / (x1 - x3);
2904
+ let y = mseg3 * (x - x3) + y3 + 0.2;
2905
+
2906
+ win.callAction1({
2907
+ actionName: "movePoint",
2908
+ componentName: `/_point1`,
2909
+ args: { x, y },
2910
+ });
2911
+
2912
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(4,`);
2913
+
2914
+ cy.window().then(async (win) => {
2915
+ let stateVariables = await win.returnAllStateVariables1();
2916
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2917
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2918
+
2919
+ expect(px).closeTo(x, 1e-6);
2920
+ expect(py).closeTo(y, 1e-6);
2921
+ });
2922
+ });
2923
+
2924
+ cy.log("move point just past first vertex");
2925
+ cy.window().then(async (win) => {
2926
+ let x = x1 + 0.2;
2927
+ let y = y1 + 0.3;
2928
+
2929
+ win.callAction1({
2930
+ actionName: "movePoint",
2931
+ componentName: `/_point1`,
2932
+ args: { x, y },
2933
+ });
2934
+
2935
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(3,5)`);
2936
+
2937
+ cy.window().then(async (win) => {
2938
+ let stateVariables = await win.returnAllStateVariables1();
2939
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2940
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2941
+
2942
+ expect(px).closeTo(x1, 1e-6);
2943
+ expect(py).closeTo(y1, 1e-6);
2944
+ });
2945
+ });
2946
+
2947
+ cy.log("point not attracted along extension of first segment");
2948
+ cy.window().then(async (win) => {
2949
+ let x = 4;
2950
+ let mseg1 = (y2 - y1) / (x2 - x1);
2951
+ let y = mseg1 * (x - x1) + y1 + 0.3;
2952
+
2953
+ win.callAction1({
2954
+ actionName: "movePoint",
2955
+ componentName: `/_point1`,
2956
+ args: { x, y },
2957
+ });
2958
+
2959
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(4,`);
2960
+
2961
+ cy.window().then(async (win) => {
2962
+ let stateVariables = await win.returnAllStateVariables1();
2963
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2964
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2965
+
2966
+ expect(px).closeTo(x, 1e-6);
2967
+ expect(py).closeTo(y, 1e-6);
2968
+ });
2969
+ });
2970
+
2971
+ cy.window().then(async (win) => {
2972
+ let x = -5;
2973
+ let mseg1 = (y2 - y1) / (x2 - x1);
2974
+ let y = mseg1 * (x - x1) + y1 - 0.3;
2975
+
2976
+ win.callAction1({
2977
+ actionName: "movePoint",
2978
+ componentName: `/_point1`,
2979
+ args: { x, y },
2980
+ });
2981
+
2982
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
2983
+ "contain.text",
2984
+ `(${nInDOM(-5)},`,
2985
+ );
2986
+
2987
+ cy.window().then(async (win) => {
2988
+ let stateVariables = await win.returnAllStateVariables1();
2989
+ let px = stateVariables["/_point1"].stateValues.xs[0];
2990
+ let py = stateVariables["/_point1"].stateValues.xs[1];
2991
+
2992
+ expect(px).closeTo(x, 1e-6);
2993
+ expect(py).closeTo(y, 1e-6);
2994
+ });
2995
+ });
2996
+
2997
+ cy.log("move point just past second vertex");
2998
+ cy.window().then(async (win) => {
2999
+ let x = x2 - 0.2;
3000
+ let y = y2 - 0.3;
3001
+
3002
+ win.callAction1({
3003
+ actionName: "movePoint",
3004
+ componentName: `/_point1`,
3005
+ args: { x, y },
3006
+ });
3007
+
3008
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3009
+ "contain.text",
3010
+ `(${nInDOM(-4)},`,
3011
+ );
3012
+
3013
+ cy.window().then(async (win) => {
3014
+ let stateVariables = await win.returnAllStateVariables1();
3015
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3016
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3017
+
3018
+ expect(px).closeTo(x2, 1e-6);
3019
+ expect(py).closeTo(y2, 1e-6);
3020
+ });
3021
+ });
3022
+
3023
+ cy.log("point not attracted along extension of second segment");
3024
+ cy.window().then(async (win) => {
3025
+ let x = 6;
3026
+ let mseg2 = (y2 - y3) / (x2 - x3);
3027
+ let y = mseg2 * (x - x2) + y2 + 0.3;
3028
+
3029
+ win.callAction1({
3030
+ actionName: "movePoint",
3031
+ componentName: `/_point1`,
3032
+ args: { x, y },
3033
+ });
3034
+
3035
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(6,`);
3036
+
3037
+ cy.window().then(async (win) => {
3038
+ let stateVariables = await win.returnAllStateVariables1();
3039
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3040
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3041
+
3042
+ expect(px).closeTo(x, 1e-6);
3043
+ expect(py).closeTo(y, 1e-6);
3044
+ });
3045
+ });
3046
+
3047
+ cy.window().then(async (win) => {
3048
+ let x = -5;
3049
+ let mseg2 = (y2 - y3) / (x2 - x3);
3050
+ let y = mseg2 * (x - x2) + y2 - 0.3;
3051
+
3052
+ win.callAction1({
3053
+ actionName: "movePoint",
3054
+ componentName: `/_point1`,
3055
+ args: { x, y },
3056
+ });
3057
+
3058
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3059
+ "contain.text",
3060
+ `(${nInDOM(-5)},`,
3061
+ );
3062
+
3063
+ cy.window().then(async (win) => {
3064
+ let stateVariables = await win.returnAllStateVariables1();
3065
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3066
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3067
+
3068
+ expect(px).closeTo(x, 1e-6);
3069
+ expect(py).closeTo(y, 1e-6);
3070
+ });
3071
+ });
3072
+
3073
+ cy.log("move polyline so point attracts to first segment");
3074
+ cy.window().then(async (win) => {
3075
+ let moveX = -3;
3076
+ let moveY = -2;
3077
+
3078
+ x1 += moveX;
3079
+ x2 += moveX;
3080
+ x3 += moveX;
3081
+ y1 += moveY;
3082
+ y2 += moveY;
3083
+ y3 += moveY;
3084
+
3085
+ win.callAction1({
3086
+ actionName: "movePolyline",
3087
+ componentName: "/_polyline1",
3088
+ args: {
3089
+ pointCoords: [
3090
+ [x1, y1],
3091
+ [x2, y2],
3092
+ [x3, y3],
3093
+ ],
3094
+ },
3095
+ });
3096
+
3097
+ cy.get(cesc("#\\/v1") + " .mjx-mrow").should(
3098
+ "contain.text",
3099
+ `(${nInDOM(x1)},${nInDOM(y1)})`,
3100
+ );
3101
+
3102
+ cy.window().then(async (win) => {
3103
+ let stateVariables = await win.returnAllStateVariables1();
3104
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3105
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3106
+
3107
+ let mseg1 = (y2 - y1) / (x2 - x1);
3108
+
3109
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
3110
+ });
3111
+ });
3112
+
3113
+ cy.log("move second vertex so point attracts to second segment");
3114
+ cy.window().then(async (win) => {
3115
+ let moveX = -1;
3116
+ let moveY = 1;
3117
+
3118
+ x2 += moveX;
3119
+ y2 += moveY;
3120
+
3121
+ win.callAction1({
3122
+ actionName: "movePolyline",
3123
+ componentName: "/_polyline1",
3124
+ args: {
3125
+ pointCoords: { 1: [x2, y2] },
3126
+ },
3127
+ });
3128
+
3129
+ cy.get(cesc("#\\/v2") + " .mjx-mrow").should(
3130
+ "contain.text",
3131
+ `(${nInDOM(x2)},${nInDOM(y2)})`,
3132
+ );
3133
+
3134
+ cy.window().then(async (win) => {
3135
+ let stateVariables = await win.returnAllStateVariables1();
3136
+
3137
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3138
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3139
+
3140
+ let mseg2 = (y2 - y3) / (x2 - x3);
3141
+
3142
+ expect(py).closeTo(mseg2 * (px - x2) + y2, 1e-6);
3143
+ });
3144
+ });
3145
+ });
3146
+
3147
+ it("constrain to polyline", () => {
3148
+ cy.window().then(async (win) => {
3149
+ win.postMessage(
3150
+ {
3151
+ doenetML: `
3152
+ <text>a</text>
3153
+ <graph>
3154
+ <polyline vertices=" (3,5) (-4,-1) (5,2)" />
3155
+ <point x="7" y="8">
3156
+ <constraints>
3157
+ <constrainTo><copy target="_polyline1" /></constrainTo>
3158
+ </constraints>
3159
+ </point>
3160
+ </graph>
3161
+ <copy target="_point1" assignNames="p1" displayDigits="8" />
3162
+ <copy target="_polyline1" prop="vertices" assignNames="v1 v2 v3" displayDigits="8" />
3163
+ `,
3164
+ },
3165
+ "*",
3166
+ );
3167
+ });
3168
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
3169
+
3170
+ let x1 = 3,
3171
+ x2 = -4,
3172
+ x3 = 5;
3173
+ let y1 = 5,
3174
+ y2 = -1,
3175
+ y3 = 2;
3176
+
3177
+ cy.log("point originally constrained");
3178
+
3179
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3180
+ "contain.text",
3181
+ `(${nInDOM(x1)},${nInDOM(y1)})`,
3182
+ );
3183
+
3184
+ cy.window().then(async (win) => {
3185
+ let stateVariables = await win.returnAllStateVariables1();
3186
+ expect(stateVariables["/_point1"].stateValues.coords).eqls([
3187
+ "vector",
3188
+ x1,
3189
+ y1,
3190
+ ]);
3191
+ });
3192
+
3193
+ cy.log("move point near segment 1");
3194
+ cy.window().then(async (win) => {
3195
+ let x = 1;
3196
+ let mseg1 = (y2 - y1) / (x2 - x1);
3197
+ let y = mseg1 * (x - x1) + y1 + 0.3;
3198
+
3199
+ win.callAction1({
3200
+ actionName: "movePoint",
3201
+ componentName: `/_point1`,
3202
+ args: { x, y },
3203
+ });
3204
+
3205
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(1.14`);
3206
+
3207
+ cy.window().then(async (win) => {
3208
+ let stateVariables = await win.returnAllStateVariables1();
3209
+
3210
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3211
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3212
+
3213
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
3214
+ });
3215
+ });
3216
+
3217
+ cy.log("move point near segment 2");
3218
+ cy.window().then(async (win) => {
3219
+ let x = 3;
3220
+ let mseg2 = (y2 - y3) / (x2 - x3);
3221
+ let y = mseg2 * (x - x2) + y2 + 0.4;
3222
+
3223
+ win.callAction1({
3224
+ actionName: "movePoint",
3225
+ componentName: `/_point1`,
3226
+ args: { x, y },
3227
+ });
3228
+
3229
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(3.12`);
3230
+
3231
+ cy.window().then(async (win) => {
3232
+ let stateVariables = await win.returnAllStateVariables1();
3233
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3234
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3235
+
3236
+ expect(py).closeTo(mseg2 * (px - x2) + y2, 1e-6);
3237
+ });
3238
+ });
3239
+
3240
+ cy.log("move point near segment between first and last vertices");
3241
+ cy.window().then(async (win) => {
3242
+ let x = 4;
3243
+ let mseg3 = (y1 - y3) / (x1 - x3);
3244
+ let y = mseg3 * (x - x3) + y3 + 0.2;
3245
+
3246
+ win.callAction1({
3247
+ actionName: "movePoint",
3248
+ componentName: `/_point1`,
3249
+ args: { x, y },
3250
+ });
3251
+
3252
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(2.93`);
3253
+
3254
+ cy.window().then(async (win) => {
3255
+ let stateVariables = await win.returnAllStateVariables1();
3256
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3257
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3258
+ let mseg1 = (y2 - y1) / (x2 - x1);
3259
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
3260
+ });
3261
+ });
3262
+
3263
+ cy.log("move point just past first vertex");
3264
+ cy.window().then(async (win) => {
3265
+ let x = x1 + 0.2;
3266
+ let y = y1 + 0.3;
3267
+
3268
+ win.callAction1({
3269
+ actionName: "movePoint",
3270
+ componentName: `/_point1`,
3271
+ args: { x, y },
3272
+ });
3273
+
3274
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should("contain.text", `(3,5)`);
3275
+
3276
+ cy.window().then(async (win) => {
3277
+ let stateVariables = await win.returnAllStateVariables1();
3278
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3279
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3280
+
3281
+ expect(px).closeTo(x1, 1e-6);
3282
+ expect(py).closeTo(y1, 1e-6);
3283
+ });
3284
+ });
3285
+
3286
+ cy.log("point along extension of first segment constrained to endpoint");
3287
+ cy.window().then(async (win) => {
3288
+ let x = 4;
3289
+ let mseg1 = (y2 - y1) / (x2 - x1);
3290
+ let y = mseg1 * (x - x1) + y1 + 0.3;
3291
+
3292
+ win.callAction1({
3293
+ actionName: "movePoint",
3294
+ componentName: `/_point1`,
3295
+ args: { x, y },
3296
+ });
3297
+
3298
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3299
+ "contain.text",
3300
+ `(${nInDOM(x1)},${nInDOM(y1)})`,
3301
+ );
3302
+
3303
+ cy.window().then(async (win) => {
3304
+ let stateVariables = await win.returnAllStateVariables1();
3305
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3306
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3307
+
3308
+ expect(px).closeTo(x1, 1e-6);
3309
+ expect(py).closeTo(y1, 1e-6);
3310
+ });
3311
+ });
3312
+
3313
+ cy.window().then(async (win) => {
3314
+ let x = -5;
3315
+ let mseg1 = (y2 - y1) / (x2 - x1);
3316
+ let y = mseg1 * (x - x1) + y1 - 0.3;
3317
+
3318
+ win.callAction1({
3319
+ actionName: "movePoint",
3320
+ componentName: `/_point1`,
3321
+ args: { x, y },
3322
+ });
3323
+
3324
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3325
+ "contain.text",
3326
+ `(${nInDOM(x2)},${nInDOM(y2)})`,
3327
+ );
3328
+
3329
+ cy.window().then(async (win) => {
3330
+ let stateVariables = await win.returnAllStateVariables1();
3331
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3332
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3333
+
3334
+ expect(px).closeTo(x2, 1e-6);
3335
+ expect(py).closeTo(y2, 1e-6);
3336
+ });
3337
+ });
3338
+
3339
+ cy.log("move point just past second vertex");
3340
+ cy.window().then(async (win) => {
3341
+ let x = x2 - 0.2;
3342
+ let y = y2 - 0.3;
3343
+
3344
+ win.callAction1({
3345
+ actionName: "movePoint",
3346
+ componentName: `/_point1`,
3347
+ args: { x, y },
3348
+ });
3349
+
3350
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3351
+ "contain.text",
3352
+ `(${nInDOM(x2)},${nInDOM(y2)})`,
3353
+ );
3354
+
3355
+ cy.window().then(async (win) => {
3356
+ let stateVariables = await win.returnAllStateVariables1();
3357
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3358
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3359
+
3360
+ expect(px).closeTo(x2, 1e-6);
3361
+ expect(py).closeTo(y2, 1e-6);
3362
+ });
3363
+ });
3364
+
3365
+ cy.log("point along extension of second segment constrained to endpoint");
3366
+ cy.window().then(async (win) => {
3367
+ let x = 6;
3368
+ let mseg2 = (y2 - y3) / (x2 - x3);
3369
+ let y = mseg2 * (x - x2) + y2 + 0.3;
3370
+
3371
+ win.callAction1({
3372
+ actionName: "movePoint",
3373
+ componentName: `/_point1`,
3374
+ args: { x, y },
3375
+ });
3376
+
3377
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3378
+ "contain.text",
3379
+ `(${nInDOM(x3)},${nInDOM(y3)})`,
3380
+ );
3381
+
3382
+ cy.window().then(async (win) => {
3383
+ let stateVariables = await win.returnAllStateVariables1();
3384
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3385
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3386
+
3387
+ expect(px).closeTo(x3, 1e-6);
3388
+ expect(py).closeTo(y3, 1e-6);
3389
+ });
3390
+ });
3391
+
3392
+ cy.window().then(async (win) => {
3393
+ let x = -5;
3394
+ let mseg2 = (y2 - y3) / (x2 - x3);
3395
+ let y = mseg2 * (x - x2) + y2 - 0.3;
3396
+
3397
+ win.callAction1({
3398
+ actionName: "movePoint",
3399
+ componentName: `/_point1`,
3400
+ args: { x, y },
3401
+ });
3402
+
3403
+ cy.get(cesc("#\\/p1") + " .mjx-mrow").should(
3404
+ "contain.text",
3405
+ `(${nInDOM(x2)},${nInDOM(y2)})`,
3406
+ );
3407
+
3408
+ cy.window().then(async (win) => {
3409
+ let stateVariables = await win.returnAllStateVariables1();
3410
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3411
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3412
+
3413
+ expect(px).closeTo(x2, 1e-6);
3414
+ expect(py).closeTo(y2, 1e-6);
3415
+ });
3416
+ });
3417
+
3418
+ cy.log("move polyline so point constrained to first segment");
3419
+ cy.window().then(async (win) => {
3420
+ let moveX = -3;
3421
+ let moveY = -5;
3422
+
3423
+ x1 += moveX;
3424
+ x2 += moveX;
3425
+ x3 += moveX;
3426
+ y1 += moveY;
3427
+ y2 += moveY;
3428
+ y3 += moveY;
3429
+
3430
+ win.callAction1({
3431
+ actionName: "movePolyline",
3432
+ componentName: "/_polyline1",
3433
+ args: {
3434
+ pointCoords: [
3435
+ [x1, y1],
3436
+ [x2, y2],
3437
+ [x3, y3],
3438
+ ],
3439
+ },
3440
+ });
3441
+
3442
+ cy.get(cesc("#\\/v1") + " .mjx-mrow").should(
3443
+ "contain.text",
3444
+ `(${nInDOM(x1)},${nInDOM(y1)})`,
3445
+ );
3446
+
3447
+ cy.window().then(async (win) => {
3448
+ let stateVariables = await win.returnAllStateVariables1();
3449
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3450
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3451
+
3452
+ let mseg1 = (y2 - y1) / (x2 - x1);
3453
+
3454
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
3455
+ });
3456
+ });
3457
+
3458
+ cy.log("move second vertex so point constrained to second segment");
3459
+ cy.window().then(async (win) => {
3460
+ let moveX = -1;
3461
+ let moveY = 8;
3462
+
3463
+ x2 += moveX;
3464
+ y2 += moveY;
3465
+
3466
+ win.callAction1({
3467
+ actionName: "movePolyline",
3468
+ componentName: "/_polyline1",
3469
+ args: {
3470
+ pointCoords: { 1: [x2, y2] },
3471
+ },
3472
+ });
3473
+
3474
+ cy.get(cesc("#\\/v2") + " .mjx-mrow").should(
3475
+ "contain.text",
3476
+ `(${nInDOM(x2)},${nInDOM(y2)})`,
3477
+ );
3478
+
3479
+ cy.window().then(async (win) => {
3480
+ let stateVariables = await win.returnAllStateVariables1();
3481
+
3482
+ let px = stateVariables["/_point1"].stateValues.xs[0];
3483
+ let py = stateVariables["/_point1"].stateValues.xs[1];
3484
+
3485
+ let mseg2 = (y2 - y3) / (x2 - x3);
3486
+
3487
+ expect(py).closeTo(mseg2 * (px - x2) + y2, 1e-6);
3488
+ });
3489
+ });
3490
+ });
3491
+
3492
+ it("constrain to polyline, different scales from graph", () => {
3493
+ cy.window().then(async (win) => {
3494
+ win.postMessage(
3495
+ {
3496
+ doenetML: `
3497
+ <text>a</text>
3498
+ <graph xmin="-110" xmax="110" ymin="-0.11" ymax="0.11">
3499
+ <polyline vertices="(-50,-0.02) (-40,0.07) (70,0.06) (10,-0.01)" name="p" />
3500
+ <point x="0" y="0.01" name="A">
3501
+ <constraints>
3502
+ <constrainTo relativeToGraphScales><copy target="p" /></constrainTo>
3503
+ </constraints>
3504
+ </point>
3505
+ </graph>
3506
+ <copy target="A" assignNames="A2" />
3507
+ `,
3508
+ },
3509
+ "*",
3510
+ );
3511
+ });
3512
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
3513
+
3514
+ let x1 = -50,
3515
+ x2 = -40,
3516
+ x3 = 70,
3517
+ x4 = 10;
3518
+ let y1 = -0.02,
3519
+ y2 = 0.07,
3520
+ y3 = 0.06,
3521
+ y4 = -0.01;
3522
+
3523
+ cy.log("point originally on segment 3");
3524
+
3525
+ cy.get(cesc("#\\/A2") + " .mjx-mrow").should(
3526
+ "contain.text",
3527
+ `(${nInDOM(15)}`,
3528
+ );
3529
+
3530
+ cy.window().then(async (win) => {
3531
+ let stateVariables = await win.returnAllStateVariables1();
3532
+
3533
+ let mseg3 = (y4 - y3) / (x4 - x3);
3534
+
3535
+ let px = stateVariables["/A"].stateValues.xs[0];
3536
+ let py = stateVariables["/A"].stateValues.xs[1];
3537
+
3538
+ expect(py).closeTo(mseg3 * (px - x3) + y3, 1e-6);
3539
+ });
3540
+
3541
+ cy.log("move point near segment 1");
3542
+ cy.window().then(async (win) => {
3543
+ let mseg1 = (y2 - y1) / (x2 - x1);
3544
+
3545
+ win.callAction1({
3546
+ actionName: "movePoint",
3547
+ componentName: `/A`,
3548
+ args: { x: -20, y: 0.02 },
3549
+ });
3550
+
3551
+ cy.get(cesc("#\\/A2") + " .mjx-mrow").should(
3552
+ "contain.text",
3553
+ `(${nInDOM(-45)}`,
3554
+ );
3555
+
3556
+ cy.window().then(async (win) => {
3557
+ let stateVariables = await win.returnAllStateVariables1();
3558
+ let px = stateVariables["/A"].stateValues.xs[0];
3559
+ let py = stateVariables["/A"].stateValues.xs[1];
3560
+
3561
+ expect(py).closeTo(mseg1 * (px - x1) + y1, 1e-6);
3562
+ });
3563
+ });
3564
+
3565
+ cy.log("move point near segment 2");
3566
+ cy.window().then(async (win) => {
3567
+ let mseg2 = (y2 - y3) / (x2 - x3);
3568
+
3569
+ win.callAction1({
3570
+ actionName: "movePoint",
3571
+ componentName: `/A`,
3572
+ args: { x: 0, y: 0.04 },
3573
+ });
3574
+
3575
+ cy.get(cesc("#\\/A2") + " .mjx-mrow").should(
3576
+ "contain.text",
3577
+ `(${nInDOM(2.3)}`,
3578
+ );
3579
+
3580
+ cy.window().then(async (win) => {
3581
+ let stateVariables = await win.returnAllStateVariables1();
3582
+ let px = stateVariables["/A"].stateValues.xs[0];
3583
+ let py = stateVariables["/A"].stateValues.xs[1];
3584
+
3585
+ expect(py).closeTo(mseg2 * (px - x2) + y2, 1e-6);
3586
+ });
3587
+ });
3588
+
3589
+ cy.log("move point near segement between first and last vertices");
3590
+ cy.window().then(async (win) => {
3591
+ let mseg3 = (y4 - y3) / (x4 - x3);
3592
+
3593
+ win.callAction1({
3594
+ actionName: "movePoint",
3595
+ componentName: `/A`,
3596
+ args: { x: -10, y: 0.02 },
3597
+ });
3598
+
3599
+ cy.get(cesc("#\\/A2") + " .mjx-mrow").should(
3600
+ "contain.text",
3601
+ `(${nInDOM(16)}`,
3602
+ );
3603
+
3604
+ cy.window().then(async (win) => {
3605
+ let stateVariables = await win.returnAllStateVariables1();
3606
+ let px = stateVariables["/A"].stateValues.xs[0];
3607
+ let py = stateVariables["/A"].stateValues.xs[1];
3608
+
3609
+ expect(py).closeTo(mseg3 * (px - x3) + y3, 1e-6);
3610
+ });
3611
+ });
3612
+ });
3613
+
3614
+ it("fixed polyline", () => {
3615
+ cy.window().then(async (win) => {
3616
+ win.postMessage(
3617
+ {
3618
+ doenetML: `
3619
+ <text>a</text>
3620
+ <graph>
3621
+ <polyline vertices="(1,3) (5,7) (-2,6)" name="p" fixed />
3622
+ </graph>
3623
+ <textinput name="ti" />
3624
+ <copy prop="value" target="ti" assignNames="t" />
3625
+ `,
3626
+ },
3627
+ "*",
3628
+ );
3629
+ });
3630
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
3631
+
3632
+ cy.window().then(async (win) => {
3633
+ let stateVariables = await win.returnAllStateVariables1();
3634
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([1, 3]);
3635
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
3636
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
3637
+ expect(stateVariables["/p"].stateValues.fixed).eq(true);
3638
+ });
3639
+
3640
+ cy.log("cannot move vertices");
3641
+ cy.window().then(async (win) => {
3642
+ win.callAction1({
3643
+ actionName: "movePolyline",
3644
+ componentName: "/p",
3645
+ args: {
3646
+ pointCoords: [
3647
+ [4, 7],
3648
+ [8, 10],
3649
+ [1, 9],
3650
+ ],
3651
+ },
3652
+ });
3653
+
3654
+ // to make sure waited for core to react,
3655
+ // wait for text to change from change in textinput
3656
+ cy.get(cesc("#\\/ti_input")).type("wait{enter}");
3657
+ cy.get(cesc("#\\/t")).should("have.text", "wait");
3658
+
3659
+ cy.window().then(async (win) => {
3660
+ let stateVariables = await win.returnAllStateVariables1();
3661
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([1, 3]);
3662
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
3663
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
3664
+ });
3665
+ });
3666
+ });
3667
+
3668
+ it("copy propIndex of vertices", () => {
3669
+ cy.window().then(async (win) => {
3670
+ win.postMessage(
3671
+ {
3672
+ doenetML: `
3673
+ <text>a</text>
3674
+ <graph>
3675
+ <polyline vertices="(2,-3) (3,4) (-3,4)" />
3676
+ </graph>
3677
+
3678
+ <p><mathinput name="n" /></p>
3679
+
3680
+ <p><copy prop="vertices" target="_polyline1" propIndex="$n" assignNames="P1 P2 P3" /></p>
3681
+
3682
+ <p><copy prop="vertex2" target="_polyline1" propIndex="$n" assignNames="x" /></p>
3683
+ `,
3684
+ },
3685
+ "*",
3686
+ );
3687
+ });
3688
+
3689
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
3690
+
3691
+ let t1x = 2,
3692
+ t1y = -3;
3693
+ let t2x = 3,
3694
+ t2y = 4;
3695
+ let t3x = -3,
3696
+ t3y = 4;
3697
+
3698
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should("not.exist");
3699
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3700
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3701
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3702
+
3703
+ cy.get(cesc("#\\/n") + " textarea").type("1{enter}", { force: true });
3704
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3705
+ "contain.text",
3706
+ `(${nInDOM(t1x)},${nInDOM(t1y)})`,
3707
+ );
3708
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3709
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3710
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should(
3711
+ "contain.text",
3712
+ `${nInDOM(t2x)}`,
3713
+ );
3714
+
3715
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}2{enter}", {
3716
+ force: true,
3717
+ });
3718
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3719
+ "contain.text",
3720
+ `(${nInDOM(t2x)},${nInDOM(t2y)})`,
3721
+ );
3722
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3723
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3724
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should(
3725
+ "contain.text",
3726
+ `${nInDOM(t2y)}`,
3727
+ );
3728
+
3729
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}3{enter}", {
3730
+ force: true,
3731
+ });
3732
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3733
+ "contain.text",
3734
+ `(${nInDOM(t3x)},${nInDOM(t3y)})`,
3735
+ );
3736
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3737
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3738
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3739
+
3740
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}4{enter}", {
3741
+ force: true,
3742
+ });
3743
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should("not.exist");
3744
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3745
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3746
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3747
+ });
3748
+
3749
+ it("copy propIndex of vertices, dot and array notation", () => {
3750
+ cy.window().then(async (win) => {
3751
+ win.postMessage(
3752
+ {
3753
+ doenetML: `
3754
+ <text>a</text>
3755
+ <graph>
3756
+ <polyline vertices="(2,-3) (3,4) (-3,4)" />
3757
+ </graph>
3758
+
3759
+ <p><mathinput name="n" /></p>
3760
+
3761
+ <p><copy source="_polyline1.vertices[$n]" assignNames="P1 P2 P3" /></p>
3762
+
3763
+ <p><copy source="_polyline1.vertex2[$n]" assignNames="x" /></p>
3764
+
3765
+ <p><copy source="_polyline1.vertices[2][$n]" assignNames="xa" /></p>
3766
+ `,
3767
+ },
3768
+ "*",
3769
+ );
3770
+ });
3771
+
3772
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
3773
+
3774
+ let t1x = 2,
3775
+ t1y = -3;
3776
+ let t2x = 3,
3777
+ t2y = 4;
3778
+ let t3x = -3,
3779
+ t3y = 4;
3780
+
3781
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should("not.exist");
3782
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3783
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3784
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3785
+ cy.get(cesc("#\\/xa") + " .mjx-mrow").should("not.exist");
3786
+
3787
+ cy.get(cesc("#\\/n") + " textarea").type("1{enter}", { force: true });
3788
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3789
+ "contain.text",
3790
+ `(${nInDOM(t1x)},${nInDOM(t1y)})`,
3791
+ );
3792
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3793
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3794
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should(
3795
+ "contain.text",
3796
+ `${nInDOM(t2x)}`,
3797
+ );
3798
+ cy.get(cesc("#\\/xa") + " .mjx-mrow").should(
3799
+ "contain.text",
3800
+ `${nInDOM(t2x)}`,
3801
+ );
3802
+
3803
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}2{enter}", {
3804
+ force: true,
3805
+ });
3806
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3807
+ "contain.text",
3808
+ `(${nInDOM(t2x)},${nInDOM(t2y)})`,
3809
+ );
3810
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3811
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3812
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should(
3813
+ "contain.text",
3814
+ `${nInDOM(t2y)}`,
3815
+ );
3816
+ cy.get(cesc("#\\/xa") + " .mjx-mrow").should(
3817
+ "contain.text",
3818
+ `${nInDOM(t2y)}`,
3819
+ );
3820
+
3821
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}3{enter}", {
3822
+ force: true,
3823
+ });
3824
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should(
3825
+ "contain.text",
3826
+ `(${nInDOM(t3x)},${nInDOM(t3y)})`,
3827
+ );
3828
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3829
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3830
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3831
+ cy.get(cesc("#\\/xa") + " .mjx-mrow").should("not.exist");
3832
+
3833
+ cy.get(cesc("#\\/n") + " textarea").type("{end}{backspace}4{enter}", {
3834
+ force: true,
3835
+ });
3836
+ cy.get(cesc("#\\/P1") + " .mjx-mrow").should("not.exist");
3837
+ cy.get(cesc("#\\/P2") + " .mjx-mrow").should("not.exist");
3838
+ cy.get(cesc("#\\/P3") + " .mjx-mrow").should("not.exist");
3839
+ cy.get(cesc("#\\/x") + " .mjx-mrow").should("not.exist");
3840
+ cy.get(cesc("#\\/xa") + " .mjx-mrow").should("not.exist");
3841
+ });
3842
+
3843
+ it("polyline from vector operations", () => {
3844
+ cy.window().then(async (win) => {
3845
+ win.postMessage(
3846
+ {
3847
+ doenetML: `
3848
+ <text>a</text>
3849
+ <math name="m" fixed>(-3,2)</math>
3850
+ <graph>
3851
+ <point name="P">(2,1)</point>
3852
+ <polyline vertices="2(2,-3)+(3,4) 3$P $P+2$m" name="polyline" />
3853
+ </graph>
3854
+
3855
+ <p><copy source="polyline.vertices" assignNames="P1 P2 P3" /></p>
3856
+
3857
+ `,
3858
+ },
3859
+ "*",
3860
+ );
3861
+ });
3862
+
3863
+ cy.get(cesc2("#/m") + " .mjx-mrow")
3864
+ .eq(0)
3865
+ .should("have.text", "(−3,2)");
3866
+ cy.get(cesc2("#/P1") + " .mjx-mrow")
3867
+ .eq(0)
3868
+ .should("have.text", "(7,−2)");
3869
+ cy.get(cesc2("#/P2") + " .mjx-mrow")
3870
+ .eq(0)
3871
+ .should("have.text", "(6,3)");
3872
+ cy.get(cesc2("#/P3") + " .mjx-mrow")
3873
+ .eq(0)
3874
+ .should("have.text", "(−4,5)");
3875
+
3876
+ cy.window().then(async (win) => {
3877
+ let stateVariables = await win.returnAllStateVariables1();
3878
+ expect(stateVariables["/polyline"].stateValues.vertices).eqls([
3879
+ [7, -2],
3880
+ [6, 3],
3881
+ [-4, 5],
3882
+ ]);
3883
+ });
3884
+
3885
+ cy.window().then(async (win) => {
3886
+ win.callAction1({
3887
+ actionName: "movePolyline",
3888
+ componentName: "/polyline",
3889
+ args: {
3890
+ pointCoords: { 0: [3, 5] },
3891
+ },
3892
+ });
3893
+ });
3894
+
3895
+ cy.get(cesc2("#/P1") + " .mjx-mrow").should("contain.text", "(3,5)");
3896
+ cy.get(cesc2("#/P2") + " .mjx-mrow").should("contain.text", "(6,3)");
3897
+ cy.get(cesc2("#/P3") + " .mjx-mrow").should("contain.text", "(−4,5)");
3898
+
3899
+ cy.window().then(async (win) => {
3900
+ let stateVariables = await win.returnAllStateVariables1();
3901
+ expect(stateVariables["/polyline"].stateValues.vertices).eqls([
3902
+ [3, 5],
3903
+ [6, 3],
3904
+ [-4, 5],
3905
+ ]);
3906
+ });
3907
+
3908
+ cy.window().then(async (win) => {
3909
+ win.callAction1({
3910
+ actionName: "movePolyline",
3911
+ componentName: "/polyline",
3912
+ args: {
3913
+ pointCoords: { 1: [-9, -6] },
3914
+ },
3915
+ });
3916
+ });
3917
+
3918
+ cy.get(cesc2("#/P1") + " .mjx-mrow").should("contain.text", "(3,5)");
3919
+ cy.get(cesc2("#/P2") + " .mjx-mrow").should("contain.text", "(−9,−6)");
3920
+ cy.get(cesc2("#/P3") + " .mjx-mrow").should("contain.text", "(−9,2)");
3921
+
3922
+ cy.window().then(async (win) => {
3923
+ win.callAction1({
3924
+ actionName: "movePolyline",
3925
+ componentName: "/polyline",
3926
+ args: {
3927
+ pointCoords: { 2: [-3, 1] },
3928
+ },
3929
+ });
3930
+ });
3931
+
3932
+ cy.get(cesc2("#/P1") + " .mjx-mrow").should("contain.text", "(3,5)");
3933
+ cy.get(cesc2("#/P2") + " .mjx-mrow").should("contain.text", "(9,−9)");
3934
+ cy.get(cesc2("#/P3") + " .mjx-mrow").should("contain.text", "(−3,1)");
3935
+ });
3936
+
3937
+ it("draggable, vertices draggable", () => {
3938
+ cy.window().then(async (win) => {
3939
+ win.postMessage(
3940
+ {
3941
+ doenetML: `
3942
+ <graph>
3943
+ <polyline vertices="(1,3) (5,7) (-2,6)" name="p" draggable="$draggable" verticesDraggable="$verticesDraggable" />
3944
+ </graph>
3945
+ <p>To wait: <booleaninput name="bi" /> <boolean copySource="bi" name="bi2" /></p>
3946
+ <p>draggable: <booleaninput name="draggable" /> <boolean copySource="p.draggable" name="d2" /></p>
3947
+ <p>vertices draggable: <booleaninput name="verticesDraggable" /> <boolean copySource="p.verticesDraggable" name="vd2" /></p>
3948
+ <p name="pvert">all vertices: $p.vertices</p>
3949
+ `,
3950
+ },
3951
+ "*",
3952
+ );
3953
+ });
3954
+
3955
+ cy.get(cesc("#\\/d2")).should("have.text", "false");
3956
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
3957
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
3958
+ .eq(0)
3959
+ .should("have.text", "(1,3)");
3960
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
3961
+ .eq(2)
3962
+ .should("have.text", "(5,7)");
3963
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
3964
+ .eq(4)
3965
+ .should("have.text", "(−2,6)");
3966
+
3967
+ cy.window().then(async (win) => {
3968
+ let stateVariables = await win.returnAllStateVariables1();
3969
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([1, 3]);
3970
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
3971
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
3972
+ expect(stateVariables["/p"].stateValues.draggable).eq(false);
3973
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(false);
3974
+ });
3975
+
3976
+ cy.log("cannot move single vertex");
3977
+ cy.window().then(async (win) => {
3978
+ await win.callAction1({
3979
+ actionName: "movePolyline",
3980
+ componentName: "/p",
3981
+ args: {
3982
+ pointCoords: { 0: [4, 7] },
3983
+ },
3984
+ });
3985
+ });
3986
+
3987
+ // wait for core to process click
3988
+ cy.get(cesc("#\\/bi")).click();
3989
+ cy.get(cesc("#\\/bi2")).should("have.text", "true");
3990
+
3991
+ cy.get(cesc("#\\/d2")).should("have.text", "false");
3992
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
3993
+
3994
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
3995
+ .eq(0)
3996
+ .should("have.text", "(1,3)");
3997
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
3998
+ .eq(2)
3999
+ .should("have.text", "(5,7)");
4000
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4001
+ .eq(4)
4002
+ .should("have.text", "(−2,6)");
4003
+
4004
+ cy.window().then(async (win) => {
4005
+ let stateVariables = await win.returnAllStateVariables1();
4006
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([1, 3]);
4007
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
4008
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
4009
+ expect(stateVariables["/p"].stateValues.draggable).eq(false);
4010
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(false);
4011
+ });
4012
+
4013
+ cy.log("cannot move all vertices");
4014
+ cy.window().then(async (win) => {
4015
+ await win.callAction1({
4016
+ actionName: "movePolyline",
4017
+ componentName: "/p",
4018
+ args: {
4019
+ pointCoords: [
4020
+ [4, 7],
4021
+ [8, 10],
4022
+ [1, 9],
4023
+ ],
4024
+ },
4025
+ });
4026
+ });
4027
+
4028
+ // wait for core to process click
4029
+ cy.get(cesc("#\\/bi")).click();
4030
+ cy.get(cesc("#\\/bi2")).should("have.text", "false");
4031
+
4032
+ cy.get(cesc("#\\/d2")).should("have.text", "false");
4033
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
4034
+
4035
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4036
+ .eq(0)
4037
+ .should("have.text", "(1,3)");
4038
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4039
+ .eq(2)
4040
+ .should("have.text", "(5,7)");
4041
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4042
+ .eq(4)
4043
+ .should("have.text", "(−2,6)");
4044
+
4045
+ cy.window().then(async (win) => {
4046
+ let stateVariables = await win.returnAllStateVariables1();
4047
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([1, 3]);
4048
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
4049
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
4050
+ expect(stateVariables["/p"].stateValues.draggable).eq(false);
4051
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(false);
4052
+ });
4053
+
4054
+ cy.log("only vertices draggable");
4055
+
4056
+ cy.get(cesc("#\\/verticesDraggable")).click();
4057
+ cy.get(cesc("#\\/vd2")).should("have.text", "true");
4058
+
4059
+ cy.log("can move single vertex");
4060
+ cy.window().then(async (win) => {
4061
+ await win.callAction1({
4062
+ actionName: "movePolyline",
4063
+ componentName: "/p",
4064
+ args: {
4065
+ pointCoords: { 0: [4, 7] },
4066
+ },
4067
+ });
4068
+ });
4069
+
4070
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow").should("contain.text", "(4,7)");
4071
+
4072
+ cy.get(cesc("#\\/d2")).should("have.text", "false");
4073
+ cy.get(cesc("#\\/vd2")).should("have.text", "true");
4074
+
4075
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4076
+ .eq(0)
4077
+ .should("have.text", "(4,7)");
4078
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4079
+ .eq(2)
4080
+ .should("have.text", "(5,7)");
4081
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4082
+ .eq(4)
4083
+ .should("have.text", "(−2,6)");
4084
+
4085
+ cy.window().then(async (win) => {
4086
+ let stateVariables = await win.returnAllStateVariables1();
4087
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([4, 7]);
4088
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
4089
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
4090
+ expect(stateVariables["/p"].stateValues.draggable).eq(false);
4091
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(true);
4092
+ });
4093
+
4094
+ cy.log("cannot move all vertices");
4095
+ cy.window().then(async (win) => {
4096
+ await win.callAction1({
4097
+ actionName: "movePolyline",
4098
+ componentName: "/p",
4099
+ args: {
4100
+ pointCoords: [
4101
+ [3, 8],
4102
+ [8, 10],
4103
+ [1, 9],
4104
+ ],
4105
+ },
4106
+ });
4107
+ });
4108
+
4109
+ // wait for core to process click
4110
+ cy.get(cesc("#\\/bi")).click();
4111
+ cy.get(cesc("#\\/bi2")).should("have.text", "true");
4112
+
4113
+ cy.get(cesc("#\\/d2")).should("have.text", "false");
4114
+ cy.get(cesc("#\\/vd2")).should("have.text", "true");
4115
+
4116
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4117
+ .eq(0)
4118
+ .should("have.text", "(4,7)");
4119
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4120
+ .eq(2)
4121
+ .should("have.text", "(5,7)");
4122
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4123
+ .eq(4)
4124
+ .should("have.text", "(−2,6)");
4125
+
4126
+ cy.window().then(async (win) => {
4127
+ let stateVariables = await win.returnAllStateVariables1();
4128
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([4, 7]);
4129
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([5, 7]);
4130
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
4131
+ expect(stateVariables["/p"].stateValues.draggable).eq(false);
4132
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(true);
4133
+ });
4134
+
4135
+ cy.log("vertices and polyline draggable");
4136
+
4137
+ cy.get(cesc("#\\/draggable")).click();
4138
+ cy.get(cesc("#\\/d2")).should("have.text", "true");
4139
+
4140
+ cy.log("can move single vertex");
4141
+ cy.window().then(async (win) => {
4142
+ await win.callAction1({
4143
+ actionName: "movePolyline",
4144
+ componentName: "/p",
4145
+ args: {
4146
+ pointCoords: { 1: [-3, 2] },
4147
+ },
4148
+ });
4149
+ });
4150
+
4151
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow").should("contain.text", "(−3,2)");
4152
+
4153
+ cy.get(cesc("#\\/d2")).should("have.text", "true");
4154
+ cy.get(cesc("#\\/vd2")).should("have.text", "true");
4155
+
4156
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4157
+ .eq(0)
4158
+ .should("have.text", "(4,7)");
4159
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4160
+ .eq(2)
4161
+ .should("have.text", "(−3,2)");
4162
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4163
+ .eq(4)
4164
+ .should("have.text", "(−2,6)");
4165
+
4166
+ cy.window().then(async (win) => {
4167
+ let stateVariables = await win.returnAllStateVariables1();
4168
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([4, 7]);
4169
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([-3, 2]);
4170
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([-2, 6]);
4171
+ expect(stateVariables["/p"].stateValues.draggable).eq(true);
4172
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(true);
4173
+ });
4174
+
4175
+ cy.log("can move all vertices");
4176
+ cy.window().then(async (win) => {
4177
+ await win.callAction1({
4178
+ actionName: "movePolyline",
4179
+ componentName: "/p",
4180
+ args: {
4181
+ pointCoords: [
4182
+ [3, 8],
4183
+ [8, 10],
4184
+ [1, 9],
4185
+ ],
4186
+ },
4187
+ });
4188
+ });
4189
+
4190
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow").should("contain.text", "(3,8)");
4191
+
4192
+ cy.get(cesc("#\\/d2")).should("have.text", "true");
4193
+ cy.get(cesc("#\\/vd2")).should("have.text", "true");
4194
+
4195
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4196
+ .eq(0)
4197
+ .should("have.text", "(3,8)");
4198
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4199
+ .eq(2)
4200
+ .should("have.text", "(8,10)");
4201
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4202
+ .eq(4)
4203
+ .should("have.text", "(1,9)");
4204
+
4205
+ cy.window().then(async (win) => {
4206
+ let stateVariables = await win.returnAllStateVariables1();
4207
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([3, 8]);
4208
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([8, 10]);
4209
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([1, 9]);
4210
+ expect(stateVariables["/p"].stateValues.draggable).eq(true);
4211
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(true);
4212
+ });
4213
+
4214
+ cy.log("polyline but not vertices draggable");
4215
+
4216
+ cy.get(cesc("#\\/verticesDraggable")).click();
4217
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
4218
+
4219
+ cy.log("cannot move single vertex");
4220
+ cy.window().then(async (win) => {
4221
+ await win.callAction1({
4222
+ actionName: "movePolyline",
4223
+ componentName: "/p",
4224
+ args: {
4225
+ pointCoords: { 2: [9, 3] },
4226
+ },
4227
+ });
4228
+ });
4229
+
4230
+ // wait for core to process click
4231
+ cy.get(cesc("#\\/bi")).click();
4232
+ cy.get(cesc("#\\/bi2")).should("have.text", "false");
4233
+
4234
+ cy.get(cesc("#\\/d2")).should("have.text", "true");
4235
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
4236
+
4237
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4238
+ .eq(0)
4239
+ .should("have.text", "(3,8)");
4240
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4241
+ .eq(2)
4242
+ .should("have.text", "(8,10)");
4243
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4244
+ .eq(4)
4245
+ .should("have.text", "(1,9)");
4246
+
4247
+ cy.window().then(async (win) => {
4248
+ let stateVariables = await win.returnAllStateVariables1();
4249
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([3, 8]);
4250
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([8, 10]);
4251
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([1, 9]);
4252
+ expect(stateVariables["/p"].stateValues.draggable).eq(true);
4253
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(false);
4254
+ });
4255
+
4256
+ cy.log("can move all vertices");
4257
+ cy.window().then(async (win) => {
4258
+ await win.callAction1({
4259
+ actionName: "movePolyline",
4260
+ componentName: "/p",
4261
+ args: {
4262
+ pointCoords: [
4263
+ [-4, 1],
4264
+ [9, -4],
4265
+ [0, 7],
4266
+ ],
4267
+ },
4268
+ });
4269
+ });
4270
+
4271
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow").should("contain.text", "(−4,1)");
4272
+
4273
+ cy.get(cesc("#\\/d2")).should("have.text", "true");
4274
+ cy.get(cesc("#\\/vd2")).should("have.text", "false");
4275
+
4276
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4277
+ .eq(0)
4278
+ .should("have.text", "(−4,1)");
4279
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4280
+ .eq(2)
4281
+ .should("have.text", "(9,−4)");
4282
+ cy.get(cesc("#\\/pvert") + " .mjx-mrow")
4283
+ .eq(4)
4284
+ .should("have.text", "(0,7)");
4285
+
4286
+ cy.window().then(async (win) => {
4287
+ let stateVariables = await win.returnAllStateVariables1();
4288
+ expect(stateVariables["/p"].stateValues.vertices[0]).eqls([-4, 1]);
4289
+ expect(stateVariables["/p"].stateValues.vertices[1]).eqls([9, -4]);
4290
+ expect(stateVariables["/p"].stateValues.vertices[2]).eqls([0, 7]);
4291
+ expect(stateVariables["/p"].stateValues.draggable).eq(true);
4292
+ expect(stateVariables["/p"].stateValues.verticesDraggable).eq(false);
4293
+ });
4294
+ });
4295
+
4296
+ it("style description changes with theme", () => {
4297
+ cy.window().then(async (win) => {
4298
+ win.postMessage(
4299
+ {
4300
+ doenetML: `
4301
+ <setup>
4302
+ <styleDefinitions>
4303
+ <styleDefinition styleNumber="1" lineColor="brown" lineColorDarkMode="yellow" />
4304
+ <styleDefinition styleNumber="2" lineColor="#540907" lineColorWord="dark red" lineColorDarkMode="#f0c6c5" lineColorWordDarkMode="light red" />
4305
+ </styleDefinitions>
4306
+ </setup>
4307
+ <graph>
4308
+ <polyline name="A" styleNumber="1" labelIsName vertices="(0,0) (0,2) (2,0)" />
4309
+ <polyline name="B" styleNumber="2" labelIsName vertices="(2,2) (2,4) (4,2)" />
4310
+ <polyline name="C" styleNumber="5" labelIsName vertices="(4,4) (4,6) (6,4)" />
4311
+ </graph>
4312
+ <p name="Adescrip">Polyline A is $A.styleDescription.</p>
4313
+ <p name="Bdescrip">B is a $B.styleDescriptionWithNoun.</p>
4314
+ <p name="Cdescrip">C is a $C.styleDescriptionWithNoun.</p>
4315
+ `,
4316
+ },
4317
+ "*",
4318
+ );
4319
+ });
4320
+
4321
+ cy.get(cesc("#\\/Adescrip")).should(
4322
+ "have.text",
4323
+ "Polyline A is thick brown.",
4324
+ );
4325
+ cy.get(cesc("#\\/Bdescrip")).should(
4326
+ "have.text",
4327
+ "B is a dark red polyline.",
4328
+ );
4329
+ cy.get(cesc("#\\/Cdescrip")).should(
4330
+ "have.text",
4331
+ "C is a thin black polyline.",
4332
+ );
4333
+
4334
+ cy.log("set dark mode");
4335
+ cy.get("#testRunner_toggleControls").click();
4336
+ cy.get("#testRunner_darkmode").click();
4337
+ cy.wait(100);
4338
+ cy.get("#testRunner_toggleControls").click();
4339
+
4340
+ cy.get(cesc("#\\/Adescrip")).should(
4341
+ "have.text",
4342
+ "Polyline A is thick yellow.",
4343
+ );
4344
+ cy.get(cesc("#\\/Bdescrip")).should(
4345
+ "have.text",
4346
+ "B is a light red polyline.",
4347
+ );
4348
+ cy.get(cesc("#\\/Cdescrip")).should(
4349
+ "have.text",
4350
+ "C is a thin white polyline.",
4351
+ );
4352
+ });
4353
+
4354
+ it("One vertex constrained to grid", () => {
4355
+ cy.window().then(async (win) => {
4356
+ win.postMessage(
4357
+ {
4358
+ doenetML: `
4359
+ <text>a</text>
4360
+ <graph name="g1" newNamespace>
4361
+ <point>(3,5)</point>
4362
+ <point>(-4,-1)</point>
4363
+ <point>(5,2)
4364
+ <constraints>
4365
+ <constrainToGrid dx="3" dy="4" />
4366
+ </constraints>
4367
+ </point>
4368
+ <point>(-3,4)</point>
4369
+ <polyline vertices="$_point1 $_point2 $_point3 $_point4" name="pg" />
4370
+ </graph>
4371
+ <graph name="g2" newNamespace>
4372
+ <copy target="../g1/pg" assignNames="pg" />
4373
+ </graph>
4374
+ <copy target="g2" assignNames="g3" />
4375
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
4376
+ `,
4377
+ },
4378
+ "*",
4379
+ );
4380
+ });
4381
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
4382
+
4383
+ let vertices = [
4384
+ [3, 5],
4385
+ [-4, -1],
4386
+ [6, 4],
4387
+ [-3, 4],
4388
+ ];
4389
+
4390
+ testPolylineCopiedTwice({ vertices });
4391
+
4392
+ cy.log("move individual vertex");
4393
+ cy.window().then(async (win) => {
4394
+ vertices[1] = [4, 7];
4395
+
4396
+ win.callAction1({
4397
+ actionName: "movePolyline",
4398
+ componentName: "/g1/pg",
4399
+ args: {
4400
+ pointCoords: { 1: vertices[1] },
4401
+ },
4402
+ });
4403
+
4404
+ testPolylineCopiedTwice({ vertices });
4405
+ });
4406
+
4407
+ cy.log("move copied polyline up and to the right");
4408
+ cy.window().then(async (win) => {
4409
+ let moveX = 4;
4410
+ let moveY = 3;
4411
+
4412
+ for (let i = 0; i < vertices.length; i++) {
4413
+ vertices[i][0] = vertices[i][0] + moveX;
4414
+ vertices[i][1] = vertices[i][1] + moveY;
4415
+ }
4416
+
4417
+ win.callAction1({
4418
+ actionName: "movePolyline",
4419
+ componentName: "/g2/pg",
4420
+ args: {
4421
+ pointCoords: vertices,
4422
+ },
4423
+ });
4424
+
4425
+ // adjustment due to constraint
4426
+ moveX = -1;
4427
+ moveY = 1;
4428
+ for (let i = 0; i < vertices.length; i++) {
4429
+ vertices[i][0] = vertices[i][0] + moveX;
4430
+ vertices[i][1] = vertices[i][1] + moveY;
4431
+ }
4432
+
4433
+ testPolylineCopiedTwice({ vertices });
4434
+ });
4435
+
4436
+ cy.log("try to move double copied polyline down and to the right");
4437
+ cy.window().then(async (win) => {
4438
+ let moveX = 1;
4439
+ let moveY = -7;
4440
+
4441
+ for (let i = 0; i < vertices.length; i++) {
4442
+ vertices[i][0] = vertices[i][0] + moveX;
4443
+ vertices[i][1] = vertices[i][1] + moveY;
4444
+ }
4445
+
4446
+ win.callAction1({
4447
+ actionName: "movePolyline",
4448
+ componentName: "/g3/pg",
4449
+ args: {
4450
+ pointCoords: vertices,
4451
+ },
4452
+ });
4453
+
4454
+ // adjustment due to constraint
4455
+ moveX = -1;
4456
+ moveY = -1;
4457
+ for (let i = 0; i < vertices.length; i++) {
4458
+ vertices[i][0] = vertices[i][0] + moveX;
4459
+ vertices[i][1] = vertices[i][1] + moveY;
4460
+ }
4461
+
4462
+ testPolylineCopiedTwice({ vertices });
4463
+ });
4464
+ });
4465
+
4466
+ it("Two vertices constrained to same grid", () => {
4467
+ cy.window().then(async (win) => {
4468
+ win.postMessage(
4469
+ {
4470
+ doenetML: `
4471
+ <text>a</text>
4472
+ <graph name="g1" newNamespace>
4473
+ <point>(3,5)
4474
+ <constraints>
4475
+ <constrainToGrid dx="3" dy="4" />
4476
+ </constraints>
4477
+ </point>
4478
+ <point>(-4,-1)</point>
4479
+ <point>(5,2)
4480
+ <constraints>
4481
+ <constrainToGrid dx="3" dy="4" />
4482
+ </constraints>
4483
+ </point>
4484
+ <point>(-3,4)</point>
4485
+ <polyline vertices="$_point1 $_point2 $_point3 $_point4" name="pg" />
4486
+ </graph>
4487
+ <graph name="g2" newNamespace>
4488
+ <copy target="../g1/pg" assignNames="pg" />
4489
+ </graph>
4490
+ <copy target="g2" assignNames="g3" />
4491
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
4492
+ `,
4493
+ },
4494
+ "*",
4495
+ );
4496
+ });
4497
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
4498
+
4499
+ let vertices = [
4500
+ [3, 4],
4501
+ [-4, -1],
4502
+ [6, 4],
4503
+ [-3, 4],
4504
+ ];
4505
+
4506
+ testPolylineCopiedTwice({ vertices });
4507
+
4508
+ cy.log("move individual vertex");
4509
+ cy.window().then(async (win) => {
4510
+ vertices[1] = [4, 7];
4511
+
4512
+ win.callAction1({
4513
+ actionName: "movePolyline",
4514
+ componentName: "/g1/pg",
4515
+ args: {
4516
+ pointCoords: { 1: vertices[1] },
4517
+ },
4518
+ });
4519
+
4520
+ testPolylineCopiedTwice({ vertices });
4521
+ });
4522
+
4523
+ cy.log("move copied polyline up and to the right");
4524
+ cy.window().then(async (win) => {
4525
+ let moveX = 4;
4526
+ let moveY = 3;
4527
+
4528
+ for (let i = 0; i < vertices.length; i++) {
4529
+ vertices[i][0] = vertices[i][0] + moveX;
4530
+ vertices[i][1] = vertices[i][1] + moveY;
4531
+ }
4532
+
4533
+ win.callAction1({
4534
+ actionName: "movePolyline",
4535
+ componentName: "/g2/pg",
4536
+ args: {
4537
+ pointCoords: vertices,
4538
+ },
4539
+ });
4540
+
4541
+ // adjustment due to constraint
4542
+ moveX = -1;
4543
+ moveY = 1;
4544
+ for (let i = 0; i < vertices.length; i++) {
4545
+ vertices[i][0] = vertices[i][0] + moveX;
4546
+ vertices[i][1] = vertices[i][1] + moveY;
4547
+ }
4548
+
4549
+ testPolylineCopiedTwice({ vertices });
4550
+ });
4551
+
4552
+ cy.log("try to move double copied polyline down and to the right");
4553
+ cy.window().then(async (win) => {
4554
+ let moveX = 1;
4555
+ let moveY = -7;
4556
+
4557
+ for (let i = 0; i < vertices.length; i++) {
4558
+ vertices[i][0] = vertices[i][0] + moveX;
4559
+ vertices[i][1] = vertices[i][1] + moveY;
4560
+ }
4561
+
4562
+ win.callAction1({
4563
+ actionName: "movePolyline",
4564
+ componentName: "/g3/pg",
4565
+ args: {
4566
+ pointCoords: vertices,
4567
+ },
4568
+ });
4569
+
4570
+ // adjustment due to constraint
4571
+ moveX = -1;
4572
+ moveY = -1;
4573
+ for (let i = 0; i < vertices.length; i++) {
4574
+ vertices[i][0] = vertices[i][0] + moveX;
4575
+ vertices[i][1] = vertices[i][1] + moveY;
4576
+ }
4577
+
4578
+ testPolylineCopiedTwice({ vertices });
4579
+ });
4580
+ });
4581
+
4582
+ it("Three vertices constrained to same grid", () => {
4583
+ cy.window().then(async (win) => {
4584
+ win.postMessage(
4585
+ {
4586
+ doenetML: `
4587
+ <text>a</text>
4588
+ <graph name="g1" newNamespace>
4589
+ <point>(3,5)
4590
+ <constraints>
4591
+ <constrainToGrid dx="3" dy="4" />
4592
+ </constraints>
4593
+ </point>
4594
+ <point>(-4,-1)
4595
+ <constraints>
4596
+ <constrainToGrid dx="3" dy="4" />
4597
+ </constraints>
4598
+ </point>
4599
+ <point>(5,2)
4600
+ <constraints>
4601
+ <constrainToGrid dx="3" dy="4" />
4602
+ </constraints>
4603
+ </point>
4604
+ <point>(-3,4)</point>
4605
+ <polyline vertices="$_point1 $_point2 $_point3 $_point4" name="pg" />
4606
+ </graph>
4607
+ <graph name="g2" newNamespace>
4608
+ <copy target="../g1/pg" assignNames="pg" />
4609
+ </graph>
4610
+ <copy target="g2" assignNames="g3" />
4611
+ <copy target="g1/pg" prop="vertices" assignNames="p1 p2 p3 p4" />
4612
+ `,
4613
+ },
4614
+ "*",
4615
+ );
4616
+ });
4617
+ cy.get(cesc("#\\/_text1")).should("have.text", "a"); //wait for page to load
4618
+
4619
+ let vertices = [
4620
+ [3, 4],
4621
+ [-3, 0],
4622
+ [6, 4],
4623
+ [-3, 4],
4624
+ ];
4625
+
4626
+ testPolylineCopiedTwice({ vertices });
4627
+
4628
+ cy.log("move individual vertex");
4629
+ cy.window().then(async (win) => {
4630
+ vertices[1] = [4, 7];
4631
+
4632
+ win.callAction1({
4633
+ actionName: "movePolyline",
4634
+ componentName: "/g1/pg",
4635
+ args: {
4636
+ pointCoords: { 1: vertices[1] },
4637
+ },
4638
+ });
4639
+
4640
+ // adjust for constraint
4641
+ vertices[1] = [3, 8];
4642
+
4643
+ testPolylineCopiedTwice({ vertices });
4644
+ });
4645
+
4646
+ cy.log("move copied polyline up and to the right");
4647
+ cy.window().then(async (win) => {
4648
+ let moveX = 4;
4649
+ let moveY = 3;
4650
+
4651
+ for (let i = 0; i < vertices.length; i++) {
4652
+ vertices[i][0] = vertices[i][0] + moveX;
4653
+ vertices[i][1] = vertices[i][1] + moveY;
4654
+ }
4655
+
4656
+ win.callAction1({
4657
+ actionName: "movePolyline",
4658
+ componentName: "/g2/pg",
4659
+ args: {
4660
+ pointCoords: vertices,
4661
+ },
4662
+ });
4663
+
4664
+ // adjustment due to constraint
4665
+ moveX = -1;
4666
+ moveY = 1;
4667
+ for (let i = 0; i < vertices.length; i++) {
4668
+ vertices[i][0] = vertices[i][0] + moveX;
4669
+ vertices[i][1] = vertices[i][1] + moveY;
4670
+ }
4671
+
4672
+ testPolylineCopiedTwice({ vertices });
4673
+ });
4674
+
4675
+ cy.log("try to move double copied polyline down and to the right");
4676
+ cy.window().then(async (win) => {
4677
+ let moveX = 1;
4678
+ let moveY = -7;
4679
+
4680
+ for (let i = 0; i < vertices.length; i++) {
4681
+ vertices[i][0] = vertices[i][0] + moveX;
4682
+ vertices[i][1] = vertices[i][1] + moveY;
4683
+ }
4684
+
4685
+ win.callAction1({
4686
+ actionName: "movePolyline",
4687
+ componentName: "/g3/pg",
4688
+ args: {
4689
+ pointCoords: vertices,
4690
+ },
4691
+ });
4692
+
4693
+ // adjustment due to constraint
4694
+ moveX = -1;
4695
+ moveY = -1;
4696
+ for (let i = 0; i < vertices.length; i++) {
4697
+ vertices[i][0] = vertices[i][0] + moveX;
4698
+ vertices[i][1] = vertices[i][1] + moveY;
4699
+ }
4700
+
4701
+ testPolylineCopiedTwice({ vertices });
4702
+ });
4703
+ });
4704
+ });