Skip to content

Commit

Permalink
Misc
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Jul 17, 2023
1 parent 05007ee commit c157b42
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 239 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react'
import { observer } from 'mobx-react'

// locals
import { WiggleDisplayModel } from '../models/model'
import RectBg from './RectBg'

const ColorLegend = observer(function ({
model,
rowHeight,
labelWidth,
exportSVG,
}: {
model: WiggleDisplayModel
rowHeight: number
labelWidth: number
exportSVG?: boolean
}) {
const {
needsCustomLegend,
needsScalebar,
needsFullHeightScalebar,
rowHeightTooSmallForScalebar,
renderColorBoxes,
sources,
} = model
const svgFontSize = Math.min(rowHeight, 12)
const canDisplayLabel = rowHeight > 11
const colorBoxWidth = renderColorBoxes ? 15 : 0
const legendWidth = labelWidth + colorBoxWidth + 5
const svgOffset = exportSVG ? 10 : 0
const extraOffset =
svgOffset || (needsScalebar && !rowHeightTooSmallForScalebar ? 50 : 0)

return sources ? (
<>
{
/* 0.25 for hanging letters like g */
needsFullHeightScalebar ? (
<RectBg
y={0}
x={extraOffset}
width={legendWidth}
height={(sources.length + 0.25) * rowHeight}
/>
) : null
}
{sources.map((source, idx) => {
const boxHeight = Math.min(20, rowHeight)
return (
<React.Fragment key={`${source.name}-${idx}`}>
{needsFullHeightScalebar ? null : (
<RectBg
y={idx * rowHeight + 1}
x={extraOffset}
width={legendWidth}
height={boxHeight}
/>
)}
{source.color ? (
<RectBg
y={idx * rowHeight + 1}
x={extraOffset}
width={colorBoxWidth}
height={needsCustomLegend ? rowHeight : boxHeight}
color={source.color}
/>
) : null}
{canDisplayLabel ? (
<text
y={idx * rowHeight + 13}
x={extraOffset + colorBoxWidth + 2}
fontSize={svgFontSize}
>
{source.name}
</text>
) : null}
</React.Fragment>
)
})}
</>
) : null
})

export default ColorLegend
14 changes: 14 additions & 0 deletions plugins/wiggle/src/MultiLinearWiggleDisplay/components/RectBg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'

const RectBg = (props: {
x: number
y: number
width: number
height: number
color?: string
}) => {
const { color = 'rgb(255,255,255,0.8)' } = props
return <rect {...props} fill={color} />
}

export default RectBg
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react'
import { measureText, getContainingView } from '@jbrowse/core/util'
import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
import { observer } from 'mobx-react'

// locals
import { WiggleDisplayModel } from '../models/model'
import RectBg from './RectBg'

type LGV = LinearGenomeViewModel

const ScoreLegend = observer(({ model }: { model: WiggleDisplayModel }) => {
const { ticks, scaleType } = model
const { width } = getContainingView(model) as LGV
const legend =
`[${ticks?.values[0]}-${ticks?.values[1]}]` +
(scaleType === 'log' ? ' (log scale)' : '')
const len = measureText(legend, 14)
const padding = 25
const xpos = width - len - padding
return (
<>
<RectBg y={0} x={xpos} width={len + 6} height={16} />
<text y={13} x={xpos}>
{legend}
</text>
</>
)
})

export default ScoreLegend
Original file line number Diff line number Diff line change
@@ -1,252 +1,18 @@
import React from 'react'
import {
measureText,
getContainingView,
getContainingTrack,
} from '@jbrowse/core/util'
import { getConf } from '@jbrowse/core/configuration'
import {
LinearGenomeViewModel,
BaseLinearDisplayComponent,
} from '@jbrowse/plugin-linear-genome-view'
import { BaseLinearDisplayComponent } from '@jbrowse/plugin-linear-genome-view'
import { observer } from 'mobx-react'

// locals
import { WiggleDisplayModel } from '../models/model'
import YScaleBar from '../../shared/YScaleBar'

type LGV = LinearGenomeViewModel

const trackLabelFontSize = 12.8

function getOffset(model: WiggleDisplayModel) {
const { prefersOffset } = model
const { trackLabels } = getContainingView(model) as LGV
const track = getContainingTrack(model)
const trackName = getConf(track, 'name')
return trackLabels === 'overlapping' && !prefersOffset
? measureText(trackName, trackLabelFontSize) + 100
: 10
}

const Wrapper = observer(function ({
children,
model,
exportSVG,
}: {
model: WiggleDisplayModel
children: React.ReactNode
exportSVG?: boolean
}) {
if (exportSVG) {
return <>{children}</>
} else {
const { height } = model
return (
<svg
style={{
position: 'absolute',
top: 0,
left: 0,
pointerEvents: 'none',
height,
width: getContainingView(model).width,
}}
>
{children}
</svg>
)
}
})

const RectBg = (props: {
x: number
y: number
width: number
height: number
color?: string
}) => {
const { color = 'rgb(255,255,255,0.8)' } = props
return <rect {...props} fill={color} />
}

const ScoreLegend = observer(({ model }: { model: WiggleDisplayModel }) => {
const { ticks, scaleType } = model
const { width } = getContainingView(model) as LGV
const legend =
`[${ticks?.values[0]}-${ticks?.values[1]}]` +
(scaleType === 'log' ? ' (log scale)' : '')
const len = measureText(legend, 14)
const padding = 25
const xpos = width - len - padding
return (
<>
<RectBg y={0} x={xpos} width={len + 6} height={16} />
<text y={13} x={xpos}>
{legend}
</text>
</>
)
})

const ColorLegend = observer(function ({
model,
rowHeight,
labelWidth,
exportSVG,
}: {
model: WiggleDisplayModel
rowHeight: number
labelWidth: number
exportSVG?: boolean
}) {
const {
needsCustomLegend,
needsScalebar,
needsFullHeightScalebar,
rowHeightTooSmallForScalebar,
renderColorBoxes,
sources,
} = model
const svgFontSize = Math.min(rowHeight, 12)
const canDisplayLabel = rowHeight > 11
const colorBoxWidth = renderColorBoxes ? 15 : 0
const legendWidth = labelWidth + colorBoxWidth + 5
const svgOffset = exportSVG ? 10 : 0
const extraOffset =
svgOffset || (needsScalebar && !rowHeightTooSmallForScalebar ? 50 : 0)

return sources ? (
<>
{
/* 0.25 for hanging letters like g */
needsFullHeightScalebar ? (
<RectBg
y={0}
x={extraOffset}
width={legendWidth}
height={(sources.length + 0.25) * rowHeight}
/>
) : null
}
{sources.map((source, idx) => {
const boxHeight = Math.min(20, rowHeight)
return (
<React.Fragment key={`${source.name}-${idx}`}>
{needsFullHeightScalebar ? null : (
<RectBg
y={idx * rowHeight + 1}
x={extraOffset}
width={legendWidth}
height={boxHeight}
/>
)}
{source.color ? (
<RectBg
y={idx * rowHeight + 1}
x={extraOffset}
width={colorBoxWidth}
height={needsCustomLegend ? rowHeight : boxHeight}
color={source.color}
/>
) : null}
{canDisplayLabel ? (
<text
y={idx * rowHeight + 13}
x={extraOffset + colorBoxWidth + 2}
fontSize={svgFontSize}
>
{source.name}
</text>
) : null}
</React.Fragment>
)
})}
</>
) : null
})

export const StatBars = observer(function (props: {
model: WiggleDisplayModel
orientation?: string
exportSVG?: boolean
}) {
const { model, orientation, exportSVG } = props
const {
stats,
needsCustomLegend,
needsFullHeightScalebar,
rowHeightTooSmallForScalebar,
rowHeight,
sources,
ticks,
} = model
const svgFontSize = Math.min(rowHeight, 12)
const canDisplayLabel = rowHeight > 11
const { width: viewWidth } = getContainingView(model) as LGV
const minWidth = 20

const ready = stats && sources
if (!ready) {
return null
}

const labelWidth = Math.max(
...(sources
.map(s => measureText(s.name, svgFontSize))
.map(width => (canDisplayLabel ? width : minWidth)) || [0]),
)

return (
<Wrapper {...props}>
{needsFullHeightScalebar ? (
<>
<g transform={`translate(${!exportSVG ? getOffset(model) : 0},0)`}>
<YScaleBar model={model} orientation={orientation} />
</g>
<g transform={`translate(${viewWidth - labelWidth - 100},0)`}>
<ColorLegend
exportSVG={exportSVG}
model={model}
rowHeight={12}
labelWidth={labelWidth}
/>
</g>
</>
) : (
<>
<ColorLegend
exportSVG={exportSVG}
model={model}
rowHeight={model.rowHeight}
labelWidth={labelWidth}
/>

{rowHeightTooSmallForScalebar || needsCustomLegend ? (
<ScoreLegend {...props} />
) : (
sources.map((_source, idx) => (
<g
transform={`translate(0 ${rowHeight * idx})`}
key={`${JSON.stringify(ticks)}-${idx}`}
>
<YScaleBar model={model} orientation={orientation} />
</g>
))
)}
</>
)}
</Wrapper>
)
})
import YScaleBars from './YScaleBars'

export default observer((props: { model: WiggleDisplayModel }) => {
const { model } = props

return (
<div>
<BaseLinearDisplayComponent {...props} />
<StatBars model={model} />
<YScaleBars model={model} />
</div>
)
})
Expand Down
Loading

0 comments on commit c157b42

Please sign in to comment.