-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(LineSeed): add line seed widget
- Loading branch information
Showing
5 changed files
with
372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from pathlib import Path | ||
from trame.app import get_server | ||
from trame.ui.vuetify3 import SinglePageLayout | ||
from trame.widgets import vuetify3, trame | ||
from trame.assets.local import to_url | ||
|
||
server = get_server() | ||
IMAGE = str(Path(__file__).with_name("seeds.jpg").resolve()) | ||
|
||
|
||
def new_seed_points(p1, p2): | ||
print(f"{p1=}") | ||
print(f"{p2=}") | ||
|
||
|
||
with SinglePageLayout(server, full_height=True) as layout: | ||
with layout.toolbar: | ||
vuetify3.VSpacer() | ||
vuetify3.VLabel("{{ width }}") | ||
vuetify3.VSlider( | ||
v_model=("width", 500), | ||
max=500, | ||
min=150, | ||
step=10, | ||
density="compact", | ||
hide_details=True, | ||
) | ||
with layout.content: | ||
with vuetify3.VContainer(classes="fill-height", fluid=True): | ||
trame.LineSeed( | ||
style=("`max-width: ${width}px;`",), | ||
image=to_url(IMAGE), | ||
point_1=("p1", [-0.5, 0, 0]), | ||
point_2=("p2", [-0.5, 0, 1.25]), | ||
bounds=("[-0.5, 1.80, -1.12, 1.11, -0.43, 1.79]",), | ||
update_seed=(new_seed_points, "[]", "$event"), | ||
) | ||
|
||
server.start() |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,308 @@ | ||
const { ref, computed, watch, unref, toRefs, onMounted, onBeforeUnmount } = | ||
window.Vue; | ||
|
||
export default { | ||
props: { | ||
point1: { | ||
type: Array, | ||
default() { | ||
return [0, 0, 0]; | ||
}, | ||
}, | ||
point2: { | ||
type: Array, | ||
default() { | ||
return [0, 0, 0]; | ||
}, | ||
}, | ||
numberOfSteps: { | ||
type: Number, | ||
default: 255, | ||
}, | ||
bounds: { | ||
type: Array, | ||
default() { | ||
return [-1, 1, -1, 1, -1, 1]; | ||
}, | ||
}, | ||
image: { | ||
default: null, | ||
}, | ||
}, | ||
emit: ["update-seed"], | ||
setup(props, { emit }) { | ||
let dragging = 0; | ||
let lastEvent = null; | ||
let lastPoint = null; | ||
|
||
const svgContainer = ref(null); | ||
const normalDelta = ref([0, 0]); | ||
const scaling2d = ref(1); | ||
const radius = ref(10); | ||
const p1 = ref([0, 0]); | ||
const p2 = ref([0, 0]); | ||
const userInput = ref(false); | ||
const x1 = ref(props.point1[0]); | ||
const y1 = ref(props.point1[1]); | ||
const z1 = ref(props.point1[2]); | ||
const x2 = ref(props.point2[0]); | ||
const y2 = ref(props.point2[1]); | ||
const z2 = ref(props.point2[2]); | ||
const sharedDepth = ref(true); | ||
const nbSeeds = ref(50); | ||
|
||
const pointColor2 = computed(() => | ||
unref(sharedDepth) ? "#2196F3" : "#4CAF50" | ||
); | ||
const step = computed( | ||
() => (props.bounds[5] - props.bounds[4]) / props.numberOfSteps | ||
); | ||
// const xScaling = computed(() => (props.bounds[1] - props.bounds[0]) / 500); | ||
const yScaling = computed(() => (props.bounds[3] - props.bounds[2]) / 500); | ||
const zScaling = computed(() => (props.bounds[5] - props.bounds[4]) / 500); | ||
|
||
function update2DPoints() { | ||
p1.value = [ | ||
500 - (unref(y1) - props.bounds[2]) / unref(yScaling), | ||
500 - (unref(z1) - props.bounds[4]) / unref(zScaling), | ||
]; | ||
p2.value = [ | ||
500 - (unref(y2) - props.bounds[2]) / unref(yScaling), | ||
500 - (unref(z2) - props.bounds[4]) / unref(zScaling), | ||
]; | ||
} | ||
|
||
function pushLineSeed() { | ||
if (!unref(userInput)) { | ||
return; | ||
} | ||
const xSelected = unref(sharedDepth) ? x1 : x2; | ||
emit("update-seed", { | ||
p1: [unref(x1), unref(y1), unref(z1)], | ||
p2: [unref(xSelected), unref(y2), unref(z2)], | ||
}); | ||
} | ||
|
||
function onMouseMove(e) { | ||
if (!unref(userInput)) { | ||
userInput.value = true; | ||
} | ||
if (dragging) { | ||
const dx = lastEvent.clientX - e.clientX; | ||
const dy = lastEvent.clientY - e.clientY; | ||
switch (dragging) { | ||
case 1: | ||
p1.value = [ | ||
lastPoint[0] - unref(scaling2d) * dx, | ||
lastPoint[1] - unref(scaling2d) * dy, | ||
]; | ||
y1.value = (500 - unref(p1)[0]) * unref(yScaling) + props.bounds[2]; | ||
z1.value = (500 - unref(p1)[1]) * unref(zScaling) + props.bounds[4]; | ||
break; | ||
case 2: | ||
p2.value = [ | ||
lastPoint[0] - unref(scaling2d) * dx, | ||
lastPoint[1] - unref(scaling2d) * dy, | ||
]; | ||
y2.value = (500 - unref(p2)[0]) * unref(yScaling) + props.bounds[2]; | ||
z2.value = (500 - unref(p2)[1]) * unref(zScaling) + props.bounds[4]; | ||
break; | ||
case 3: | ||
p1.value = [ | ||
lastPoint[0][0] - unref(scaling2d) * dx, | ||
lastPoint[0][1] - unref(scaling2d) * dy, | ||
]; | ||
y1.value = (500 - unref(p1)[0]) * unref(yScaling) + props.bounds[2]; | ||
z1.value = (500 - unref(p1)[1]) * unref(zScaling) + props.bounds[4]; | ||
p2.value = [ | ||
lastPoint[1][0] - unref(scaling2d) * dx, | ||
lastPoint[1][1] - unref(scaling2d) * dy, | ||
]; | ||
y2.value = (500 - unref(p2)[0]) * unref(yScaling) + props.bounds[2]; | ||
z2.value = (500 - unref(p2)[1]) * unref(zScaling) + props.bounds[4]; | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
// Compute delta for line offset connection in svg | ||
const vect = [unref(p1)[0] - unref(p2)[0], unref(p1)[1] - unref(p2)[1]]; | ||
const norm = Math.sqrt(vect[0] * vect[0] + vect[1] * vect[1]); | ||
if (norm > 0.0001) { | ||
vect[0] /= norm; | ||
vect[1] /= norm; | ||
} | ||
normalDelta.value = vect; | ||
|
||
pushLineSeed(); | ||
} | ||
} | ||
|
||
function onMousePress(pointIdx, e) { | ||
dragging = pointIdx; | ||
lastEvent = e; | ||
switch (pointIdx) { | ||
case 1: | ||
lastPoint = unref(p1).slice(); | ||
break; | ||
case 2: | ||
lastPoint = unref(p2).slice(); | ||
break; | ||
case 3: | ||
lastPoint = [unref(p1).slice(), unref(p2).slice()]; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
function onMouseRelease() { | ||
dragging = 0; | ||
} | ||
|
||
function onResize() { | ||
scaling2d.value = 500 / unref(svgContainer).getBoundingClientRect().width; | ||
} | ||
const resizeObserver = new ResizeObserver(onResize); | ||
onMounted(() => { | ||
console.log("svgContainer", unref(svgContainer)); | ||
resizeObserver.observe(unref(svgContainer)); | ||
}); | ||
onBeforeUnmount(() => resizeObserver.disconnect()); | ||
|
||
watch( | ||
() => props.point1, | ||
(v) => { | ||
[x1.value, y1.value, z1.value] = v; | ||
update2DPoints(); | ||
} | ||
); | ||
watch( | ||
() => props.point2, | ||
(v) => { | ||
[x2.value, y2.value, z2.value] = v; | ||
update2DPoints(); | ||
} | ||
); | ||
watch(sharedDepth, pushLineSeed); | ||
|
||
update2DPoints(); | ||
const { image } = toRefs(props); | ||
return { | ||
svgContainer, | ||
onMouseMove, | ||
onMousePress, | ||
onMouseRelease, | ||
normalDelta, | ||
radius, | ||
p1, | ||
p2, | ||
nbSeeds, | ||
sharedDepth, | ||
x1, | ||
x2, | ||
step, | ||
pointColor2, | ||
pushLineSeed, | ||
image, | ||
}; | ||
}, | ||
|
||
template: `<v-col class="mt-2"> | ||
<svg viewBox="0 0 500 500" | ||
ref="svgContainer" | ||
width="100%" | ||
@mousemove="onMouseMove" | ||
@mouseup="onMouseRelease" | ||
> | ||
<image | ||
:href="image" | ||
x="0" | ||
y="0" | ||
width="500" | ||
height="500" | ||
/> | ||
<line | ||
:x1="p1[0] - normalDelta[0] * radius" | ||
:y1="p1[1] - normalDelta[1] * radius" | ||
:x2="p2[0] + normalDelta[0] * radius" | ||
:y2="p2[1] + normalDelta[1] * radius" | ||
style="cursor: grab;stroke: rgba(0,0,0,0.25);stroke-width:8" | ||
@mousedown="onMousePress(3, $event)" | ||
/> | ||
<circle | ||
:cx="p2[0]" | ||
:cy="p2[1]" | ||
:r="radius" | ||
:stroke="pointColor2" | ||
stroke-width="8" | ||
fill="rgba(0,0,0,0)" | ||
@mousedown="onMousePress(2, $event)" | ||
style="cursor: pointer;" | ||
/> | ||
<circle | ||
:cx="p1[0]" | ||
:cy="p1[1]" | ||
r="10" | ||
stroke="#2196F3" | ||
stroke-width="8" | ||
fill="rgba(0,0,0,0)" | ||
@mousedown="onMousePress(1, $event)" | ||
style="cursor: pointer;" | ||
/> | ||
</svg> | ||
<v-col class="pt-0"> | ||
<v-row class="align-center"> | ||
<v-col cols="12" md="11"> | ||
<v-text-field | ||
density="compact" | ||
hide-details | ||
type="number" | ||
min="5" | ||
max="1000" | ||
step="1" | ||
label="Seeds count" | ||
v-model="nbSeeds" | ||
/> | ||
</v-col> | ||
<v-col cols="12" md="1"> | ||
<v-switch | ||
style="width: 80px" | ||
class="mt-0" | ||
density="compact" | ||
v-model="sharedDepth" | ||
hide-details | ||
/> | ||
</v-col> | ||
</v-row> | ||
<v-row> | ||
<v-slider | ||
v-show="!sharedDepth" | ||
v-model="x2" | ||
track-color="green" | ||
color="green" | ||
density="compact" | ||
hide-details | ||
@update:modelValue="pushLineSeed" | ||
:min="bounds[0]" | ||
:max="bounds[1]" | ||
:step="step" | ||
/> | ||
</v-row> | ||
<v-row> | ||
<v-slider | ||
v-model="x1" | ||
track-color="blue" | ||
color="blue" | ||
density="compact" | ||
hide-details | ||
@update:modelValue="pushLineSeed" | ||
:min="bounds[0]" | ||
:max="bounds[1]" | ||
:step="step" | ||
/> | ||
</v-row> | ||
</v-col> | ||
</v-col> | ||
`, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters