123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- // https://observablehq.com/@jinnace/sticky-force-layout@137
- export default function define(runtime, observer) {
- const main = runtime.module();
- yglob.m = main
- main.variable(observer()).define(["md"], function(md){return(
- md`# Sticky Force Layout
-
- In a [force simulation](https://github.com/d3/d3-force#simulation_nodes), we set *d.*fx = x and *d.*fy = y while dragging, to fix the nodes in the ⟨x,y⟩ position after they have been repositioned by the user.
-
- Click on a node to release it from its fixed position. Note that the force layout resumes automatically on drag. This ensures that other nodes in the graph respond naturally to the dragged node’s movement.
- `
- )});
- // main.variable(observer()).define(["d3","width","height","graph","clamp"], function*(d3,width,height,graph,clamp)
- // main.variable(observer("chart")).define("chart", ["data","d3","width","height","types","color","location","drag","linkArc","invalidation"], function(data,d3,width,height,types,color,location,drag,linkArc,invalidation)
- // main.variable(observer()).define( ["d3","width","height","graph","clamp"], function(d3,width,height,graph,clamp)
- main.variable(observer()).define(["d3","width","height","graph","clamp"], function*(d3,width,height,graph,clamp)
- {
- clog("vbox")
- var cwidth,cheight,cx,cy
- var cwidth_,cheight_,cx_,cy_
- if (1 || yglob.svg_m > 1){
- cwidth_ = width * (yglob.svg_m - 1)/2
- cheight_ = height * (yglob.svg_m - 1)/2
- cwidth = width*yglob.svg_m - cwidth_
- cheight = height*yglob.svg_m - cheight_
- cx = 0 - cwidth_
- cy = 0 - cheight_
-
-
- } else {
- cwidth = width*yglob.svg_m
- cheight = height*yglob.svg_m
- cx =0
- cy = 0
- }
- clog("vbox",{cwidth,cheight,cx,cy,cwidth_,cheight_})
-
- // const svg = d3.create("svg").attr("viewBox", [0, 0, width*yglob.svg_m, height*yglob.svg_m]),
- const svg = d3.create("svg").attr("viewBox", [cx, cy, cwidth, cheight]),
- link = svg
- .selectAll(".link")
- .data(graph.links)
- .join("line")
- .classed("link", true)
-
- /*
-
- node = svg
- .selectAll(".node")
- .data(graph.nodes)
- .join("circle")
- .attr("r", 12)
- .classed("node", true)
- .classed("fixed", d => d.fx !== undefined);
- // .join("g")
- // .attr("r", 12)
- // .classed("node", true)
- // .classed("fixed", d => d.fx !== undefined);
- //
-
- */
-
-
- /*
- const node = svg
- .selectAll(".node")
- .data(graph.nodes)
- .join("circle")
- .attr("r", 12)
- .classed("node", true)
- .classed("fixed", d => d.fx !== undefined);
- */
-
- // svg.append("g").attr("id","tx").classed("tnodex", true).text("Q")
- // /*
-
-
-
- const node = svg
- .selectAll(".node")
- .data(graph.nodes)
- .join("g")
- .attr("r", 12)
- .classed("node", true)
- .classed("fixed", d => d.fx !== undefined)
-
-
- svg.append("text").attr("id","tx").classed("tnodex", true).text("Q")
- // */
-
- const node_l = svg.append("g").classed("n2",1)
- .selectAll("g")
- // .selectAll(".node")
- .data(graph.nodes)
- // .join("circle")
- .join("g")
-
- // .attr("x", "16px")
- // .attr("transform", "translate(40,2)")
- .attr("fill", "#0ff")
- .classed("node", true)
- .classed("node_l", true)
- .classed("fixed", (d) => {clog("zx~",d);return d.fx !== undefined})
- .classed("fx", glob_dev_fns.cls_picker || nop)
- // const node = node_l
- //
- node_l.append("circle")
- .attr("r", 6)
- .attr("transform", "translate(1,-18)")
- // svg.selectAll("#tx").after(node_l)
- // svg.selectAll
- /*
-
- .join("circle")
- .attr("r", 12)
- .classed("node", true)
- .classed("fixed", d => d.fx !== undefined);
-
-
-
-
-
-
-
-
-
-
- /*
-
-
- node.append("circle")
- .attr("r", 12)
- .classed("node", true)
- .classed("fixed", d => {
- clog("C")
- return d.fx !== undefined || 11
- }).clone(true)
-
- */
- // .classed("fixed", d => d.fx !== undefined || 11).clone(true)
-
-
- console.log("z61",graph,graph.nodes)
- console.log("z62",graph.nodes,length)
- var kx,vx
- for (vx of graph.nodes){
- clog("z~",vx)
- }
- console.log("NODE.",svg)
- // var z = node.append("use").attr("href","#tx")
- var z = node.append("text")
- .attr("x", 10)
- // .attr("y", "0.3em")
- .attr("y", "1em")
- // .attr("fill","#000")
- /*
- .style("border-bottom-color","#000")
- .attr("border-bottom-color","#000")
-
-
- .attr("text-decoration","underline")
- .attr("text-decoration-color","#00f")
- .attr("text-decoration-style","wavy")
-
- .style("text-decoration","underline")
- .style("text-decoration-color","#00f")
- .style("text-decoration-style","wavy")
-
- .style("text-decoration-color","#00f")
- .attr("underline-thickness",3)
- .attr("stroke", "#004")
- .style("stroke", "#004")
- .attr("stroke-width", 0)
- */
- .text(d => {clog(d.id,d,this); return d.index + " Z"})
- // .text(d => {clog(d.id,d,this); return d.index + " Z"}).append("text").text("???")
- node.append("circle").attr("r", 12)
-
- // node.style("border-bottom-color","#000")
- // node.attr("border-bottom-color","#000")
- // border-bottom-color: blue;
-
- // .attr("fill","#0ff")
- // .style("background","#0ff")
- // .style(`background:#0ff;`)
- // .style({background:"#0ff"})
- // .css({background:"#0ff"})
-
- console.log("NODE",svg,node,[z],z.style,[svg.node])
-
-
- /*
- let transform;
- const zoom = d3.zoom().on("zoom", e => {
- node.attr("transform", (transform = e.transform));
- node.style("stroke-width", 3 / Math.sqrt(transform.k));
- // points.attr("r", 3 / Math.sqrt(transform.k));
- });
-
- svg.call(zoom)
- .call(zoom.transform, d3.zoomIdentity)
- */
-
-
-
- yield svg.node();
- /*
- clog("z?",graph)
- for (vx of graph.nodes){
- clog("z~",vx)
- }
- */
- // dev_dec_gen(glob_dev_fns.forceManyBody,"forceManyBody_",[])
- // dev_dec_gen(glob_dev_fns.forceCenter,"forceCenter_",[width / 2, height / 2])
- // dev_dec_gen(glob_dev_fns.forceLink,"forceLink_",[graph.links])
-
- // glob_dev_fns.forceManyBody_
- // glob_dev_fns.forceCenter_
- // glob_dev_fns.forceLink_
- // clog()
-
-
-
- clog("d3_",d3,d3.evl,d3.evl(glob_dev_fns.forceManyBody + ""))
- Object.assign(window.yglob,{d3})
-
- const simulation = d3
- .forceSimulation()
- .nodes(graph.nodes)
-
- .force("charge",dev_dec_gen(glob_dev_fns.forceManyBody,"forceManyBody_",[]))
- .force("center",dev_dec_gen(glob_dev_fns.forceCenter,"forceCenter_",[width / 2, height / 2]))
- .force("link", dev_dec_gen(glob_dev_fns.forceLink,"forceLink_",[graph.links]))
-
- // .force("charge", d3.forceManyBody())
- // .force("center", d3.forceCenter(width / 2, height / 2))
- // .force("link", d3.forceLink(graph.links))
-
- .on("tick", tick);
-
-
- /*
-
-
- .force("charge", d3.evl(`clog("d3_~");ret= `+glob_dev_fns.forceManyBody)())
- .force("center", d3.evl(`clog("d3_~");ret= `+glob_dev_fns.forceCenter)(width / 2, height / 2))
- .force("link", d3.evl(`clog("d3_~");ret= `+glob_dev_fns.forceLink)(graph.links))
-
-
- .force("charge", glob_dev_fns.forceManyBody())
- .force("center", glob_dev_fns.forceCenter(width / 2, height / 2))
- .force("link", glob_dev_fns.forceLink(graph.links))
-
- .force("charge", d3.forceManyBody())
- .force("center", d3.forceCenter(width / 2, height / 2))
- .force("link", d3.forceLink(graph.links))
-
-
-
-
- .force("charge", d3.evl(`
- clog("d3_C")
- ret.fn=` +glob_dev_fns.forceManyBody + "").fn())
- .force("center", d3.evl(`
- clog("d3_C")
- ret.fn=` +glob_dev_fns.forceCenter + "").fn(width / 2, height / 2))
- .force("link", d3.evl(`
-
- clog("d3_C")
- ret.fn=` +glob_dev_fns.forceLink + "").fn(graph.links))
-
-
-
-
-
-
- */
-
-
-
-
-
-
-
- const drag = d3
- .drag()
- .on("start", dragstart)
- .on("drag", dragged);
-
- node.call(drag).on("click", click);
- node_l.call(drag).on("click", click);
-
- function tick() {
- return glob_dev_fns["tick"].apply(this,arguments)
- }
- function click(event, d) {
- return glob_dev_fns["click"].apply(this,arguments)
- }
- function dragstart() {
- return glob_dev_fns["dragstart"].apply(this,arguments)
- }
- function dragged(event, d) {
- return glob_dev_fns["dragged"].apply(this,arguments)
- }
- // function tick() {}
-
- function tick_() {
- link
- .attr("x1", d => d.source.x)
- .attr("y1", d => d.source.y)
- .attr("x2", d => d.target.x)
- .attr("y2", d => d.target.y);
- node.attr("transform", d => `translate(${d.x},${d.y})`);
- node_l.attr("transform", d => `translate(${d.x},${d.y})`);
- // node.find("text").text(d => `${d.index} z?`)
- // node.text(d => `${d.index} z?`)
- // node.text(d => { // clog("Ntxt") return`${d.index} z?`})
- z.text(d => {
- // clog("Ntxt")
- return`${d.index} ${d.i2 != undefined ? d.i2 : "_"}`
- return`${d.index} ${d.i2 || "_"}`
- return`${d.index} ${d.x.toFixed(2)},${d.y.toFixed(2)}`
- })
- if (!yglob.n1){
- clog("vbx",node,z)
- yglob.n1 =1
- }
- // node
- // clog("t`",this,arguments)
- // node_l.attr("transform", d => `translate(${d.x},${d.y})`);
- // node_l.attr("transform", d => `translate(${d.x},${d.y})`);
- /*
- node
- .attr("cx", d => d.x)
- .attr("cy", d => d.y);
- */
- }
-
- function click_(event, d) {
- delete d.fx;
- delete d.fy;
- clog("click")
- d3.select(this).classed("fixed", false);
- simulation.alpha(1).restart();
- }
-
- function dragstart_() {
- clog("cli drag")
- d3.select(this).classed("fixed", true);
- }
-
- function dragged_(event, d) {
- d.fx = clamp(event.x, 0, width);
- d.fy = clamp(event.y, 0, height);
- // clog("DRAGGED2")
- // simulation.alpha(0).restart();
- simulation.alpha(1).restart();
- }
- glob_dev_fns["tick"] = tick_
- glob_dev_fns["click"] = click_
- glob_dev_fns["dragstart"] = dragstart_
- glob_dev_fns["dragged"] = dragged_
-
- glob_dev_fns["tick_"] = tick_
- glob_dev_fns["click_"] = click_
- glob_dev_fns["dragstart_"] = dragstart_
- glob_dev_fns["dragged_"] = dragged_
-
- clog(":vbox")
- window.yglob = window.yglob || {}
- Object.assign(window.yglob,{simulation,d3})
- // window.yglob = {simulation}
- }
- );
- main.variable(observer("d3")).define("d3", ["require"], function(require){return(
- // clog("D3 .0")
- require("/ign/libs/d3_.js")
- // require("d3@6")
- // clog("D3 .1")
- )});
- main.variable(observer("height")).define("height", ["width"], function(width){return(
- Math.min(500, width * 0.6)
- )});
- main.variable(observer("clamp")).define("clamp", function(){return(
- function clamp(x, lo, hi) {
- return x < lo ? lo : x > hi ? hi : x;
- }
- )});
- /*
- main.variable(observer()).define(["html"], function(html){return(
- html`<style>
-
- .link {
- stroke: #000;
- stroke-width: 1.5px;
- }
-
- .node {
- cursor: move;
- fill: #ccc;
- stroke: #000;
- stroke-width: 1.5px;
- }
-
- .node.fixed {
- fill: #f00;
- }
-
- </style>`
- )});
- */
- main.variable(observer("graph")).define("graph", function(){
- clog("d3_mg")
-
-
- // return(
- const ret = (
- {
- // nodes: Array.from({length:10}, () => ({})),
- nodes: Array.from({length:16}, () => ({})),
- // nodes: Array.from({length:13}, () => ({})),
- links: [
- { source: 0, target: 1 },
- { source: 1, target: 2 },
- { source: 2, target: 0 },
- { source: 1, target: 3 },
- { source: 3, target: 2 },
- { source: 3, target: 4 },
- { source: 4, target: 5 },
- { source: 5, target: 6 },
- { source: 5, target: 7 },
- { source: 6, target: 7 },
- { source: 6, target: 8 },
- { source: 7, target: 8 },
- { source: 9, target: 4 },
- { source: 9, target: 11 },
- { source: 9, target: 10 },
- { source: 10, target: 11 },
- { source: 11, target: 12 },
- { source: 12, target: 10 },
- { source: 13, target: 14 },
- ]
- }
- )
- window.yglob.main = ret
- return ret
- });
- return main;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- // window.yglob.dbg_flags
- // window.yglob.dbg_flags.
-
-
-
-
-
-
- window.yglob = window.yglob || {
- svg_m:1,
- dbg_flags:{
- center:1,
- center_f:1,
- },
-
- }
-
-
-
-
-
-
- // clog("vbox..0")
|