Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
W
Wiki
Manage
Activity
Members
Labels
Plan
Issues
53
Issue boards
Milestones
Wiki
Code
Merge requests
6
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
MDM Lab
Wiki
Commits
2dd27243
Commit
2dd27243
authored
11 months ago
by
Remi PLANEL
Browse files
Options
Downloads
Patches
Plain Diff
add composable to compute rotation text label
parent
45dca804
No related branches found
No related tags found
No related merge requests found
Pipeline
#129854
waiting for manual action with stages
in 8 minutes and 26 seconds
Changes
3
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
components/OperonStructure.vue
+110
-60
110 additions, 60 deletions
components/OperonStructure.vue
composables/useTextRotate.ts
+77
-0
77 additions, 0 deletions
composables/useTextRotate.ts
types/structure.ts
+3
-0
3 additions, 0 deletions
types/structure.ts
with
190 additions
and
60 deletions
components/OperonStructure.vue
+
110
−
60
View file @
2dd27243
...
...
@@ -4,6 +4,7 @@ import * as d3 from "d3";
import
type
{
PlotMargin
}
from
"
../types/plot
"
;
import
type
{
StructureGeneLinks
,
StructureOperonGene
,
StructureOperonGeneWithCoordinate
,
StructureOperonGeneWithImg
}
from
"
../types/structure
"
import
{
useStructuresBasket
}
from
'
~/stores/structuresBasket
'
;
import
{
useTextRotate
,
type
TextRotateOuput
}
from
'
~/composables/useTextRotate
'
;
interface
Props
{
...
...
@@ -17,29 +18,25 @@ const props = withDefaults(defineProps<Props>(), {
const
{
genes
:
genesProps
}
=
toRefs
(
props
)
// const refGenes = ref()
const
height
=
ref
<
number
>
(
200
)
//
const height = ref
<
number
>
(
200
)
const
svgRef
=
ref
<
SVGElement
|
null
>
(
null
)
const
structureHeight
=
ref
(
130
)
const
geneHeight
=
ref
(
40
)
const
linkHeight
=
ref
(
20
)
const
margin
=
ref
<
PlotMargin
>
({
marginTop
:
5
,
marginRight
:
7
,
marginBottom
:
5
0
,
marginBottom
:
5
,
marginLeft
:
7
,
})
const
gbContainer
=
ref
(
null
)
const
geneToHighlight
=
ref
<
string
|
null
>
(
null
)
const
snackbar
=
ref
(
false
)
const
color
=
d3
.
scaleOrdinal
(
d3
.
schemeCategory10
);
const
plotHeight
=
computed
(()
=>
{
const
{
marginTop
,
marginBottom
}
=
toValue
(
margin
)
return
toValue
(
height
)
+
marginTop
+
marginBottom
})
const
domain
=
computed
(()
=>
{
const
genes
=
toValue
(
computedGenes
)
return
genes
?.
map
(
d
=>
{
return
d
.
gene
})
})
const
innerPadding
=
ref
<
number
>
(
8
)
const
totalGeneLength
=
computed
(()
=>
{
...
...
@@ -66,12 +63,6 @@ const xScaleGenes = computed(() => {
.
domain
(
toValue
(
domainGenes
))
.
range
([
0
,
computedPlotWidth
.
value
])
})
const
yScale
=
ref
(
d3
.
scaleBand
()
.
paddingInner
(
0.5
)
.
domain
([
'
img
'
,
'
buff
'
,
'
buff2
'
,
'
gene
'
,
'
label
'
])
.
range
([
toValue
(
margin
).
marginTop
,
toValue
(
height
)]));
const
gbContainer
=
ref
(
null
)
const
computedContainerWidth
=
computed
(()
=>
{
return
useElementSize
(
gbContainer
,
{
width
:
500
,
height
:
0
},
{
box
:
'
border-box
'
}).
width
.
value
})
...
...
@@ -80,13 +71,11 @@ const computedPlotWidth = computed(() => {
return
computedContainerWidth
.
value
-
marginLeft
-
marginRight
})
const
computedGenes
=
computed
<
StructureOperonGene
[]
>
(()
=>
{
const
genes
=
toValue
(
genesProps
)
if
(
genes
!==
null
&&
genes
?.
length
>
0
)
{
let
currentSumSize
=
0
return
genes
.
map
(
d
=>
{
return
genes
.
map
(
(
d
)
=>
{
const
size
=
d
?.
size
??
10
const
position
=
currentSumSize
currentSumSize
=
position
+
size
+
innerPadding
.
value
...
...
@@ -100,9 +89,8 @@ const computedGenes = computed<StructureOperonGene[]>(() => {
}
else
{
return
[]
}
})
const
structureVersion
=
computed
(()
=>
{
const
genesVal
=
toValue
(
computedGenes
)
if
(
genesVal
?.
length
>
0
)
{
...
...
@@ -113,57 +101,101 @@ const structureVersion = computed(() => {
}
})
const
structur
eNodes
=
computed
<
StructureOperonGeneWithCoordinate
[]
>
(()
=>
{
const
gen
eNodes
=
computed
<
StructureOperonGeneWithCoordinate
[]
>
(()
=>
{
const
genes
=
toValue
(
computedGenes
)
const
xScaleVal
=
toValue
(
xScale
)
const
yScaleVal
=
toValue
(
yScale
)
const
xScaleVal
=
toValue
(
xScale
Genes
)
//
const yScaleVal = toValue(yScale)
if
(
genes
!==
null
)
{
return
genes
.
map
(
d
=>
{
const
r
=
d3
.
min
([
toValue
(
xScale
).
bandwidth
(),
toValue
(
yScale
).
step
()
*
3
])
// const geneWidth = xScaleVal(d.size)
// const position = xScaleVal(d.position)
// const geneCenter = xScaleVal(d.position) + geneWidth / 2
// const xPostion = geneCenter - r / 2
const
x
=
xScaleVal
(
d
.
gene
)
const
y
=
yScaleVal
(
'
img
'
)
const
x
=
xScaleVal
(
d
.
position
)
// const y = yScaleVal('gene')
const
width
=
xScaleVal
(
d
.
size
)
// let rotate = 0
// let labelWidth = (d.gene.length * textSizeRatio.value) / Math.sqrt(2)
// let labelHeight = labelWidth
// if (width
<
labelWidth
)
{
// // need to increase angle
// rotate = 90
// labelHeight = labelWidth
// labelWidth = 16
// }
return
{
...
d
,
width
,
x
,
// rotate: 0,
// labelWidth,
labelHeight
:
150
,
y
:
0
,
// y: y === undefined ? 0 : y,
height
:
0
// height: yScaleVal.bandwidth()
}
})
}
else
{
return
[]
}
})
const
yScale
=
computed
(()
=>
{
const
{
marginTop
}
=
toValue
(
margin
)
const
structureHeightVal
=
toValue
(
structureHeight
)
+
marginTop
const
linkHeightVal
=
toValue
(
linkHeight
)
const
geneHeightVal
=
toValue
(
geneHeight
)
return
{
img
:
0
,
gene
:
structureHeightVal
+
linkHeightVal
,
label
:
structureHeightVal
+
linkHeightVal
+
geneHeightVal
+
10
}
})
const
geneNodesWithY
=
computed
(()
=>
{
const
genes
=
toValue
(
geneNodes
)
const
yScaleVal
=
toValue
(
yScale
)
if
(
genes
!==
null
)
{
const
y
=
yScaleVal
.
gene
return
genes
.
map
(
d
=>
{
return
{
...
d
,
r
:
r
,
// x: xPostion > 0 ? xPostion : 0,
x
:
x
===
undefined
?
0
:
x
,
y
:
y
===
undefined
?
0
:
y
,
width
:
toValue
(
xScale
).
bandwidth
(),
// width: r,
height
:
yScaleVal
.
step
()
*
3
height
:
geneHeight
.
value
}
})
}
else
{
return
[]
}
})
const
geneNodes
=
computed
<
StructureOperonGeneWithCoordinate
[]
>
(()
=>
{
const
genes
=
toValue
(
computedGenes
)
const
xScaleVal
=
toValue
(
xScaleGenes
)
const
structureNodes
=
computed
<
StructureOperonGeneWithCoordinate
[]
>
(()
=>
{
const
genes
=
toValue
(
geneNodesWithY
)
const
xScaleVal
=
toValue
(
xScale
)
const
yScaleVal
=
toValue
(
yScale
)
if
(
genes
!==
null
)
{
return
genes
.
map
(
d
=>
{
const
x
=
xScaleVal
(
d
.
position
)
const
y
=
yScaleVal
(
'
gene
'
)
const
x
=
xScaleVal
(
d
.
gene
)
const
y
=
yScaleVal
.
img
return
{
...
d
,
width
:
xScaleVal
(
d
.
size
),
x
,
x
:
x
===
undefined
?
0
:
x
,
y
:
y
===
undefined
?
0
:
y
,
height
:
yScaleVal
.
bandwidth
()
width
:
toValue
(
xScale
).
bandwidth
(),
height
:
structureHeight
.
value
}
})
}
else
{
return
[]
}
})
const
geneLabelHeight
=
computed
(()
=>
{
const
heights
=
toValue
(
genesTextRotate
)
const
max
=
d3
.
max
(
Object
.
values
(
heights
).
map
(({
height
})
=>
toValue
(
height
)))
return
max
!==
undefined
?
max
:
0
})
const
plotHeight
=
computed
(()
=>
{
const
{
marginTop
,
marginBottom
}
=
toValue
(
margin
)
return
marginTop
+
marginBottom
+
toValue
(
geneLabelHeight
)
+
toValue
(
structureHeight
)
+
toValue
(
geneHeight
)
+
toValue
(
linkHeight
)
+
10
})
const
linksGenesStruct
=
computed
<
StructureGeneLinks
[]
>
(()
=>
{
const
geneNodesVal
=
toValue
(
geneNodes
)
const
geneNodesVal
=
toValue
(
geneNodes
WithY
)
const
structureNodesVal
=
toValue
(
structureNodes
)
return
d3
.
zip
(
geneNodesVal
,
structureNodesVal
).
map
(([
source
,
target
])
=>
{
...
...
@@ -176,26 +208,30 @@ const linksGenesStruct = computed<StructureGeneLinks[]>(() => {
})
const
genesLabel
=
computed
(()
=>
{
const
geneNodesVal
=
toValue
(
geneNodes
)
const
geneNodesVal
=
toValue
(
geneNodes
WithY
)
const
yScaleVal
=
toValue
(
yScale
)
return
geneNodesVal
.
map
(
d
=>
({
...
d
,
y
:
yScaleVal
(
"
label
"
)
}))
return
geneNodesVal
.
map
(
d
=>
({
...
d
,
y
:
yScaleVal
.
label
}))
})
onMounted
(()
=>
{
// const genePropsVal = toValue(genesProps)
// refGenes.value = genePropsVal?.map(d => d)
draw
()
})
const
genesTextRotate
=
ref
<
Record
<
string
,
TextRotateOuput
>>
({})
watch
(
genesLabel
,
(
newGenesLabel
)
=>
{
const
genesTextRotateVal
=
toValue
(
genesTextRotate
)
newGenesLabel
.
forEach
(
el
=>
{
const
textRotate
=
useTextRotate
({
availableWidth
:
el
.
width
})
genesTextRotateVal
[
el
.
id
.
toString
()]
=
textRotate
})
})
watch
(
structureNodes
,
()
=>
{
draw
()
})
watch
(
geneNodes
,
()
=>
{
watch
(
geneNodes
WithY
,
()
=>
{
draw
()
})
...
...
@@ -285,7 +321,7 @@ function drawStructure(operonGroup: d3.Selection<SVGGElement, any, SVGElement |
exit
=>
exit
.
remove
()
)
const
imageSelection
=
structureSelection
.
attr
(
"
transform
"
,
`translate(0,
${
toValue
(
yScale
)
(
"
img
"
)
}
)`
)
.
attr
(
"
transform
"
,
`translate(0,
${
toValue
(
yScale
)
.
img
}
)`
)
.
attr
(
"
cursor
"
,
d
=>
d
.
highlight
?
"
pointer
"
:
null
)
.
select
(
"
image
"
)
imageSelection
...
...
@@ -302,7 +338,7 @@ function drawStructure(operonGroup: d3.Selection<SVGGElement, any, SVGElement |
}
function
drawGenes
(
operonGroup
:
d3
.
Selection
<
SVGGElement
,
any
,
SVGElement
|
null
,
any
>
)
{
const
genesWithCoordVal
=
toValue
(
geneNodes
)
const
genesWithCoordVal
=
toValue
(
geneNodes
WithY
)
const
genes
=
genesWithCoordVal
const
genesSelection
=
operonGroup
.
selectAll
(
"
g.gene-grp
"
)
// get all "existing" lines in svg
...
...
@@ -343,13 +379,12 @@ function drawGenes(operonGroup: d3.Selection<SVGGElement, any, SVGElement | null
)
genesSelection
.
attr
(
"
cursor
"
,
d
=>
d
.
highlight
?
"
pointer
"
:
null
)
.
attr
(
"
transform
"
,
d
=>
`translate(
${
d
.
x
}
,
0
)`
)
.
attr
(
"
transform
"
,
d
=>
`translate(
${
d
.
x
}
,
${
d
.
y
}
)`
)
const
genePathSelection
=
genesSelection
.
select
(
"
path.gene
"
)
// .attr("stroke", d => d?.highlight ? d3.color(color(d.system))?.darker() : null)
.
attr
(
"
stroke-width
"
,
d
=>
d
?.
highlight
?
4
:
0
)
.
attr
(
"
transform
"
,
d
=>
`translate(0,
${
d
.
y
}
)`
)
genePathSelection
.
transition
()
.
attr
(
"
fill
"
,
d
=>
d
?.
highlight
?
d3
.
color
(
color
(
d
.
system
))?.
brighter
()
:
color
(
d
.
system
))
...
...
@@ -412,15 +447,30 @@ function drawGenesLabel(operonGroup: d3.Selection<SVGGElement, any, SVGElement |
)
updateSelection
.
attr
(
"
cursor
"
,
d
=>
d
.
highlight
?
"
pointer
"
:
null
)
.
select
(
"
text
"
)
.
attr
(
"
transform
"
,
d
=>
`translate(
${
d
.
x
+
d
.
width
/
2
}
,
${
d
.
y
}
) rotate(40) `
)
.
select
<
SVGTextElement
>
(
"
text
"
)
.
attr
(
"
transform
"
,
function
(
d
)
{
const
genesTextRotateVal
=
toValue
(
genesTextRotate
)
const
geneId
=
d
.
id
.
toString
()
const
textRotate
=
genesTextRotateVal
?.[
geneId
]
if
(
textRotate
!==
undefined
)
{
const
{
rotate
,
width
,
setTextElem
,
textWidth
}
=
textRotate
setTextElem
(
this
)
return
`translate(
${
d
.
x
+
d
.
width
/
2
-
toValue
(
width
)
/
2
}
,
${
d
.
y
}
) rotate(
${
toValue
(
rotate
)}
) `
}
return
null
})
.
attr
(
"
style
"
,
d
=>
d
.
highlight
?
"
font-weight: 700
"
:
null
)
.
text
(
d
=>
d
.
gene
)
updateSelection
.
select
(
"
title
"
).
text
(
d
=>
d
.
gene
)
}
function
adjacentlinks
(
nodes
:
Record
<
string
,
any
>
)
{
const
links
=
[]
for
(
let
i
=
0
;
i
<
nodes
.
length
;
i
++
)
{
...
...
This diff is collapsed.
Click to expand it.
composables/useTextRotate.ts
0 → 100644
+
77
−
0
View file @
2dd27243
import
{
useElementSize
}
from
'
@vueuse/core
'
export
interface
TextRotateInput
{
availableWidth
:
MaybeRef
<
number
>
}
export
interface
TextRotateOuput
{
rotate
:
ComputedRef
<
number
>
width
:
Ref
<
number
>
height
:
Ref
<
number
>
textWidth
:
ComputedRef
<
number
>
,
setTextElem
:
(
newTextElement
:
MaybeRef
<
SVGTextElement
>
)
=>
void
}
export
function
useTextRotate
({
availableWidth
}:
TextRotateInput
):
TextRotateOuput
{
const
width
=
ref
<
number
>
(
0
)
const
height
=
ref
<
number
>
(
20
)
const
textElement
=
ref
<
SVGTextElement
|
undefined
>
(
undefined
)
const
availableWidthVal
=
toValue
(
availableWidth
)
const
textWidth
=
computed
(()
=>
{
const
textElementVal
=
toValue
(
textElement
)
if
(
textElementVal
!==
undefined
)
{
const
{
width
}
=
textElementVal
.
getBBox
()
return
width
}
return
0
})
function
setTextElem
(
newTextElement
:
MaybeRef
<
SVGTextElement
>
)
{
textElement
.
value
=
toValue
(
newTextElement
)
}
const
rotateRad
=
computed
(()
=>
{
const
textWidthSide
=
textWidth
.
value
/
Math
.
sqrt
(
2
)
const
textWidthVal
=
toValue
(
textWidth
)
if
(
textWidthVal
===
0
)
return
0
if
(
availableWidthVal
>
textWidthVal
)
{
width
.
value
=
textWidth
.
value
height
.
value
=
20
return
0
}
if
(
textWidthSide
<
availableWidthVal
)
{
width
.
value
=
textWidthSide
height
.
value
=
textWidthSide
return
Math
.
PI
/
4
}
else
{
width
.
value
=
0
height
.
value
=
textWidth
.
value
return
Math
.
PI
/
2
}
})
const
rotate
=
computed
(()
=>
{
return
rotateRad
.
value
*
180
/
Math
.
PI
})
watch
(
rotateRad
,
(
newVal
)
=>
{
const
textWidthVal
=
toValue
(
textWidth
)
if
(
newVal
===
0
)
{
width
.
value
=
textWidthVal
height
.
value
=
20
}
else
if
(
newVal
>
Math
.
PI
/
4
)
{
width
.
value
=
15
height
.
value
=
textWidthVal
+
100
}
else
{
const
w
=
Math
.
sin
(
newVal
)
*
textWidthVal
const
h
=
Math
.
cos
(
newVal
)
*
textWidthVal
height
.
value
=
h
+
100
width
.
value
=
w
}
})
return
{
rotate
,
width
,
height
,
textWidth
,
setTextElem
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
types/structure.ts
+
3
−
0
View file @
2dd27243
...
...
@@ -21,6 +21,9 @@ export interface StructureOperonGeneWithCoordinate extends StructureOperonGeneWi
height
:
number
x
:
number
y
:
number
labelHeight
:
number
,
// labelWidth: number,
// rotate: number
}
export
interface
StructureGeneLinks
{
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment