zotero-better-notes/addon/chrome/content/mindMap.html

336 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<body>
<script src="chrome://__addonRef__/content/lib/js/go.js"></script>
<style>
html,
body,
div {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#canvas {
position:absolute;
height:100%; width:100%;
}
</style>
<div id="allSampleContent" class="p-4 w-full">
<script id="code">
function init() {
window.addEventListener('message', handler, false)
// Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make
// For details, see https://gojs.net/latest/intro/buildingObjects.html
const $ = go.GraphObject.make;
myDiagram = $(go.Diagram, "myDiagramDiv", {
"commandHandler.copiesTree": true,
"commandHandler.copiesParentKey": true,
"commandHandler.deletesTree": true,
"draggingTool.dragsTree": true,
"undoManager.isEnabled": true,
initialAutoScale: go.Diagram.UniformToFill,
layout: $(go.TreeLayout,
{ comparer: go.LayoutVertex.smartComparer })
});
// a node consists of some text with a line shape underneath
myDiagram.nodeTemplate = $(
go.Node,
"Vertical",
{ selectionObjectName: "TEXT" },
$(
go.TextBlock,
{
name: "TEXT",
minSize: new go.Size(30, 15),
editable: true,
},
// remember not only the text string but the scale and the font in the node data
new go.Binding("text", "text").makeTwoWay(),
new go.Binding("scale", "scale").makeTwoWay(),
new go.Binding("font", "font").makeTwoWay()
),
$(
go.Shape,
"LineH",
{
stretch: go.GraphObject.Horizontal,
strokeWidth: 3,
height: 3,
// this line shape is the port -- what links connect with
portId: "",
fromSpot: go.Spot.LeftRightSides,
toSpot: go.Spot.LeftRightSides,
},
new go.Binding("stroke", "brush"),
// make sure links come in from the proper direction and go out appropriately
new go.Binding("fromSpot", "dir", (d) => spotConverter(d, true)),
new go.Binding("toSpot", "dir", (d) => spotConverter(d, false))
),
// remember the locations of each node in the node data
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
go.Point.stringify
),
// make sure text "grows" in the desired direction
new go.Binding("locationSpot", "dir", (d) =>
spotConverter(d, false)
)
);
// selected nodes show a button for adding children
myDiagram.nodeTemplate.selectionAdornmentTemplate = $(
go.Adornment,
"Spot",
$(
go.Panel,
"Auto",
// this Adornment has a rectangular blue Shape around the selected node
$(go.Shape, { fill: null, stroke: "dodgerblue", strokeWidth: 3 }),
$(go.Placeholder, { margin: new go.Margin(4, 4, 0, 4) })
),
// and this Adornment has a Button to the right of the selected node
$(
"Button",
{
alignment: go.Spot.Right,
alignmentFocus: go.Spot.Left,
click: jumpNode, // define click behavior for this Button in the Adornment
},
$(
go.TextBlock,
"↗️", // the Button content
{ font: "bold 8pt sans-serif" }
)
)
);
// a link is just a Bezier-curved line of the same color as the node to which it is connected
myDiagram.linkTemplate = $(
go.Link,
{
curve: go.Link.Bezier,
fromShortLength: -2,
toShortLength: -2,
selectable: false,
},
$(
go.Shape,
{ strokeWidth: 3 },
new go.Binding("stroke", "toNode", (n) => {
if (n.data.brush) return n.data.brush;
return "black";
}).ofObject()
)
);
myDiagram.addDiagramListener("SelectionMoved", (e) => {
var rootX = myDiagram.findNodeForKey(0).location.x;
myDiagram.selection.each((node) => {
if (node.data.parent !== 0) return; // Only consider nodes connected to the root
var nodeX = node.location.x;
if (rootX < nodeX && node.data.dir !== "right") {
updateNodeDirection(node, "right");
} else if (rootX > nodeX && node.data.dir !== "left") {
updateNodeDirection(node, "left");
}
layoutTree(node);
});
});
// read in the predefined graph using the JSON format data held in the "mySavedModel" textarea
window.parent.postMessage({type: "ready"}, "*");
getData()
}
function spotConverter(dir, from) {
if (dir === "left") {
return from ? go.Spot.Left : go.Spot.Right;
} else {
return from ? go.Spot.Right : go.Spot.Left;
}
}
function changeTextSize(obj, factor) {
var adorn = obj.part;
adorn.diagram.startTransaction("Change Text Size");
var node = adorn.adornedPart;
var tb = node.findObject("TEXT");
tb.scale *= factor;
adorn.diagram.commitTransaction("Change Text Size");
}
function toggleTextWeight(obj) {
var adorn = obj.part;
adorn.diagram.startTransaction("Change Text Weight");
var node = adorn.adornedPart;
var tb = node.findObject("TEXT");
// assume "bold" is at the start of the font specifier
var idx = tb.font.indexOf("bold");
if (idx < 0) {
tb.font = "bold " + tb.font;
} else {
tb.font = tb.font.slice(idx + 5);
}
adorn.diagram.commitTransaction("Change Text Weight");
}
function updateNodeDirection(node, dir) {
myDiagram.model.setDataProperty(node.data, "dir", dir);
// recursively update the direction of the child nodes
var chl = node.findTreeChildrenNodes(); // gives us an iterator of the child nodes related to this particular node
while (chl.next()) {
updateNodeDirection(chl.value, dir);
}
}
function layoutTree(node) {
if (node.data.key === 0) {
// adding to the root?
layoutAll(); // lay out everything
} else {
// otherwise lay out only the subtree starting at this parent node
var parts = node.findTreeParts();
layoutAngle(parts, node.data.dir === "left" ? 180 : 0);
}
}
function layoutAngle(parts, angle) {
var layout = go.GraphObject.make(go.TreeLayout, {
angle: angle,
arrangement: go.TreeLayout.ArrangementFixedRoots,
nodeSpacing: 5,
layerSpacing: 20,
setsPortSpot: false, // don't set port spots since we're managing them with our spotConverter function
setsChildPortSpot: false,
});
layout.doLayout(parts);
}
function layoutAll() {
var root = myDiagram.findNodeForKey(0);
if (root === null) return;
myDiagram.startTransaction("Layout");
// split the nodes and links into two collections
var rightward = new go.Set(/*go.Part*/);
var leftward = new go.Set(/*go.Part*/);
root.findLinksConnected().each((link) => {
var child = link.toNode;
if (child.data.dir === "left") {
leftward.add(root); // the root node is in both collections
leftward.add(link);
leftward.addAll(child.findTreeParts());
} else {
rightward.add(root); // the root node is in both collections
rightward.add(link);
rightward.addAll(child.findTreeParts());
}
});
// do one layout and then the other without moving the shared root node
layoutAngle(rightward, 0);
layoutAngle(leftward, 180);
myDiagram.commitTransaction("Layout");
}
function getData(){
window.parent.postMessage({type: "getMindMapData"}, "*");
}
function setData(nodes){
const data = {
class: "go.TreeModel",
nodeDataArray: [{ key: 999, text: "📄", parent: undefined }],
};
const colors = []
for (const node of nodes) {
const parent = node.parent.model.id === -1? 999:node.parent.model.id;
data.nodeDataArray.push({
key: node.model.id,
text: `${node.model.rank===7?'🔗':''}${node.model.name.slice(0,50)}${node.model.name.length>=50?'...':''}`,
parent: parent,
lineIndex: node.model.lineIndex,
noteLink: node.model.rank===7?node.model.link:'',
brush: go.Brush.randomColor()
});
}
myDiagram.model = go.Model.fromJson(data);
}
function jumpNode(e, obj) {
var adorn = obj.part;
var oldnode = adorn.adornedPart;
var olddata = oldnode.data;
if(olddata.noteLink){
window.parent.postMessage({type: "jumpNote", link: olddata.noteLink, id: olddata.key}, "*");
}else{
window.parent.postMessage({type: "jumpNode", lineIndex: olddata.lineIndex, id: olddata.key}, "*");
}
}
function handler(e){
console.log(e)
if(e.data.type === "setMindMapData"){
setData(e.data.nodes)
}
}
window.addEventListener("DOMContentLoaded", ()=>{
try{
init()
}catch(e){
window.parent.postMessage({type: "error", event: e}, "*");
}
});
var resizeTime = new Date().getTime()
window.addEventListener('resize', (e)=>{
const canvas = document.getElementsByTagName("canvas")[0]
const div = document.getElementById('myDiagramDiv')
canvas.setAttribute('height', div.getAttribute('height'))
canvas.setAttribute('width', div.getAttribute('width'))
const currentResize = new Date().getTime()
resizeTime = currentResize
// Delay update
setTimeout(()=>{
if(resizeTime === currentResize){
getData()
}
}, 500)
})
</script>
<div id="sample">
<div
id="myDiagramDiv"
style="
width: 100%;
position: relative;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
cursor: auto;
font: 13px sans-serif;
overflow: hidden;
"
>
<canvas
tabindex="0"
style="
position: absolute;
top: 0px;
left: 0px;
z-index: 2;
user-select: none;
touch-action: none;
cursor: auto;
"
>This text is displayed if your browser does not support the Canvas
HTML element.</canvas
>
</div>
</div>
</body>
</html>