Skip to content

Commit 3f84b01

Browse files
authored
Merge pull request #31 from flamapy/develop
feat: Improve visualization component
2 parents 8c04506 + 2ec38a4 commit 3f84b01

File tree

8 files changed

+87
-12
lines changed

8 files changed

+87
-12
lines changed

Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Default output directory for wheels
2+
WHEELS_DIR = assets
3+
4+
# Define the package (can be overridden in the command)
5+
PACKAGE ?=
6+
7+
.PHONY: help
8+
help:
9+
@echo "Makefile for managing Python dependencies"
10+
@echo ""
11+
@echo "Usage:"
12+
@echo " make dependencies PACKAGE=<package_name> Download and build wheels for a package"
13+
@echo " make clean Remove all downloaded files in $(WHEELS_DIR)"
14+
@echo " make clean-tar Remove only source tarballs (.tar.gz, .zip)"
15+
@echo " make help Show this help message"
16+
17+
.PHONY: dependencies
18+
dependencies:
19+
@mkdir -p $(WHEELS_DIR)
20+
@echo "Downloading wheels and source distributions for $(PACKAGE)..."
21+
@pip download --dest $(WHEELS_DIR) $(PACKAGE) || true
22+
@echo "Checking for missing wheels..."
23+
@pip install --no-cache-dir --find-links=$(WHEELS_DIR) $(PACKAGE) || true
24+
@echo "Building missing wheels for $(PACKAGE)..."
25+
@pip wheel --find-links=$(WHEELS_DIR) --wheel-dir $(WHEELS_DIR) $(PACKAGE) || true
26+
@echo "All dependencies for $(PACKAGE) have been downloaded and built in $(WHEELS_DIR)"
27+
@$(MAKE) clean-tar # Automatically clean tar files after building
28+
29+
.PHONY: clean
30+
clean:
31+
@rm -rf $(WHEELS_DIR)
32+
@echo "Cleaned up $(WHEELS_DIR)"
33+
34+
.PHONY: clean-tar
35+
clean-tar:
36+
@find $(WHEELS_DIR) -type f \( -name "*.tar.gz" -o -name "*.zip" \) -delete
37+
@echo "Removed source distributions (.tar.gz, .zip) from $(WHEELS_DIR)"

public/flamapy/flamapy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ class Flamapy {
1818
await pyodideInstance.runPythonAsync(`
1919
import micropip
2020
await micropip.install("flamapy/flamapy-2.0.1-py3-none-any.whl", deps=False)
21-
await micropip.install("flamapy/flamapy_fw-2.0.1-py3-none-any.whl", deps=False)
22-
await micropip.install("flamapy/flamapy_fm-2.0.1-py3-none-any.whl", deps=False)
21+
await micropip.install("flamapy/flamapy_fw-2.0.2.dev0-py3-none-any.whl", deps=False)
22+
await micropip.install("flamapy/flamapy_fm-2.0.2.dev0-py3-none-any.whl", deps=False)
2323
await micropip.install("flamapy/flamapy_sat-2.0.1-py3-none-any.whl", deps=False)
2424
await micropip.install("flamapy/flamapy_bdd-2.0.1-py3-none-any.whl", deps=False)
2525
await micropip.install("flamapy/dd-0.5.7-py3-none-any.whl", deps=False)
47.4 KB
Binary file not shown.
24.2 KB
Binary file not shown.

public/flamapy/flamapy_ide.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,23 @@ def feature_tree(node):
162162
res['attributes']['isMandatory'] = node.is_mandatory()
163163
res['attributes']['isOptional'] = node.is_optional()
164164
res['attributes']['isAbstract'] = node.is_abstract
165+
res['attributes']['isMultifeature'] = node.is_multifeature()
166+
res['attributes']['featureCardinality'] = dict()
167+
res['attributes']['featureCardinality']['min'] = node.feature_cardinality.min
168+
res['attributes']['featureCardinality']['max'] = node.feature_cardinality.max
169+
res['attributes']['isNumerical'] = node.is_numerical()
170+
res['attributes']['isString'] = node.is_string()
171+
res['attributes']['featureType'] = node.feature_type.value
172+
165173
if node.get_children():
166174
res['attributes']['isAlternativeGroup'] = node.is_alternative_group()
167175
res['attributes']['isOrGroup'] = node.is_or_group()
176+
res['attributes']['isCardinalityGroup'] = node.is_cardinality_group()
177+
if node.is_cardinality_group():
178+
res['attributes']['cardinalityGroup'] = dict()
179+
cardinalityGroup = [relation for relation in node.get_relations() if relation.is_cardinal()]
180+
res['attributes']['cardinalityGroup']['min'] = cardinalityGroup[0].card_min if cardinalityGroup else None
181+
res['attributes']['cardinalityGroup']['max'] = cardinalityGroup[0].card_max if cardinalityGroup else None
168182
res['children'] = [feature_tree(child) for child in node.get_children()]
169183
return res
170184

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
flamapy==2.0.1
2-
flamapy_fw==2.0.1
3-
flamapy_fm==2.0.1
2+
./public/flamapy/flamapy_fw-2.0.2.dev0-py3-none-any.whl
3+
./public/flamapy/flamapy_fm-2.0.2.dev0-py3-none-any.whl
44
flamapy_sat==2.0.1
55
flamapy_bdd==2.0.1
66
pytest==8.3.3

src/components/FeatureModelVisualization.jsx

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,35 @@ import Tree from "react-d3-tree";
44
import { elementToSVG } from "dom-to-svg";
55

66
// Function to draw an arc between the children
7-
const drawSemicircle = (rectWidth, rectHeight, isAlternative) => {
7+
const drawSemicircle = (rectWidth, rectHeight, isAlternative, isCardinalityGroup, card_min, card_max) => {
88
const radius = rectWidth / 4;
99
const startX = radius;
1010
const startY = rectHeight / 2;
1111
const endX = -radius;
1212
const endY = rectHeight / 2;
1313

1414
return (
15+
<g>
1516
<path
1617
d={`M ${startX},${startY} A ${radius},${radius} 0 0,1 ${endX},${endY}`}
1718
fill={isAlternative ? "none" : "gray"}
1819
stroke="black"
1920
strokeWidth="1"
2021
className="group"
2122
/>
23+
{isCardinalityGroup && (
24+
<text
25+
x="0"
26+
y={endY + 15}
27+
fill="white"
28+
fontSize="12"
29+
textAnchor="middle"
30+
dominantBaseline="middle"
31+
>
32+
[{card_min}..{card_max}]
33+
</text>
34+
)}
35+
</g>
2236
);
2337
};
2438

@@ -40,9 +54,19 @@ const RenderRectSvgNode = ({ nodeDatum, toggleNode }) => {
4054
const isOptional = nodeDatum.attributes?.isOptional;
4155
const isAlternativeGroup = nodeDatum.attributes?.isAlternativeGroup;
4256
const isOrGroup = nodeDatum.attributes?.isOrGroup;
57+
const isCardinalityGroup = nodeDatum.attributes?.isCardinalityGroup;
58+
const cardinalityGroupMin = nodeDatum.attributes?.cardinalityGroup?.min;
59+
const cardinalityGroupMax = nodeDatum.attributes?.cardinalityGroup?.max == -1 ? "*" : nodeDatum.attributes?.cardinalityGroup?.max;
4360
const isAbstract = nodeDatum.attributes?.isAbstract;
44-
45-
const nodeName = nodeDatum.name;
61+
const isMultifeature = nodeDatum.attributes?.isMultifeature;
62+
const featureCardinalityMin = nodeDatum.attributes?.featureCardinality.min;
63+
const featureCardinalityMax = nodeDatum.attributes?.featureCardinality.max == -1 ? "*" : nodeDatum.attributes?.featureCardinality.max;
64+
const featureCardinality = isMultifeature ? " [" + featureCardinalityMin + ".." + featureCardinalityMax + "]" : "";
65+
const isNumerical = nodeDatum.attributes?.isNumerical;
66+
const isString = nodeDatum.attributes?.isString;
67+
const featureType = isNumerical || isString ? " : " + nodeDatum.attributes?.featureType : "";
68+
69+
const nodeName = nodeDatum.name + featureCardinality + featureType;
4670
const defaultFontSize = 20;
4771

4872
const [fontSize, setFontSize] = useState(defaultFontSize);
@@ -81,7 +105,7 @@ const RenderRectSvgNode = ({ nodeDatum, toggleNode }) => {
81105
x="0"
82106
y="5"
83107
textAnchor="middle"
84-
style={{ fontSize: `${fontSize}px`, fontWeight: "lighter" }}
108+
style={{ fontSize: `${fontSize}px`, fontWeight: "lighter", fontStyle: isAbstract ? "italic" : "normal" }}
85109
>
86110
{nodeName}
87111
</text>
@@ -103,8 +127,8 @@ const RenderRectSvgNode = ({ nodeDatum, toggleNode }) => {
103127
)}
104128

105129
{/* Render arc between children if it's an alternative group */}
106-
{(isAlternativeGroup || isOrGroup) && (
107-
<g>{drawSemicircle(rectWidth, rectHeight, isAlternativeGroup)}</g>
130+
{(isAlternativeGroup || isOrGroup || isCardinalityGroup) && (
131+
<g>{drawSemicircle(rectWidth, rectHeight, isAlternativeGroup, isCardinalityGroup, cardinalityGroupMin, cardinalityGroupMax)}</g>
108132
)}
109133
</g>
110134
);

src/pages/editor/EditorPage.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,10 @@ function EditorPage({ selectedFile }) {
316316
};
317317

318318
return (
319-
<div className="flex flex-col h-full w-full">
319+
<div className="flex-1 overflow-hidden flex flex-col">
320320
{/* Top Section */}
321321

322-
<div className="flex flex-1 p-2 gap-2">
322+
<div className="flex flex-row flex-grow p-2 gap-2 overflow-auto">
323323
{/* Left Side Panel */}
324324
<TreeView
325325
treeData={featureTree}

0 commit comments

Comments
 (0)