Published
Edited
Dec 20, 2019
Insert cell
md`# Visual Control`
Insert cell
html `<div><div style="width:50%" id="control1" ></div><div style="width:50%" id="control2" ></div></div>`
Insert cell
{
mutable ar = parse("m26.45834,0c0,14.61254 -11.8458,26.45834 -26.45834,26.45834c-14.61254,0 -26.45833,-11.8458 -26.45833,-26.45834c0,-7.30627 2.96145,-13.92085 7.74947,-18.70886c2.394,-2.39401 5.24465,-4.33138 8.41008,-5.67024c3.16544,-1.33887 8.02987,-6.42491 10.29878,-8.69382c2.40868,2.40868 7.13335,7.35495 10.29878,8.69382c3.16543,1.33886 6.01608,3.27623 8.41009,5.67023c4.78802,4.78802 7.74947,11.4026 7.74947,18.70887z")
//set("control1", ar,200)
console.log(ar)
//return arrayToString(ar)
}
Insert cell
mutable ar =[]
Insert cell
Insert cell
set("control1", [1,1,1,1,1,1,1,1,11,1,1,1,1,1,1,1,1,1,11],200)
Insert cell
set("control2", [1,1],200,0)
Insert cell
d3.range(5).map(i => ({
x: ar[i][1],
y: ar[i][2],
}))
Insert cell
set = function(divId, pathArray, w, h){
const radius = w/75
const strokeW = w/500
if (h === undefined) h = w/Math.sqrt(2)
const div = d3.select("#"+divId)
div.node().innerHTML = ""
area[divId] = [w,h]
const svg = div.append(`svg`)
.attr("viewBox", [-strokeW-radius, -strokeW-radius, w+2*strokeW+2*radius, h+2*strokeW+2*radius])
.attr("stroke-width", strokeW);
attrs(svg.append("rect"), {width:w+2*radius,height:h+2*radius,rx:radius,ry:radius, "stroke-width":strokeW,stroke:"#000", x:-radius, y:-radius,fill:"#fff"})

const circles = d3.range(pathArray.length-1).map(i => ({
x: pathArray[i][1],
y: pathArray[i][2],
}));

svg.selectAll("circle")
.data(circles)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", radius)
.attr("fill", (d, i) => d3.schemeCategory10[i % 1])
.on("click", click)
.call(drag)

return svg.node();
}
Insert cell
function attrs(select, obj){
for (let key in obj) {
select.attr(key, obj[key])
}
}
Insert cell
area =({})
Insert cell
function click(d){
//if (d3.event.defaultPrevented)
console.log("click2")
}
Insert cell
drag = {
function dragstarted(d) {
d3.select(this).raise().attr("stroke", "black");
console.log(d)
d3.event.s = d
}

function dragged(d) {
let x = d3.event.x, y = d3.event.y
if (x < 0) x=0
if (y < 0) y=0
if (x > area["control1"][0]) x=area["control1"][0]
if (y > area["control1"][1]) y=area["control1"][1]
console.log("d",d,d3.event)
d3.select(this).attr("cx", d.x = x).attr("cy", d.y = y);
}

function dragended(d) {
console.log("d",d,d3.event)
if ( d === d3.event.s) console.log("click")
d3.select(this).attr("stroke", null);
}

return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
.clickDistance(5)
//.on("click", click);
}
Insert cell
class Point {
// Initialize
constructor (...args) {
this.init(...args)
}

init (x, y) {
const base = { x: 0, y: 0 }

// ensure source as object
const source = Array.isArray(x) ? { x: x[0], y: x[1] }
: typeof x === 'object' ? { x: x.x, y: x.y }
: { x: x, y: y }

// merge source
this.x = source.x == null ? base.x : source.x
this.y = source.y == null ? base.y : source.y

return this
}

// Clone point
clone () {
return new Point(this)
}



toArray () {
return [ this.x, this.y ]
}
}
Insert cell
function arrayToString (a) {
for (var i = 0, il = a.length, s = ''; i < il; i++) {
s += a[i][0]

if (a[i][1] != null) {
s += a[i][1]

if (a[i][2] != null) {
s += ' '
s += a[i][2]

if (a[i][3] != null) {
s += ' '
s += a[i][3]
s += ' '
s += a[i][4]

if (a[i][5] != null) {
s += ' '
s += a[i][5]
s += ' '
s += a[i][6]

if (a[i][7] != null) {
s += ' '
s += a[i][7]
}
}
}
}
}
}

return s + ' '
}
Insert cell
function parse (array = [ [ 'M', 0, 0 ] ]) {
// if it's already a patharray, no need to parse it
//if (array instanceof PathArray) return array
let mlhvqtcsaz = 'mlhvqtcsaz'.split('')

for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
settings.pathHandlers[mlhvqtcsaz[i]] = (function (i) {
return function (c, p, p0) {
if (i === 'H') c[0] = c[0] + p.x
else if (i === 'V') c[0] = c[0] + p.y
else if (i === 'A') {
c[5] = c[5] + p.x
c[6] = c[6] + p.y
} else {
for (var j = 0, jl = c.length; j < jl; ++j) {
c[j] = c[j] + (j % 2 ? p.y : p.x)
}
}

return settings.pathHandlers[i](c, p, p0)
}
})(mlhvqtcsaz[i].toUpperCase())
}

// prepare for parsing
var s
var paramCnt = { M: 2, L: 2, H: 1, V: 1, C: 6, S: 4, Q: 4, T: 2, A: 7, Z: 0 }
function pathRegReplace (a, b, c, d) {
return c + d.replace(settings.dots, ' .')
}

if (typeof array === 'string') {
array = array
.replace(settings.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
.replace(settings.pathLetters, ' $& ') // put some room between letters and numbers
.replace(settings.hyphen, '$1 -') // add space before hyphen
.trim() // trim
.split(settings.delimiter) // split into array
console.log("ff",array)
} else {
array = array.reduce(function (prev, curr) {
return [].concat.call(prev, curr)
}, [])
}

// array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
var result = []
var p = new Point()
var p0 = new Point()
var index = 0
var len = array.length

do {
// Test if we have a path letter
if (settings.isPathLetter.test(array[index])) {
s = array[index]
++index
// If last letter was a move command and we got no new, it defaults to [L]ine
} else if (s === 'M') {
s = 'L'
} else if (s === 'm') {
s = 'l'
}
console.log("gg",array, s)

result.push(settings.pathHandlers[s].call(null,
array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),
p, p0
)
)
} while (len > index)

return result
}
Insert cell
d3 = require("d3@5")
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