tixy-ish
Inspired by tixy.land; in development; open to contributions!
ƒ
calculang ✍️
editable and dangerous! 🧙♂️⚠️javascript ✨
generated from calculang ⬆️dev tools 🧰
🎨
inputs ⚙️
eval-on-select (select formula text, then activate with F9)
compiled selection (via sourcemap)
appendix & source code of 🎨
showing selected source code of 🎨
For complete source see GitHub.
notes
this is Javascript and using tools and patterns that I repeat, but remember that calculang is unopinionated!calculang/output is also highly portable and uniform.
visual 1 (main output, with mouse interactivity)
const spec = ({
// vega-lite
title: "v",
mark: {type:'point', point: false, filled: true},
encoding: {
x: { field: 'x_in', type: 'quantitative', domain: _.range(0,size_in), scale: {nice:false, domain:[-1,16]} },
y: { field: 'y_in', type: 'quantitative', domain: _.range(0,size_in), sort:'descending', scale: {nice:false, domain:[-1,16]} },
size: { field: 'abs_v_clamped', type: 'quantitative', scale: {domain:[0,1]} },
//color: {value: 'red'}
color: { field: 'positive', type: 'nominal', scale: {domain:[false, true], range: ['orange','red'] }}, // todo color calcd from model?
shape: { field: 'positive', type: 'nominal', scale: {domain:[false, true], range: ['diamond','circle'] }} // todo color calcd from model?
},
data: { name: "data" },
datasets: {
data: [],
},
autosize: { "type": "fit", "contains": "padding"},
width: Math.min(400,rhs_width-30),
height: 300,
background:'rgba(0,0,0,0)'
})
// interactivity via vega signals and listeners
const viz = embed('#viz', spec, {patch: [{
path: "/signals",
op: "add",
value: [{
name: "mousex",
value: 8,
on: [
{"events": "mousemove{30}", "update": (size_in-1)+"*x()/range('x')[1]"}
]
},{
name: "mousey",
value: 8,
on: [
{"events": "mousemove{30}", "update": (size_in-1)+"*y()/range('y')[1]"}
]
}]
}]})
const data_source = calcuvegadata({
models: [model],
spec,
domains: {
x_in: _.range(0,size_in),
y_in: _.range(0,size_in)
},
input_cursors: [
{ t_in, mousex_in, mousey_in, random_seed_in }
]
})
viz.view.data("data", data_source)/*.resize()*/.run(); // turn off resize
const random_seed_in = 'x' // reactive issues if mixed in mutable updates blocks
const mousex_in = Mutable(8)
const mousey_in = Mutable(8)
viz.view.addSignalListener('mousex', a => {
console.log('mousex', a)
mousex_in.value = viz.view.signal('mousex')
})
viz.view.addSignalListener('mousey', a => {
mousey_in.value = viz.view.signal('mousey')
})
visual 2
const spec2 = ({
// vega-lite
title: "selection",
mark: {type:'text', point: false, filled: true},
encoding: {
x: { field: 'x_in', type: 'quantitative', scale: {nice:false, domain:[-1,16]} },
y: { field: 'y_in', type: 'quantitative', sort:'descending', scale: {nice:false, domain:[-1,16]} },
text: { field: 'selection_fn', format: ('.1f') },
color: { field: 'selection_fn', type: 'quantitative', legend: false/*, scale: {domain:[0,1] }*/}
},
data: { name: "data" },
datasets: {
data: [],
},
autosize: { "type": "fit", "contains": "padding"},
width: Math.min(500,rhs_width-30),
height: 300,
background:'rgba(0,0,0,0)'
})
const viz2 = embed('#viz2', spec2)
const data_source2 = calcuvegadata({
models: [{selection_fn: (a) => selection_fn(model,a)}],
spec: spec2,
domains: {
x_in: _.range(0,size_in),
y_in: _.range(0,size_in)
},
input_cursors: [
{ t_in, mousex_in, mousey_in, random_seed_in }
]
})
viz2.view.data("data", data_source2)/*.resize()*/.run(); // turn off resize
const size_in = 16
const t_in_Input = Inputs.input(0);
const t_in = Generators.input(t_in_Input);
const rhs_width = Generators.width(document.querySelector(".rhs")); // keep as a generator for reactivity
eval-on-select
// all inputs must be maintianed here to pass to selection function
const ins = ({x_in: 8, y_in:8, t_in, random_seed_in, mousex_in, mousey_in})
todo maintain eval selection range with edits? Alt.: don't react to edits by freezing into Mutable, but this is poor. and multi-selection (concatenating useful imo)