Built with blockbuilder.org
Last active
November 2, 2015 00:19
-
-
Save enjalot/200cd9a890f98b82d6f3 to your computer and use it in GitHub Desktop.
positive definite
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src="http://acko.net/files/mathbox2/mathbox-bundle.min.js"></script> | |
<script src="matrix.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
svg { | |
position: absolute; | |
left: 440px; | |
width: 500px; | |
height: 200; | |
} | |
#mathbox1 { | |
position: absolute; | |
left:20px; | |
top: 20px; | |
width: 400px; | |
height: 400px; | |
} | |
.number { | |
cursor: col-resize; | |
} | |
</style> | |
</head> | |
<script type="application/glsl" id="vertex-xyz"> | |
// Enable STPQ mapping | |
#define POSITION_STPQ | |
void getPosition(inout vec4 xyzw, inout vec4 stpq) { | |
// Store XYZ per vertex in STPQ | |
stpq = xyzw; | |
} | |
</script> | |
<script type="application/glsl" id="fragment-shader"> | |
// Enable STPQ mapping | |
#define POSITION_STPQ | |
vec4 getColor(vec4 rgba, inout vec4 stpq) { | |
float z = stpq.z/3.0; | |
if(z < 0.0) { | |
return vec4(0.4, 0, 0, 0.9); | |
} | |
return vec4(0.0, 0.4*z - 0.6, (0.4/z + 0.4), 0.9); | |
} | |
</script> | |
<body> | |
<svg> | |
<text x=140 y=55 id="eqn"></text> | |
<text x=140 y=80 id="result">Positive Definite? <tspan id="pd"></tspan></text> | |
</svg> | |
<div id="mathbox1"></div> | |
<script> | |
var svg = d3.select("svg"); | |
var A = [ | |
[1, 0], | |
[0, 1] | |
] | |
var matrix = new d3.svg.matrix() | |
.data(A).mapping([ | |
["a", "b"], | |
["b", "c"] | |
]) | |
.cellWidth(40) | |
.cellHeight(40) | |
.margin([10, 10]) | |
var green = '#6ffe5c'; | |
var orange = '#fe732d'; | |
var matrixg = svg.append("g") | |
.attr("transform", "translate(20, 30)") | |
matrix.update(matrixg) // render the matrix | |
matrix.on("change", function(){ | |
updateAnnotations(); | |
}) | |
function updateAnnotations() { | |
var a = A[0][0]; | |
var b = A[0][1]; | |
var c = A[1][1]; | |
var isPD = a*c > b*b | |
d3.select("#pd").text( isPD ? "yes" : "no") | |
matrixg.selectAll("path.bracket").style({ | |
stroke: (isPD ? "green" : orange) | |
}) | |
d3.select("#eqn") | |
.text(a + " * x^2 + 2*" + b + "* x*y + " + c + " * y^2") | |
} | |
updateAnnotations(); | |
// Load mathbox with controls | |
var mathbox = mathBox({ | |
element: d3.select("#mathbox1").node(), | |
plugins: ['core', 'cursor', 'controls'], | |
controls: { | |
klass: THREE.OrbitControls, | |
}, | |
}); | |
if (mathbox.fallback) throw "WebGL error"; | |
// mathbox.resize({viewWidth:100, viewHeight:100}) | |
// Set renderer background | |
var three = mathbox.three; | |
three.renderer.setClearColor(new THREE.Color(0xffffff), 1.0); | |
// Set mathbox units and place camera | |
mathbox.set({ scale: 720, focus: 3 }); | |
var camera = mathbox.camera({ proxy: true, position: [0, -1.0,1.1] }); | |
// Create cartesian view | |
var view = mathbox | |
.cartesian({ | |
range: [[-10, 10], [-10, 10], [-10, 15]], | |
scale: [1,1,1], | |
}); | |
// 2D axes / grid | |
var axesWidth = 0.5 | |
view.axis({ axis: 1, width: axesWidth }); | |
view.axis({ axis: 2, width: axesWidth }); | |
view.axis({ axis: 3, width: axesWidth }); | |
view.grid({ width: axesWidth, divideX: 20, divideY: 20, opacity:1 }); | |
var r = 3; | |
var ai = document.getElementById("a") | |
var bi = document.getElementById("b") | |
var ci = document.getElementById("c") | |
var area = view.area({ | |
id: "main", | |
width: 20, | |
height: 20, | |
axes: [0, 2], | |
rangeX: [-r, r], | |
rangeY: [-r, r], | |
expr: function (emit, x, y, i, j, time, delta) { | |
var a = A[0][0]; | |
var b = A[0][1]; | |
var c = A[1][1]; | |
var z = (a * x*x + 2*b*x*y + c * y*y) * 0.2; | |
emit(x, y, z); | |
}, | |
channels:3 | |
}) | |
area | |
.shader({ | |
code: "#vertex-xyz" | |
}) | |
.vertex({ | |
// Work in data XYZ instead of view XYZ | |
pass: 'data' | |
}) | |
.shader({ | |
code: "#fragment-shader", | |
}) | |
.fragment({gamma: true }) | |
// Fragment shaded shapes | |
.surface({ | |
fill: true, | |
lineX: false, | |
lineY: false, | |
width: 1, | |
zBias: 1, | |
/* | |
shaded: true, | |
lineX: true, | |
lineY: true, | |
//color: "#51e4ff", | |
width: 0.5, | |
opacity: 1 | |
*/ | |
}) | |
area.surface({ | |
fill: false, | |
lineX: true, | |
lineY: true, | |
width: 1.5, | |
zBias: 1, | |
color: "#c6cfd1", | |
width: 0.5, | |
opacity: 1 | |
}) | |
view | |
.interval({ | |
length: 32, | |
channels: 2, | |
expr: function (emit, x, i, t) { | |
var a = A[0][0]; | |
var b = A[0][1]; | |
var c = A[1][1]; | |
emit(x, -x); //TODO line up with trough | |
}, | |
}) | |
.line({ | |
width: 1, | |
color: orange, | |
}) | |
view | |
.interval({ | |
length: 32, | |
channels: 3, | |
expr: function (emit, x, i, t) { | |
var a = A[0][0]; | |
var b = A[0][1]; | |
var c = A[1][1]; | |
var y = -x; | |
var z = (a * x*x + 2*b*x*y + c * y*y) * 0.2; | |
emit(x,y, z);//TODO line up with trough | |
}, | |
}) | |
.line({ | |
width: 1, | |
color: green, | |
}) | |
var view = mathbox.select("") | |
var surface = mathbox.select('surface') | |
</script> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d3.layout.matrix = matrixLayout; | |
d3.svg.matrix = matrixComponent; | |
function matrixComponent() { | |
var g; | |
var data = [[]]; | |
var mapping = [[]]; | |
var nodes = []; | |
var layout = d3.layout.matrix(); | |
var margin = layout.margin(); | |
var cellWidth = layout.cellWidth(); | |
var cellHeight = layout.cellHeight(); | |
/* | |
TODO | |
make scrubbing configurable, per-cell | |
*/ | |
var dispatch = d3.dispatch("change") | |
this.update = function(group) { | |
if(group) g = group; | |
nodes = layout.nodes(data); | |
var line = d3.svg.line() | |
.x(function(d) { return d[0] }) | |
.y(function(d) { return d[1] }) | |
var brackets = g.selectAll("path.bracket") | |
.data([1, -1]) | |
brackets.enter().append("path").classed("bracket", true) | |
.attr("d", function(d) { | |
var nRows = data.length; | |
var x0 = d * cellWidth/4; | |
var x1 = -margin[0]/2; | |
var y0 = -margin[1]/2; | |
var y1 = (cellHeight + margin[1]) * nRows - margin[1]/2 | |
if(d === 1) { | |
return line([ | |
[x0, y0], | |
[x1, y0], | |
[x1, y1], | |
[x0, y1] | |
]) | |
} else { | |
var dx = (cellWidth + margin[0]) * data[0].length - margin[0]/2 | |
x0 -= margin[0]/2 | |
return line([ | |
[x0 + dx, y0], | |
[dx, y0], | |
[dx, y1], | |
[x0 + dx, y1] | |
]) | |
} | |
}).attr({ | |
stroke: "#111", | |
fill: "none" | |
}) | |
var cells = g.selectAll("g.number").data(nodes) | |
var enter = cells.enter().append("g").classed("number", true) | |
enter.append("rect").classed("bg", true) | |
cells.select("rect.bg") | |
.attr({ | |
width: cellWidth, | |
height: cellHeight, | |
x: function(d) { return d.x }, | |
y: function(d) { return d.y }, | |
fill: "#fff" | |
}) | |
enter.append("text") | |
cells.select("text").attr({ | |
x: function(d) { return d.x + cellWidth/2 }, | |
y: function(d) { return d.y + cellHeight/2 }, | |
"alignment-baseline": "middle", | |
"text-anchor": "middle", | |
"line-height": cellHeight, | |
"fill": "#091242" | |
}).text(function(d) { return d.data }) | |
var step = 0.1; | |
var that = this; | |
var drag = d3.behavior.drag() | |
.on("drag", function(d) { | |
var oldData = d.data; | |
var val = d.data + d3.event.dx * step | |
val = +(Math.round(val*10)/10).toFixed(1) | |
set(val, d.i, d.j); | |
//data[d.i][d.j] = val; | |
that.update() | |
dispatch.change(d, oldData) | |
}) | |
cells.call(drag) | |
return this; | |
} | |
function set(val, i, j) { | |
var m = mapping[i][j]; | |
if(m){ | |
mapping.forEach(function(row, mi) { | |
row.forEach(function(col, mj) { | |
if(col === m) { | |
data[mi][mj] = val; | |
} | |
}) | |
}) | |
} | |
data[i][j] = val; | |
} | |
this.mapping = function(val) { | |
if(val) { | |
// TODO make sure dims match | |
mapping = val; | |
return this; | |
} | |
return mapping; | |
} | |
this.data = function(val) { | |
if(val) { | |
data = val; | |
nodes = layout.nodes(data); | |
return this; | |
} | |
return data; | |
} | |
this.margin = function(val) { | |
if(val) { | |
margin = val; | |
layout.margin(margin); | |
return this; | |
} | |
return margin; | |
} | |
this.cellWidth = function(val) { | |
if(val) { | |
cellWidth = val; | |
layout.cellWidth(cellWidth); | |
return this; | |
} | |
return cellWidth; | |
} | |
this.cellHeight = function(val) { | |
if(val) { | |
cellHeight = val; | |
layout.cellHeight(cellHeight); | |
return this; | |
} | |
return cellHeight; | |
} | |
d3.rebind(this, dispatch, "on") | |
return this; | |
} | |
function matrixLayout() { | |
/* | |
We accept our matrix data as a list of rows: | |
[ [a, b], | |
[c, d] ] | |
*/ | |
var data = [[]]; | |
var nodes; | |
var margin = [0, 0]; | |
var cellWidth = 20; | |
var cellHeight = 20; | |
var nRows; | |
function getX(i) { | |
return i * (cellWidth + margin[0]) | |
} | |
function getY(j) { | |
return j * (cellHeight + margin[1]) | |
} | |
function newNodes() { | |
nRows = data.length; | |
nodes = []; | |
data.forEach(function(rows,i) { | |
rows.forEach(function(col, j) { | |
var node = { | |
x: getX(j), | |
y: getY(i), | |
data: col, | |
i: i, | |
j: j, | |
index: i * nRows + j | |
} | |
nodes.push(node); | |
}) | |
}) | |
} | |
function calculate() { | |
nRows = data.length; | |
data.forEach(function(rows,i) { | |
rows.forEach(function(col, j) { | |
var node = nodes[i * nRows + j]; | |
if(!node) return; | |
node.data = col; | |
node.x = getX(j); | |
node.y = getY(i); | |
}) | |
}) | |
} | |
this.nodes = function(val) { | |
if(val) { | |
this.data(val); | |
} | |
return nodes; | |
} | |
this.data = function(val) { | |
if(val) { | |
if(val.length === data.length && val[0].length === data[0].length) { | |
// if the same size matrix is being updated, | |
// just update the values by reference | |
// the positions shouldn't change | |
data = val; | |
calculate(); | |
} else { | |
data = val; | |
newNodes(); | |
} | |
nRows = data.length; | |
return this; | |
} | |
return data; | |
} | |
this.margin = function(val) { | |
if(val) { | |
margin = val; | |
calculate(); | |
return this; | |
} | |
return margin; | |
} | |
this.cellWidth = function(val) { | |
if(val) { | |
cellWidth = val; | |
calculate(); | |
return this; | |
} | |
return cellWidth; | |
} | |
this.cellHeight = function(val) { | |
if(val) { | |
cellHeight = val | |
calculate(); | |
return this; | |
} | |
return cellHeight; | |
} | |
return this; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment