107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
import os
|
|
|
|
path = "core/templates/core/project_detail.html"
|
|
with open(path, "r") as f:
|
|
html = f.read()
|
|
|
|
# 1. Add top bar buttons (Layout, Zoom, etc)
|
|
buttons_to_add = """
|
|
<select id="layout-select" class="form-select form-select-sm d-inline-block w-auto me-2" onchange="changeLayout(this.value)">
|
|
<option value="organic">Organic Layout</option>
|
|
<option value="hierarchical">Hierarchical Layout</option>
|
|
</select>
|
|
<div class="btn-group btn-group-sm me-2" role="group">
|
|
<button type="button" class="btn btn-outline-secondary" onclick="zoomIn()" title="Zoom In">+</button>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="zoomOut()" title="Zoom Out">-</button>
|
|
</div>"""
|
|
|
|
html = html.replace('<button class="btn btn-sm btn-outline-primary" onclick="fitNetwork()">Reset View</button>',
|
|
buttons_to_add + '\n <button class="btn btn-sm btn-outline-primary" onclick="fitNetwork()">Reset View</button>')
|
|
|
|
# 2. Add emoji logic
|
|
emoji_script = """
|
|
const categoryEmojis = {
|
|
'Strategy': '🎯',
|
|
'Product': '📦',
|
|
'Market': '🌍',
|
|
'Operations': '⚙️',
|
|
'Finance': '💰',
|
|
'General': '💡'
|
|
};
|
|
|
|
function getNodeEmoji(category) {
|
|
let cat = category || 'General';
|
|
for (let key in categoryEmojis) {
|
|
if (cat.toLowerCase().includes(key.toLowerCase())) {
|
|
return categoryEmojis[key];
|
|
}
|
|
}
|
|
return '💡'; // default emoji
|
|
}
|
|
"""
|
|
|
|
html = html.replace('function getNodeColor(category) {', emoji_script + '\n function getNodeColor(category) {')
|
|
|
|
# update node array to include emoji
|
|
html = html.replace('label: "{{ node.title|escapejs }}",', 'label: getNodeEmoji("{{ node.category|escapejs }}") + " " + "{{ node.title|escapejs }}",')
|
|
|
|
# 3. Add script functions for zoom and layout
|
|
scripts_to_add = """
|
|
function zoomIn() {
|
|
if (network) {
|
|
const scale = network.getScale() * 1.5;
|
|
network.moveTo({ scale: scale, animation: { duration: 300, easingFunction: 'easeInOutQuad' } });
|
|
}
|
|
}
|
|
|
|
function zoomOut() {
|
|
if (network) {
|
|
const scale = network.getScale() / 1.5;
|
|
network.moveTo({ scale: scale, animation: { duration: 300, easingFunction: 'easeInOutQuad' } });
|
|
}
|
|
}
|
|
|
|
function changeLayout(layoutType) {
|
|
if (layoutType === 'hierarchical') {
|
|
network.setOptions({
|
|
layout: {
|
|
hierarchical: {
|
|
enabled: true,
|
|
direction: 'UD',
|
|
sortMethod: 'directed',
|
|
nodeSpacing: 200,
|
|
levelSeparation: 150
|
|
}
|
|
},
|
|
physics: {
|
|
hierarchicalRepulsion: {
|
|
nodeDistance: 200
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
network.setOptions({
|
|
layout: { hierarchical: { enabled: false } },
|
|
physics: {
|
|
solver: 'forceAtlas2Based',
|
|
forceAtlas2Based: {
|
|
gravitationalConstant: -100,
|
|
centralGravity: 0.01,
|
|
springLength: 150,
|
|
springConstant: 0.08
|
|
},
|
|
maxVelocity: 50,
|
|
minVelocity: 0.1,
|
|
timestep: 0.5,
|
|
stabilization: { iterations: 150 }
|
|
}
|
|
});
|
|
}
|
|
}
|
|
"""
|
|
hTml = html.replace('// Export Map function', scripts_to_add + '\n // Export Map function')
|
|
|
|
with open(path, "w") as f:
|
|
f.write(html)
|
|
print("Updated HTML!")
|