Skip to content

Commit

Permalink
Merge pull request #219 from lsst-ts/tickets/DM-46860
Browse files Browse the repository at this point in the history
DM-46860: Add side-by-side view for ComCam movies
  • Loading branch information
ugyballoons authored Oct 18, 2024
2 parents d85ea69 + a3387da commit abbb1a2
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 72 deletions.
3 changes: 3 additions & 0 deletions python/lsst/ts/rubintv/handlers/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ async def get_camera_mosaic_page(
location_name: str,
camera_name: str,
request: Request,
headerless: bool = False,
) -> Response:
logger.info("Getting mosaic page", headerless=headerless)
location, camera = await get_location_camera(location_name, camera_name, request)
if not camera.mosaic_view_meta:
raise HTTPException(404, "No mosaic found for this camera.")
Expand All @@ -180,6 +182,7 @@ async def get_camera_mosaic_page(
"location": location,
"camera": camera.model_dump(),
"title": title,
"headerless": headerless,
},
)

Expand Down
12 changes: 11 additions & 1 deletion python/lsst/ts/rubintv/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Channel(BaseModel):
label: str = ""
per_day: bool = False
colour: str = ""
icon: str = ""
text_colour: str = "#000"


class HasButton(BaseModel):
Expand All @@ -63,8 +65,8 @@ class HasButton(BaseModel):
True for a shadow, false otherwise.
"""

name: str
title: str
name: str = ""
logo: str = ""
text_colour: str = "#000"
text_shadow: bool = False
Expand All @@ -81,10 +83,17 @@ class MosaicViewMeta(BaseModel):
The channel name.
metaColumns : list[str]
A list of metadata columns.
dataType : str
Presently, "image" or "video" are only options.
"""

channel: str
metaColumns: list[str]
dataType: str = "image"


class ExtraButton(HasButton):
linkURL: str


class Camera(HasButton):
Expand Down Expand Up @@ -140,6 +149,7 @@ class Camera(HasButton):
image_viewer_link: str = ""
copy_row_template: str = ""
mosaic_view_meta: list[MosaicViewMeta] = []
extra_buttons: list[ExtraButton] = []

def seq_channels(self) -> list[Channel]:
return [c for c in self.channels if not c.per_day]
Expand Down
36 changes: 36 additions & 0 deletions python/lsst/ts/rubintv/models/models_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ bucket_configurations:
[ slac, base-usdf, tucson-usdf, summit-usdf ]

locations:
- name: test
title: TEST
profile_name: rubin-rubintv-data-summit
bucket_name: rubin-rubintv-data-summit
camera_groups:
Test: [ comcam ]

- name: slac
title: SLAC
profile_name: rubin-rubintv-data-usdf
Expand Down Expand Up @@ -225,6 +232,35 @@ cameras:
- name: psf_shape_azel
title: PSF shape AzEl
colour: "#6F58E7"
- name: mount
title: Mount torques
colour: "#58b4e7"

- name: day_movie
title: Whole Day Movie
per_day: True
color: "#83daee"
icon: movies
- name: last_n_movie
title: Last N Images Movie
per_day: True
color: "#83eebe"
icon: movies

extra_buttons:
- title: Movies View
name: moviesView
# relative url
linkURL: mosaic
logo: AI-astral-movie.jpg
text_colour: "#fff"

mosaic_view_meta:
- channel: day_movie
metaColumns: []
- channel: last_n_movie
metaColumns: []

copy_row_template: "dataId = {\"day_obs\": {dayObs}, \"seq_num\": \
{seqNum}}"
image_viewer_link: "http://ccs.lsst.org/FITSInfo/\
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/lsst/ts/rubintv/templates/_layout.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ window.onpageshow = function (event) {
window.APP_DATA = {}
window.APP_DATA.locationName = {{ location.name|tojson if location else "" }}
window.APP_DATA.siteLocation = {{ site_location|tojson if site_location else "null" }}
window.APP_DATA.imagesURL = "{{ url_for('static', path='images')}}"
window.APP_DATA.pathPrefix = {{ path_prefix|tojson if path_prefix else "null" }}
</script>

Expand Down
25 changes: 24 additions & 1 deletion python/lsst/ts/rubintv/templates/mosaic.jinja
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
{% extends "_camera.jinja" %}

{% block header %}
{% if not headerless %}
{{ super() }}
{% endif %}
{% endblock header %}

{% block pagesubtitle %}
{% if not headerless %}
Current Mosaic
{% endif %}
{% endblock pagesubtitle %}

{% block breadcrumb %}
{% if not headerless %}
<a href="{{ url_for('home') }}">Home</a>>
<a href="{{ url_for('location', location_name=location.name) }}">{{ location.title }}</a>>
<a href="{{ url_for('camera', location_name=location.name, camera_name=camera.name) }}">{{ camera.title }}</a>>
<p>Current Mosaic</p>
{% else %}
<style>
.breadcrumb {
padding: 0
}
</style>
{% endif %}
{% endblock breadcrumb %}

{% block content %}
<div id="mosaic-view" class="columns">
{# React MosiacView root here #}
Expand All @@ -11,5 +35,4 @@

{% block footer_scripts %}
<script src='{{ url_for("static", path="assets/mosaic-view.js") }}'></script>
{{ super() }}
{% endblock footer_scripts %}
82 changes: 56 additions & 26 deletions src/js/components/MosaicView.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function ChannelView({ locationName, camera, view, currentMeta }) {
<span>: { dayObs }</span>
) }
</h3>
<ChannelImage
<ChannelMedia
locationName={locationName}
camera={camera}
event={view.latestEvent}
Expand All @@ -116,39 +116,69 @@ ChannelView.propTypes = {
currentMeta: metadataType
}

function ChannelImage({ locationName, camera, event }) {
const { filename } = event
const relUrl = buildImageURI(
locationName,
camera.name,
event.channel_name,
filename
)
const imgSrc = new URL(`event_image/${relUrl}`, APP_DATA.baseUrl)
if (filename) {
return (
<div className="viewImage">
<a href={imgSrc}>
<img className="resp" src={imgSrc} />
</a>
</div>
)
} else {
return (
<div className="viewImage placeholder">
<h4 className="image-placeholder">No image for today</h4>
</div>
)
function ChannelMedia({ locationName, camera, event }) {
const { filename, ext } = event
const mediaURL = buildMediaURI(locationName, camera.name, event.channel_name, filename)
switch (ext) {
case 'mp4':
return <ChannelVideo mediaURL={mediaURL}/>
case 'jpg':
case 'jpeg':
case 'png':
return <ChannelImage mediaURL={mediaURL}/>
default:
return <ChannelMediaPlaceholder/>
}
}
ChannelImage.propTypes = {
ChannelMedia.propTypes = {
locationName: PropTypes.string,
camera: cameraType,
event: eventType,
}

function ChannelImage({mediaURL}) {
const imgSrc = new URL(`event_image/${mediaURL}`, APP_DATA.baseUrl)
return (
<div className="viewImage">
<a href={imgSrc}>
<img className="resp" src={imgSrc} />
</a>
</div>
)
}
ChannelImage.propTypes = {
mediaURL: PropTypes.string,
}

function ChannelVideo({mediaURL}) {
const videoSrc = new URL(`event_video/${mediaURL}`, APP_DATA.baseUrl)
return (
<div className="viewVideo">
<a href={videoSrc}>
<video className="resp" controls autoPlay loop>
<source src={videoSrc}/>
</video>
</a>
</div>
)
}
ChannelVideo.propTypes = {
mediaURL: PropTypes.string,
}

function ChannelMediaPlaceholder() {
return (
<div className="viewImage placeholder">
<h4 className="image-placeholder">Nothing today yet</h4>
</div>
)
}

function ChannelMetadata({ view, metadata }) {
const { channel, metaColumns: viewColumns, latestEvent: {seq_num: seqNum} } = view
if (viewColumns.length == 0) {
return
}
const columns = [...commonColumns, ...viewColumns]
const metadatum = metadata[seqNum] || {}
return (
Expand All @@ -172,5 +202,5 @@ ChannelMetadata.propTypes = {
metadata: metadataType,
}

const buildImageURI = (locationName, cameraName, channelName, filename) =>
const buildMediaURI = (locationName, cameraName, channelName, filename) =>
`${locationName}/${cameraName}/${channelName}/${filename}`
Loading

0 comments on commit abbb1a2

Please sign in to comment.