Skip to content

Instantly share code, notes, and snippets.

@jared-hughes
Last active May 24, 2021 03:07
Show Gist options
  • Save jared-hughes/b62dc3042947d6dcee16a186301227dc to your computer and use it in GitHub Desktop.
Save jared-hughes/b62dc3042947d6dcee16a186301227dc to your computer and use it in GitHub Desktop.
Step through transformations on a Desmos graph. Superseded by https://github.com/jason-woolf/DesmosPlayer.
// ==UserScript==
// @name DesmoSteps
// @namespace http://github.com/jared-hughes
// @version 0.2.0
// @description Step through transformations automatically on a Desmos graph
// @author Jared Hughes (fireflame241)
// @match https://www.desmos.com/calculator*
// @grant none
// @run-at document-idle
// ==/UserScript==
// LICENSE: ISC
// Fork of https://github.com/jared-hughes/DesThree/blob/master/src/tests/indexIntegration.js
(function () {
let Calc
let currentIndex = -1
let resetButton, passButton, title
// to get IDs run in the browser console (ctrl+shift+I in Chrome):
// console.table(Calc.getState().expressions.list)
// or
// console.table(Calc.getState().expressions.list.map(e => ({id: e.id, type: e.type, latex: e.latex})))
// numbers are interchangeable with string IDs
// to get one expression use:
// console.log(Calc.getState().expressions.list[i])
// where i is the index (not ID) of the expression
// if you don't wrap a function with `auto`, you have to manually move on to the next step
const steps = [
// turn on this folder
auto(set(6, { hidden: false }), 2000),
// animate that slider
auto(setSliderPlaying(10, true, 1), 5000),
// turn off this expression
set(9, { hidden: true }),
// reset that slider
setSlider(10, 'u=0')
]
function set (id, args) {
const obj = { id, ...args }
const func = () => Calc.setExpression(obj)
func.desc = obj
return func
}
function setSliderPlaying (id, isPlaying, playDirection) {
// for some reason this does not work through Calc.setExpression()
const obj = { isPlaying: isPlaying ?? true, playDirection: playDirection ?? 1 }
const func = () => {
const state = Calc.getState()
const expr = state.expressions.list.filter(e => e.id === id.toString())[0]
expr.slider = obj
Calc.setState(state)
}
func.desc = { id, slider: obj }
return func
}
function setSlider (id, latex) {
const setSliderFunc = setSliderPlaying(id, false)
const func = () => {
setSliderFunc()
set(10, { latex })()
}
func.desc = setSliderFunc.desc
return func
}
function auto (func, time) {
// after `time` ms after running func, call the next one
const newFunc = () => {
func()
setTimeout(
() => setState(currentIndex + 1),
time
)
}
newFunc.desc = func.desc
return newFunc
}
const interval = setInterval(() => {
if (document.querySelector('.save-button') && window.Calc) {
Calc = window.Calc
init()
clearInterval(interval)
}
}, 100)
function testlog (s) {
console.log(`%c${s}`, 'font-weight: bold; border: 1px solid black; border-radius: 999px; padding: 3px 5px 3px 5px')
}
function enableButton (el) {
el.firstChild.classList.add('dcg-btn-green')
el.firstChild.classList.remove('disabled-save-btn')
}
function disableButton (el) {
el.firstChild.classList.remove('dcg-btn-green')
el.firstChild.classList.add('disabled-save-btn')
}
function setState (index) {
index = Math.min(index, steps.length - 1)
index = Math.max(index, 0)
currentIndex = index
testlog(`Switching to step #${index + 1}`)
console.log(steps[index].desc)
markState(index)
steps[index]()
}
function markState (index) {
if (index > 0) {
enableButton(resetButton)
} else {
disableButton(resetButton)
}
if (index === steps.length - 1) {
disableButton(passButton)
} else {
enableButton(passButton)
}
title.innerHTML = (`Step #${index + 1}`)
}
function init () {
const initState = Calc.getState()
testlog('Stepping enabled')
const saveButton = document.querySelector('.save-button')
resetButton = saveButton.cloneNode(true)
resetButton.firstChild.innerHTML = 'Reset'
resetButton.addEventListener('click', () => {
currentIndex = -1
markState(-1)
Calc.setState(initState, { allowUndo: true })
})
saveButton.after(resetButton)
passButton = resetButton.cloneNode(true)
passButton.firstChild.innerHTML = 'Next Step'
passButton.addEventListener('click', () => setState(currentIndex + 1))
resetButton.after(passButton)
passButton.firstChild.classList.add('dcg-btn-green')
passButton.firstChild.classList.remove('disabled-save-btn')
title = document.querySelector('.dcg-variable-title')
title.style.maxWidth = '600px'
// saveButton.style.display = 'none'
const buttonContainer = document.querySelector('.save-btn-container')
buttonContainer.after(title)
buttonContainer.style.position = 'relative'
buttonContainer.style.top = '-18px'
document.querySelector('.align-center-container').style.display = 'none'
markState(currentIndex)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment