Skip to content
Snippets Groups Projects
Commit 42aa2773 authored by Remi  PLANEL's avatar Remi PLANEL
Browse files

Merge branch 'operon-struct-type' into operon-struct-type-article

parents 4247207d a9d28f57
No related branches found
No related tags found
No related merge requests found
Pipeline #129670 waiting for manual action
......@@ -14,6 +14,9 @@ const structureBasket = useStructuresBasket()
const props = withDefaults(defineProps<Props>(), {
genes: null
});
const { genes: genesProps } = toRefs(props)
// const refGenes = ref()
const height = ref<number>(200)
const svgRef = ref<SVGElement | null>(null)
const margin = ref<PlotMargin>({
......@@ -23,6 +26,8 @@ const margin = ref<PlotMargin>({
marginLeft: 7,
})
const geneToHighlight = ref<string | null>(null)
const snackbar = ref(false)
const color = d3.scaleOrdinal(d3.schemeCategory10);
const plotHeight = computed(() => {
......@@ -63,6 +68,7 @@ const xScaleGenes = computed(() => {
})
const yScale = ref(d3.scaleBand()
.paddingInner(0.5)
.domain(['img', 'buff', 'buff2', 'gene'])
.range([toValue(margin).marginTop, toValue(height)]));
const gbContainer = ref(null)
......@@ -77,8 +83,8 @@ const computedPlotWidth = computed(() => {
const computedGenes = computed<StructureOperonGene[]>(() => {
const genes = toValue(props.genes)
if (genes !== null) {
const genes = toValue(genesProps)
if (genes !== null && genes?.length > 0) {
let currentSumSize = 0
return genes.map(d => {
const size = d?.size ?? 10
......@@ -87,14 +93,16 @@ const computedGenes = computed<StructureOperonGene[]>(() => {
return {
...d,
size,
position
position,
highlight: geneToHighlight.value === d.gene
}
})
}
else { return [] }
})
})
const structureVersion = computed(() => {
const genesVal = toValue(computedGenes)
if (genesVal?.length > 0) {
......@@ -105,8 +113,33 @@ const structureVersion = computed(() => {
}
})
const structureNodes = computed<StructureOperonGeneWithCoordinate[]>(() => {
const genes = toValue(computedGenes)
const xScaleVal = toValue(xScale)
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
return {
...d,
r: r,
// x: xPostion > 0 ? xPostion : 0,
x: xScaleVal(d.gene),
y: yScaleVal('img'),
width: toValue(xScale).bandwidth(),
// width: r,
height: yScaleVal.step() * 3
}
})
}
else { return [] }
})
const genesWithCoord = computed<StructureOperonGeneWithCoordinate[]>(() => {
const geneNodes = computed<StructureOperonGeneWithCoordinate[]>(() => {
const genes = toValue(computedGenes)
const xScaleVal = toValue(xScaleGenes)
const yScaleVal = toValue(yScale)
......@@ -123,11 +156,34 @@ const genesWithCoord = computed<StructureOperonGeneWithCoordinate[]>(() => {
}
else { return [] }
})
const linksGenesStruct = computed(() => {
const geneNodesVal = toValue(geneNodes)
const structureNodesVal = toValue(structureNodes)
return d3.zip(geneNodesVal, structureNodesVal).map(([source, target]) => {
return {
source: [source.x + source.width / 2, source.y],
target: [target.x + target.width / 2, target.y + target.height / 2 + 30],
highlight: source?.highlight || target?.highlight
}
})
})
onMounted(() => {
// const genePropsVal = toValue(genesProps)
// refGenes.value = genePropsVal?.map(d => d)
draw()
})
watch(genesWithCoord, () => {
watch(structureNodes, () => {
draw()
})
watch(geneNodes, () => {
draw()
})
......@@ -156,49 +212,130 @@ function draw() {
.attr("transform", 'rotate(-20)')
.attr("text-anchor", "start")
let gGenes = createOrSelect(svg, "g", "genes")
gGenes
let gOperon = createOrSelect(svg, "g", "operon")
gOperon
.attr("transform", `translate(${marginLeft},0)`)
.call(drawGenes, xScale, yScale)
.call(drawLinks)
.call(drawGenes)
.call(drawStructure)
}
}
function drawGenes(genesGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
const data = toValue(genesWithCoord)
const genesSelection = genesGroup
.selectAll("g.operon-item") // get all "existing" lines in svg
.data<StructureOperonGeneWithCoordinate>(data) // sync them with our data
.join(
enter => {
const gOperonItem = enter.append("g")
.classed("operon-item", true);
function adjacentlinks(nodes: Record<string, any>) {
const links = []
for (let i = 0; i < nodes.length; i++) {
if (i < nodes.length - 1) {
links.push({ index: i, source: nodes[i], target: nodes[+1] })
}
}
return links
}
// gene grp
const gGene = gOperonItem.append("g")
.classed("gene-grp", true)
gGene
.append("path")
.classed("gene", true)
function drawLinks(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
const stroke = "#555" // stroke for links
const strokeWidth = 1.5 // stroke width for links
const strokeOpacity = 0.4 // stroke opacity for links
operonGroup
.selectAll("path.link")
.data(linksGenesStruct.value)
.join("path")
.classed("link", true)
.attr("fill", "none")
.attr("stroke", "currentColor")
.attr("stroke-opacity", d => d.highlight ? 0.6 : strokeOpacity)
.attr("stroke-width", d => d.highlight ? strokeWidth + 2 : strokeWidth)
.attr("d", d3.link(d3.curveBumpY))
}
function drawStructure(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
const structureNodeVal = toValue(structureNodes)
// const totalSize = domainGenes.value[1]
// const structureLinks = adjacentlinks(structures)
// const sim = d3.forceSimulation(structureNodeVal)
// .force("link", d3.forceLink(structureLinks))
// .force("collide", d3.forceCollide((d) => d.r))
// .stop()
// .tick(10);
// sim.tick()
const structureSelection = operonGroup
.selectAll("g.structure") // get all "existing" lines in svg
.data<StructureOperonGeneWithCoordinate>(structureNodeVal) // sync them with our data
.join(
enter => {
const gStructure = enter.append("g")
.classed("structure", true);
// img group
gOperonItem
.append("g").classed("img", true)
gStructure
.append("image")
.on("mouseover", function (event) {
const srcSelection = d3.select(event.srcElement)
const target = d3.select(event.srcElement.parentElement)
const node = srcSelection.data()
geneToHighlight.value = node[0].gene
target
// .attr("stroke-width", 4)
// .attr("stroke", "darkred")
.attr("cursor", "pointer")
})
.on("mouseout", function (event) {
const target = d3.select(event.srcElement.parentElement)
target
// .attr("stroke-width", 0)
// .attr("stroke", null)
.attr("cursor", "unset")
geneToHighlight.value = null
})
return gStructure
},
update => update,
exit => exit.remove()
)
const imageSelection = structureSelection
.attr("transform", d => `translate(0,${toValue(yScale)("img")})`)
.select("image")
imageSelection
.transition()
.attr("transform", d => `translate(${d.x},${d.highlight ? -10 : 0})`)
imageSelection
.attr("href", d => d?.structImg ?? null)
.attr("width", d => d.width)
.attr("height", d => d.height)
.attr("preserveAspectRatio", "xMidYMid meet")
.on("click", function (event) {
const data = d3.select<SVGElement, StructureOperonGeneWithCoordinate>(this).data()
structureBasket.set(data.map(s => s?.structPath ?? ''))
})
}
function drawGenes(operonGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
const genesWithCoordVal = toValue(geneNodes)
const genes = genesWithCoordVal
const links = adjacentlinks(genes)
const genesSelection = operonGroup
.selectAll("g.operon-item") // get all "existing" lines in svg
.data<StructureOperonGeneWithCoordinate>(genes) // sync them with our data
.join(
enter => {
const gOperonItem = enter.append("g")
.classed("operon-item", true);
// gene grp
const gGene = gOperonItem.append("g")
.classed("gene-grp", true)
gGene
.append("path")
.classed("gene", true)
gOperonItem.append("text")
// .attr("fill", "white")
......@@ -215,45 +352,28 @@ function drawGenes(genesGroup: d3.Selection<SVGElement, any, SVGElement, any>) {
exit => exit.remove()
)
genesSelection.select("g.gene-grp").attr("transform", d => `translate(${d.x}, 0)`)
genesSelection.select("g.img")
.attr("transform", d => `translate(${xScale.value(d.gene)})`)
.select("image")
.attr("transform", d => `translate(0, ${toValue(yScale)("img")})`)
.attr("href", d => d?.structImg ?? null)
.attr("width", toValue(xScale).bandwidth())
.attr("height", toValue(yScale).step() * 3)
.attr("preserveAspectRatio", "xMidYMid meet")
.on("click", function (event) {
const data = d3.select<SVGElement, StructureOperonGeneWithCoordinate>(this).data()
structureBasket.set(data.map(s => s?.structPath ?? ''))
})
genesSelection.select("g.gene-grp").select("path.gene")
genesSelection.select("g.gene-grp")
.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})`)
.attr("fill", d => color(d.system))
.attr("fill", d => d?.highlight ? d3.color(color(d.system))?.brighter() : color(d.system))
.attr("d", d => drawGene(d).toString())
genesSelection.select("line")
// x1="0" y1="80" x2="100" y2="20" stroke="black"
.attr("x1", d => xScale.value(d.gene) + xScale.value.bandwidth() / 2)
.attr("y1", d => yScale.value("buff2") + yScale.value.bandwidth() / 3)
.attr("x2", d => xScaleGenes.value(d.position) + xScaleGenes.value(d.size / 2))
.attr("y2", d => yScale.value("gene") - 2)
.attr("stroke", "currentColor")
}
function drawGene({ width, height }) {
const context = d3.path()
context.moveTo(0, 0)
context.lineTo(width, 0)
context.lineTo(width, height)
context.lineTo(0, height)
context.closePath()
function drawGene({ width, height }) {
const context = d3.path()
context.moveTo(0, 0)
context.lineTo(width, 0)
context.lineTo(width, height)
context.lineTo(0, height)
context.closePath()
return context
return context
}
}
</script>
......
......@@ -7,6 +7,7 @@ export interface StructureOperonGene {
exchangeables: string[]
size: number
position: number
highlight?: boolean
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment