Published
Edited
Oct 20, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
degreeTracker
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Chart = {
svg
.attr("viewBox", [0,0,1,1])
.attr("width", width * 0.8).attr("height", width*0.8)
.attr("tabindex", 1)
.attr("pointer-events", "all")
.call(d3.drag()
.subject(dragObject)
.on("start", dragStart)
.on("drag", dragged)
)
d3.select(window)
.on("keydown", keydown);
return svg.node()
}
Insert cell
Insert cell
mutable fileInputDim = 0;
Insert cell
fileInputTracker = {
let obj = {
"name": "",
"lastModifiedDate": ""
}
return obj
}
Insert cell
content = Files.text(file)
Insert cell
mutable pointsStorageFromFile = []
Insert cell
mutable tmpKnots = []
Insert cell
dataLoadIn = {
if(inputFormat === "Text File" && content && (file.name != fileInputTracker.name || file.lastModifiedDate.toString() != fileInputTracker.lastModifiedDate)){
fileInputTracker.name = file.name
fileInputTracker.lastModifiedDate = file.lastModifiedDate.toString()
console.log("doing once!")
let loadInData = content.trim().split("\n")
const filteredData = loadInData.filter(obj => {
if(obj.startsWith("BSPLINE")){
return false
}else if(obj.startsWith("#")){
return false
}else{
return true
}
})
let [dimension, numOfPoints, degree] = filteredData[0].trim().split(' ').map(i => parseInt(i))
mutable fileInputDim = degree
mutable tmpKnots = filteredData[1].trim().split(' ').map(i => parseInt(i))
let dataPoints = []
mutable pointsStorageFromFile = []
filteredData.slice(2).forEach(obj => {
let tmpD = obj.trim().split(' ').map(i => parseFloat(i))
dataPoints.push([tmpD[0], 1-tmpD[1]])
mutable pointsStorageFromFile.push([tmpD[0], 1-tmpD[1]])
})
while(mutable points.length > 0){
mutable points.pop()
}
for(let i = 0; i < dataPoints.length; i++){
mutable points.push([dataPoints[i][0],dataPoints[i][1]])
}

while(mutable knots.length > 0){
mutable knots.pop()
}
for(let i = 0; i < tmpKnots.length; i++){
mutable knots.push(tmpKnots[i])
}
mutable degreeTracker = mutable tmpKnots.length - mutable points.length - 1
mutable numP = mutable points.length
mutable knots = mutable knots;
mutable points = mutable points
mutable tmpKnots = mutable tmpKnots
mutable clampedTracker = false
mutable uniformTracker = false
mutable closeTracker = false
mutable openTracker = false
console.log("sdasdasdasdasdasdasdasdasdasd")
update()
// return dataPoints
}
}
Insert cell
knots
Insert cell
mutable uniformTracker = false
Insert cell
mutable closeTracker = false
Insert cell
mutable openTracker = false
Insert cell
mutable clampedTracker = false
Insert cell
functionButtonClick = {
if(functionButton == 1 && (mutable uniformTracker==false)){
console.log("0011000000011111111010101010101")
mutable uniformTracker = true
mutable closeTracker = false
mutable openTracker = false
mutable clampedTracker = false

}
else if(functionButton == 2 && !clampedTracker){
mutable clampedTracker = true
mutable uniformTracker = false
mutable closeTracker = false
mutable openTracker = false

}else if(functionButton == 3 && !closeTracker){
mutable closeTracker = true
mutable uniformTracker = false
mutable openTracker = false
mutable clampedTracker = false

}else if(functionButton == 4 && !openTracker){
mutable openTracker = true
mutable uniformTracker = false
mutable closeTracker = false
mutable clampedTracker = false
}else {
mutable openTracker = false
mutable uniformTracker = false
mutable closeTracker = false
mutable clampedTracker = false
}
}
Insert cell
mutable ControlPointButtonTracker = 0
Insert cell
mutable previousTrack = "Clamped"
Insert cell
clickAddControlP = {
if(addControlPointButton > ControlPointButtonTracker){
mutable ControlPointButtonTracker = addControlPointButton;
let selectedIdx = points.indexOf(selected)
if(selectedIdx >= numDegree){
d3.select(".addBtn1").style("color", "green")
mutable clampedTracker = false
const tmp = knots[selectedIdx]/2 + knots[selectedIdx+1]/2;
let tmpArr1 = knots.slice(0,selectedIdx+1)
tmpArr1.push(tmp)
tmpArr1 = tmpArr1.concat(knots.slice(selectedIdx+1))
while(mutable knots.length > 0){
mutable knots.pop()
}
for(let i=0;i<tmpArr1.length;i++){
mutable knots.push(tmpArr1[i])
}
mutable knots = mutable knots
// mutable knots = tmpArr1

let tmpPoints = [...points.slice(0, selectedIdx-numDegree+1)]
console.log("Check this!!!!!!!!")
console.log(selectedIdx-numDegree+1)
console.log(tmpPoints)
let resPoints = [...points.slice(selectedIdx)]
console.log(resPoints)
for(let j=selectedIdx-numDegree+1; j<=selectedIdx;j++){
let coef = (tmp - tmpArr1[j])/(tmpArr1[j+numDegree]-tmpArr1[j])
console.log("coef="+coef)
let mid1 = [...points[j]].map(i=>coef*i)
let mid2 = [...points[j-1]].map(i=>(1-coef)*i)
tmpPoints.push([mid1[0]+mid2[0], mid1[1]+mid2[1]])
}
tmpPoints = tmpPoints.concat(resPoints)
while(mutable points.length > 0){
mutable points.pop()
}
for(let i=0;i<tmpPoints.length;i++){
mutable points.push(tmpPoints[i])
}

mutable points = mutable points
// mutable points = tmpPoints

// mutable points = mutable points
// mutable knots = mutable knots
update()
}
}
}
Insert cell
selectedIdx = points.indexOf(selected)
Insert cell
numP
Insert cell
Insert cell
mutable knots = []
Insert cell
mutable backup = []
Insert cell
mutable backUpStatus = false
Insert cell
openTracker
Insert cell
knotsInitialize = {
mutable points;
// mutable degreeTracker = numDegree
mutable numPointTracker = points.length
if(inputFormat == "Text File"){
mutable knots = mutable tmpKnots;
mutable knots = mutable knots;
mutable degreeTracker = tmpKnots.length - points.length - 1
mutable degreeTracker = mutable degreeTracker
update()
}else{
if(clampedTracker){
console.log(1111)
while(mutable knots.length > 0){
mutable knots.pop()
}
const numInTotal = (mutable points).length + numDegree + 1
const numRealValue = numInTotal - 2*(numDegree + 1)
for(let i = 0; i < numDegree + 1; i++){
mutable knots.push(0)
}
let j = 0
for(j=0; j < numRealValue; j++){
mutable knots.push(j+1)
}
j += 1
for(let k=0; k < numDegree + 1; k++){
mutable knots.push(j)
}
mutable previousTrack = "Clamped"
mutable knots = mutable knots;
update()
document.querySelector(".reset").click()
// mutable knots = mutable knots
}else if(uniformTracker){
console.log(2222)
const knotsLength = knots.length
while(mutable knots.length > 0){
mutable knots.pop()
}
const newKnotsLength = (mutable points).length + numDegree + 1
for(let i = 0;i<newKnotsLength;i++){
mutable knots.push(i)
}
// ////
// while(mutable backup.length > 0){
// mutable backup.pop()
// }
// for(let j=length - numDegree; j<length; j++){
// (mutable backup).push([... points[j]])
// }
// ////
// let indexHelper = 0
// if(previousTrack == "Close"){
// for(let j=points.length - numDegree; j<length; j++){
// mutable points[j] = [mutable backup[indexHelper][0], mutable backup[indexHelper][1]]
// indexHelper ++
// }
// }
mutable previousTrack = "Uniform"
mutable knots = mutable knots;
update()
document.querySelector(".reset").click()
}else if(closeTracker){
console.log(3333)
const length = mutable points.length
let indexHelper = 0
for(let j=length - numDegree; j<length; j++){
mutable points[j] = mutable points[indexHelper]
indexHelper ++
}
mutable previousTrack = "Close"
mutable points = mutable points
update()
document.querySelector(".reset").click()
}else if(openTracker){
console.log(4444)
const length = mutable points.length
if(previousTrack == "Close"){
console.log("Open Tracker")
for(let j=length - numDegree; j<length; j++){
mutable points.pop()
}
for(let j=length - numDegree; j<length; j++){
mutable points.push([0.1 + Math.round(Math.random()*10) * 0.5/(numPoints), 0.5 + (Math.random()-0.5)*0.6])
}
}
mutable previousTrack = "Open"
mutable points = mutable points
update()
document.querySelector(".reset").click()
}
// mutable knots = mutable knots
}
// dos()
}
Insert cell
Insert cell
Insert cell
// mutable clamped = true
Insert cell
// mutable uniform = false
Insert cell
Insert cell
function makeCurve() {
if(numP < 2){
return [[0,0]]
}
const curve = d3.range(steps).map(function(i) { return bspline((mutable knots)[numDegree]+((mutable knots)[numPoints]- (mutable knots)[numDegree])*i/steps);})
return curve;
}
Insert cell

function bspline(t)
{
let i=numDegree;
while(mutable knots[i+1]<=t)
{
i=i+1;
}
if(i>numPoints-1) i=numPoints-1;
var x=0;
var y=0;
for(let j = numDegree; j >= 0; j--){
x += bsplineBasis(i-j,numDegree+1)(t)*(mutable points)[i-j][0]
y += bsplineBasis(i-j,numDegree+1)(t)*(mutable points)[i-j][1]
}
return [x, y];
}
Insert cell
function bsplineBasis(i,k)
{
if(k==1)
{
return (function(t) { if((mutable knots[i]<=t) && (t<mutable knots[i+1])) {return 1;} else {return 0;}});
}
else
{
return (function(t) {
if(bsplineBasis(i,k-1)(t) == 0){
if(bsplineBasis(i+1,k-1)(t) == 0){
return 0;
}else{
return bsplineBasis(i+1,k-1)(t)*(mutable knots[i+k]-t)/(mutable knots[i+k]-mutable knots[i+1]);
}
}else if(bsplineBasis(i+1,k-1)(t)*(mutable knots[i+k]-t) == 0){
if(bsplineBasis(i,k-1)(t) == 0){
return 0;
}else{
return bsplineBasis(i,k-1)(t)*(t-mutable knots[i])/(knots[i+k-1]-mutable knots[i]);
}
}
else {
return bsplineBasis(i,k-1)(t)*(t-mutable knots[i])/(mutable knots[i+k-1]-mutable knots[i]) + bsplineBasis(i+1,k-1)(t)*(mutable knots[i+k]-t)/(mutable knots[i+k]-mutable knots[i+1]);
}
})
}
}

Insert cell
mutable numP = (points).length
Insert cell
mutable points = []
Insert cell
function dragObject(event){
console.log(event.sourceEvent.target)
console.log(event.sourceEvent.target.__data__)
let object = event.sourceEvent.target.__data__;
if(!object){
mutable points.push(object = [scale(event.x),scale(event.y)])
mutable numP = mutable points.length
console.log("dragobject")
update()
}else{
update()
}
return object
}
Insert cell
function update(){
// if(mutable subDivisionTracker == 0){
console.log("here123")
mutable knots = mutable knots
mutable degreeTracker = mutable degreeTracker
const pathGroup = svg.selectAll(".bs").data([0])
const pathGroupEnter = pathGroup.enter().append("path")
pathGroup.merge(pathGroupEnter).attr("class", "bs")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.5/500)
.attr("d", d => {
console.log("before rendering")
console.log(points)
console.log(knots)
if(knots.length > 0){
const cr = makeCurve()
return line(cr)
}else{
return ""
}
})

const hullGroup = svg.selectAll('.hull').data([0])
const hullGroupEnter = hullGroup.enter().append("path").attr("class", "hull")
hullGroup.merge(hullGroupEnter)
.attr("fill", "none")
.attr("stroke", "green")
.attr("stroke-width", 1.5/500)
.attr("d", line(mutable points))

const circle = svg.selectAll("g")
.data(mutable points, d=>d)
circle.enter().append("g")
.call(g => g.append("circle")
.attr("r", radius*2)
.attr("stroke", "black")
.attr("fill", "black")
.attr("stroke-width", radius/3)
).merge(circle)
.attr("transform", d => `translate(${d})`)
.select("circle:last-child")
.attr("fill", d=> {
return d===mutable selected ? "lightblue": "black"})
circle.exit().remove()

hullGroup.exit().remove()
pathGroup.exit().remove()
}
Insert cell
function dragStart({subject}){
// console.log(subject)
mutable selected = subject
mutable points = mutable points
console.log(selected)
console.log("dragStart")
update();
}
Insert cell
function dragged(event) {
event.subject[0] = scale(Math.max(0, Math.min(width*0.8, event.x)));
event.subject[1] = scale(Math.max(0, Math.min(width*0.8, event.y)));
mutable points = mutable points;
console.log("dragged")
update()
}
Insert cell
mutable selected = []
Insert cell
Insert cell
scale = d3.scaleLinear().domain([0,width*0.8]).range([0,1])
Insert cell
Insert cell
mutable clearTracker = 0
Insert cell
clear = {
if(clearButton != clearTracker){
mutable clearTracker = clearButton
console.log("clear")
while (mutable points.length > 0) {
mutable points.pop()
}

while (mutable knots.length > 0) {
mutable knots.pop()
}
mutable points = mutable points
mutable knots = mutable knots
mutable numP = 0
// mutable clamped = true
d3.select(".addBtn1").style("color", "black")
svg.selectAll("*").remove()
}
}
Insert cell
function keydown(event) {
if (!mutable selected) return;
switch (event.key) {
case "Backspace":
case "Delete": {
event.preventDefault();
const i = mutable points.indexOf(selected);
mutable points.splice(i, 1);
mutable points = mutable points;
mutable numP = mutable points.length;
mutable selected = mutable points.length ? mutable points[i > 0 ? i - 1 : 0] : null;
// knotsInitialize()
console.log("Keydown")
update();
break;
}
}
}
Insert cell
line = d3.line()
Insert cell
mutable degreeTracker = 0
Insert cell
mutable numPointTracker = 0
Insert cell
knots[1]
Insert cell
function deBoor(t)
{
let i=numDegree;
while(knots[i+1]<t)
{
i=i+1;
}
if(i>numP) i=numP;
const res = deBoorRecurse(i, numDegree, t)
return [res.x, res.y]
}
Insert cell
function deBoorRecurse(i,r,t)
{
if(r==0) return {'x':points[i][0], 'y':points[i][1]};
let a=(t-knots[i])/(knots[i+4-r]-knots[i]);
let qq={"r":r,"x":((1-a)*deBoorRecurse(i-1,r-1,t).x+a*deBoorRecurse(i,r-1,t).x),"y":((1-a)*deBoorRecurse(i-1,r-1,t).y+a*deBoorRecurse(i,r-1,t).y)};
return qq;
}
Insert cell
mutable initializationTracker = 0
Insert cell
initialzeCanvas = {
if(initializeButton > 0 && initializeButton != initializationTracker){
mutable initializationTracker = initializeButton
if(inputFormat === "Input Number"){
// mutable points = d3.range(0, numPoints).map(i => [0.1 + i * 0.9/(numPoints), 0.5 + (Math.random()-0.5)*0.6])
while(mutable points.pop()){
continue
}
d3.range(0, numPoints).map(i => [0.1 + i * 0.9/(numPoints), 0.5 + (Math.random()-0.5)*0.6]).forEach(obj => {
mutable points.push(obj)
})
mutable numP = mutable points.length
}else{
mutable points = pointsStorageFromFile
}
update()
}
}
Insert cell
function outputString(){
console.log("output!!!!!")
// mutable uniformTracker = false
// mutable closeTracker = false
// mutable openTracker = false
// mutable clampedTracker = false
let text = ``
text += "BSPLINE\n"
text += "# Sample file containing Bspline control points\n"
text += "# {dimension} {number of points} {degree}\n"
text += "" + 2 + " " + (mutable points.length) + " " + (numDegree) + "\n"

knots.forEach(obj => text+= obj+" ")
text += "\n"
points.forEach(obj => {
text += "" + obj[0] + " " + obj[1] + "\n"
})
return text
}
Insert cell
dataType = ["Input Number", "Text File"]
Insert cell
d3 = require("d3@6")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more