diff --git a/Dockerfile b/Dockerfile
index faaf1f14..f86a1a0e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,6 +16,8 @@ RUN echo -e " server {\n" \
" root /app;\n" \
" index index.html;\n" \
" try_files \$uri \$uri/ /index.html;\n" \
+ " add_header 'Cross-Origin-Embedder-Policy' 'require-corp';\n" \
+ " add_header 'Cross-Origin-Opener-Policy' 'same-origin';\n" \
" }\n" \
" }\n" \
> /etc/nginx/conf.d/datalab.conf
diff --git a/package-lock.json b/package-lock.json
index 34f02b80..a9a0e9c6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"vue": "^3.5.9",
"vue-router": "^4.2.5",
"vue3-carousel": "^0.3.1",
- "vuetify": "^3.6.0",
+ "vuetify": "^3.7.4",
"webfontloader": "^1.0.0"
},
"devDependencies": {
@@ -12726,9 +12726,9 @@
}
},
"node_modules/vuetify": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.6.0.tgz",
- "integrity": "sha512-ic7VrB+nOTo8F7APhcKPjtDEO3yBCK5CJ2LIQ/4oAC/aaAKtuGuNMBUiUVitDKQjr0tcnDgy9Ar1CrHU5d28IA==",
+ "version": "3.7.4",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.4.tgz",
+ "integrity": "sha512-Y8UU5wUDQXC3oz2uumPb8IOdvB4XMCxtxnmqdOc+LihNuPlkSgxIwf92ndRzbOtJFKHsggFUxpyLqpQp+A+5kg==",
"engines": {
"node": "^12.20 || >=14.13"
},
@@ -12740,7 +12740,6 @@
"typescript": ">=4.7",
"vite-plugin-vuetify": ">=1.0.0",
"vue": "^3.3.0",
- "vue-i18n": "^9.0.0",
"webpack-plugin-vuetify": ">=2.0.0"
},
"peerDependenciesMeta": {
@@ -12750,9 +12749,6 @@
"vite-plugin-vuetify": {
"optional": true
},
- "vue-i18n": {
- "optional": true
- },
"webpack-plugin-vuetify": {
"optional": true
}
diff --git a/package.json b/package.json
index 393e5634..f5a0c48f 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"vue": "^3.5.9",
"vue-router": "^4.2.5",
"vue3-carousel": "^0.3.1",
- "vuetify": "^3.6.0",
+ "vuetify": "^3.7.4",
"webfontloader": "^1.0.0"
},
"devDependencies": {
diff --git a/src/assets/MockData.JSON b/src/assets/MockData.JSON
new file mode 100644
index 00000000..e0a37b05
--- /dev/null
+++ b/src/assets/MockData.JSON
@@ -0,0 +1,195 @@
+[
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000001",
+ "time": "2023-12-11 00:15",
+ "object": "M33",
+ "image": "images/image1.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000002",
+ "time": "2023-12-11 00:30",
+ "object": "NGC 224",
+ "image": "images/image2.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000003",
+ "time": "2023-12-11 00:45",
+ "object": "NGC 253",
+ "image": "images/image3.png"
+ },
+ {
+ "basefile_name": "sro2-sq002ms-20231210-00000004",
+ "time": "2023-12-11 01:00",
+ "object": "M81",
+ "image": "images/image4.png"
+ },
+ {
+ "basefile_name": "eco1-ec002cs-20231210-00000005",
+ "time": "2023-12-11 01:15",
+ "object": "M82",
+ "image": "images/image5.png"
+ },
+ {
+ "basefile_name": "eco2-sq003cm-20231210-00000006",
+ "time": "2023-12-11 01:30",
+ "object": "M87",
+ "image": "images/image6.png"
+ },
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000007",
+ "time": "2023-12-11 01:45",
+ "object": "NGC 5128",
+ "image": "images/image7.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000008",
+ "time": "2023-12-11 02:00",
+ "object": "NGC 4736",
+ "image": "images/image8.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000009",
+ "time": "2023-12-11 02:15",
+ "object": "NGC 4826",
+ "image": "images/image9.png"
+ },
+ {
+ "basefile_name": "sro2-sq002ms-20231210-00000010",
+ "time": "2023-12-11 02:30",
+ "object": "NGC 5055",
+ "image": "images/image10.png"
+ },
+ {
+ "basefile_name": "eco1-ec002cs-20231210-00000011",
+ "time": "2023-12-11 02:45",
+ "object": "NGC 6946",
+ "image": "images/image11.png"
+ },
+ {
+ "basefile_name": "eco2-sq003cm-20231210-00000012",
+ "time": "2023-12-11 03:00",
+ "object": "NGC 5194",
+ "image": "images/image12.png"
+ },
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000013",
+ "time": "2023-12-11 03:15",
+ "object": "NGC 5236",
+ "image": "images/image13.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000014",
+ "time": "2023-12-11 03:30",
+ "object": "NGC 5457",
+ "image": "images/image14.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000015",
+ "time": "2023-12-11 03:45",
+ "object": "NGC 3031",
+ "image": "images/image15.png"
+ },
+ {
+ "basefile_name": "eco1-ec002cs-20231210-00000016",
+ "time": "2023-12-11 04:00",
+ "object": "NGC 5195",
+ "image": "images/image16.png"
+ },
+ {
+ "basefile_name": "eco2-sq003cm-20231210-00000017",
+ "time": "2023-12-11 04:15",
+ "object": "IC 342",
+ "image": "images/image17.png"
+ },
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000018",
+ "time": "2023-12-11 04:30",
+ "object": "NGC 2403",
+ "image": "images/image18.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000019",
+ "time": "2023-12-11 04:45",
+ "object": "NGC 2903",
+ "image": "images/image19.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000020",
+ "time": "2023-12-11 05:00",
+ "object": "NGC 3184",
+ "image": "images/image20.png"
+ },
+ {
+ "basefile_name": "sro2-sq002ms-20231210-00000021",
+ "time": "2023-12-11 05:15",
+ "object": "NGC 3344",
+ "image": "images/image21.png"
+ },
+ {
+ "basefile_name": "eco1-ec002cs-20231210-00000022",
+ "time": "2023-12-11 05:30",
+ "object": "NGC 3621",
+ "image": "images/image22.png"
+ },
+ {
+ "basefile_name": "eco2-sq003cm-20231210-00000023",
+ "time": "2023-12-11 05:45",
+ "object": "NGC 3627",
+ "image": "images/image23.png"
+ },
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000024",
+ "time": "2023-12-11 06:00",
+ "object": "NGC 4244",
+ "image": "images/image24.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000025",
+ "time": "2023-12-11 06:15",
+ "object": "NGC 4258",
+ "image": "images/image25.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000026",
+ "time": "2023-12-11 06:30",
+ "object": "NGC 4559",
+ "image": "images/image26.png"
+ },
+ {
+ "basefile_name": "sro2-sq002ms-20231210-00000027",
+ "time": "2023-12-11 06:45",
+ "object": "NGC 4565",
+ "image": "images/image27.png"
+ },
+ {
+ "basefile_name": "eco1-ec002cs-20231210-00000028",
+ "time": "2023-12-11 07:00",
+ "object": "NGC 4631",
+ "image": "images/image28.png"
+ },
+ {
+ "basefile_name": "eco2-sq003cm-20231210-00000029",
+ "time": "2023-12-11 07:15",
+ "object": "NGC 4725",
+ "image": "images/image29.png"
+ },
+ {
+ "basefile_name": "aro1-sq002ms-20231210-00000030",
+ "time": "2023-12-11 07:30",
+ "object": "NGC 4736",
+ "image": "images/image30.png"
+ },
+ {
+ "basefile_name": "mrc1-ec002cs-20231210-00000031",
+ "time": "2023-12-11 07:45",
+ "object": "NGC 4826",
+ "image": "images/image31.png"
+ },
+ {
+ "basefile_name": "mrc2-sq003cm-20231210-00000032",
+ "time": "2023-12-11 08:00",
+ "object": "NGC 5055",
+ "image": "images/image32.png"
+ }
+]
+
diff --git a/src/assets/images/image1.png b/src/assets/images/image1.png
new file mode 100644
index 00000000..7c1cb866
Binary files /dev/null and b/src/assets/images/image1.png differ
diff --git a/src/assets/images/image10.png b/src/assets/images/image10.png
new file mode 100644
index 00000000..b3c9e1fc
Binary files /dev/null and b/src/assets/images/image10.png differ
diff --git a/src/assets/images/image11.png b/src/assets/images/image11.png
new file mode 100644
index 00000000..a0b76eb3
Binary files /dev/null and b/src/assets/images/image11.png differ
diff --git a/src/assets/images/image12.png b/src/assets/images/image12.png
new file mode 100644
index 00000000..c6df68aa
Binary files /dev/null and b/src/assets/images/image12.png differ
diff --git a/src/assets/images/image13.png b/src/assets/images/image13.png
new file mode 100644
index 00000000..da1dbef2
Binary files /dev/null and b/src/assets/images/image13.png differ
diff --git a/src/assets/images/image14.png b/src/assets/images/image14.png
new file mode 100644
index 00000000..828c0fa6
Binary files /dev/null and b/src/assets/images/image14.png differ
diff --git a/src/assets/images/image15.png b/src/assets/images/image15.png
new file mode 100644
index 00000000..ddae93c3
Binary files /dev/null and b/src/assets/images/image15.png differ
diff --git a/src/assets/images/image16.png b/src/assets/images/image16.png
new file mode 100644
index 00000000..b7f32c93
Binary files /dev/null and b/src/assets/images/image16.png differ
diff --git a/src/assets/images/image17.png b/src/assets/images/image17.png
new file mode 100644
index 00000000..d44e2664
Binary files /dev/null and b/src/assets/images/image17.png differ
diff --git a/src/assets/images/image18.png b/src/assets/images/image18.png
new file mode 100644
index 00000000..74d133e8
Binary files /dev/null and b/src/assets/images/image18.png differ
diff --git a/src/assets/images/image19.png b/src/assets/images/image19.png
new file mode 100644
index 00000000..27d6ec0a
Binary files /dev/null and b/src/assets/images/image19.png differ
diff --git a/src/assets/images/image2.png b/src/assets/images/image2.png
new file mode 100644
index 00000000..7bc7c9fc
Binary files /dev/null and b/src/assets/images/image2.png differ
diff --git a/src/assets/images/image20.png b/src/assets/images/image20.png
new file mode 100644
index 00000000..108afc17
Binary files /dev/null and b/src/assets/images/image20.png differ
diff --git a/src/assets/images/image21.png b/src/assets/images/image21.png
new file mode 100644
index 00000000..534ddbf5
Binary files /dev/null and b/src/assets/images/image21.png differ
diff --git a/src/assets/images/image22.png b/src/assets/images/image22.png
new file mode 100644
index 00000000..a813e7ce
Binary files /dev/null and b/src/assets/images/image22.png differ
diff --git a/src/assets/images/image23.png b/src/assets/images/image23.png
new file mode 100644
index 00000000..8206687e
Binary files /dev/null and b/src/assets/images/image23.png differ
diff --git a/src/assets/images/image24.png b/src/assets/images/image24.png
new file mode 100644
index 00000000..84e9ebd2
Binary files /dev/null and b/src/assets/images/image24.png differ
diff --git a/src/assets/images/image25.png b/src/assets/images/image25.png
new file mode 100644
index 00000000..6881c473
Binary files /dev/null and b/src/assets/images/image25.png differ
diff --git a/src/assets/images/image26.png b/src/assets/images/image26.png
new file mode 100644
index 00000000..8e9e146f
Binary files /dev/null and b/src/assets/images/image26.png differ
diff --git a/src/assets/images/image27.png b/src/assets/images/image27.png
new file mode 100644
index 00000000..0fa50bed
Binary files /dev/null and b/src/assets/images/image27.png differ
diff --git a/src/assets/images/image28.png b/src/assets/images/image28.png
new file mode 100644
index 00000000..659b83b1
Binary files /dev/null and b/src/assets/images/image28.png differ
diff --git a/src/assets/images/image29.png b/src/assets/images/image29.png
new file mode 100644
index 00000000..796d9329
Binary files /dev/null and b/src/assets/images/image29.png differ
diff --git a/src/assets/images/image3.png b/src/assets/images/image3.png
new file mode 100644
index 00000000..f8422e53
Binary files /dev/null and b/src/assets/images/image3.png differ
diff --git a/src/assets/images/image30.png b/src/assets/images/image30.png
new file mode 100644
index 00000000..f0a63008
Binary files /dev/null and b/src/assets/images/image30.png differ
diff --git a/src/assets/images/image31.png b/src/assets/images/image31.png
new file mode 100644
index 00000000..84545e31
Binary files /dev/null and b/src/assets/images/image31.png differ
diff --git a/src/assets/images/image32.png b/src/assets/images/image32.png
new file mode 100644
index 00000000..cffdc0b0
Binary files /dev/null and b/src/assets/images/image32.png differ
diff --git a/src/assets/images/image4.png b/src/assets/images/image4.png
new file mode 100644
index 00000000..a0419e69
Binary files /dev/null and b/src/assets/images/image4.png differ
diff --git a/src/assets/images/image5.png b/src/assets/images/image5.png
new file mode 100644
index 00000000..8ee95c30
Binary files /dev/null and b/src/assets/images/image5.png differ
diff --git a/src/assets/images/image6.png b/src/assets/images/image6.png
new file mode 100644
index 00000000..d548f68b
Binary files /dev/null and b/src/assets/images/image6.png differ
diff --git a/src/assets/images/image7.png b/src/assets/images/image7.png
new file mode 100644
index 00000000..f4e5a764
Binary files /dev/null and b/src/assets/images/image7.png differ
diff --git a/src/assets/images/image8.png b/src/assets/images/image8.png
new file mode 100644
index 00000000..8f97619b
Binary files /dev/null and b/src/assets/images/image8.png differ
diff --git a/src/assets/images/image9.png b/src/assets/images/image9.png
new file mode 100644
index 00000000..2bb84677
Binary files /dev/null and b/src/assets/images/image9.png differ
diff --git a/src/components/DataSession/OperationWizard.vue b/src/components/DataSession/OperationWizard.vue
index 505a7f52..2af91d0c 100644
--- a/src/components/DataSession/OperationWizard.vue
+++ b/src/components/DataSession/OperationWizard.vue
@@ -3,7 +3,7 @@ import { ref, onMounted, computed, defineEmits, defineProps} from 'vue'
import { fetchApiCall, handleError } from '@/utils/api'
import { calculateColumnSpan } from '@/utils/common'
import ImageGrid from '../Global/ImageGrid'
-import ImageScalingGroup from '../Global/ImageScalingGroup'
+import ImageScalingGroup from '../Global/Scaling/ImageScalingGroup'
import { useConfigurationStore } from '@/stores/configuration'
import { useAlertsStore } from '@/stores/alerts'
diff --git a/src/components/Global/CompositeImage.vue b/src/components/Global/Scaling/CompositeImage.vue
similarity index 100%
rename from src/components/Global/CompositeImage.vue
rename to src/components/Global/Scaling/CompositeImage.vue
diff --git a/src/components/Global/Scaling/HistogramSlider.vue b/src/components/Global/Scaling/HistogramSlider.vue
new file mode 100644
index 00000000..41d23238
--- /dev/null
+++ b/src/components/Global/Scaling/HistogramSlider.vue
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Z-Scale
+
+
+
+
+
+
+
+
+ {{ labelSliderToScaleValue(modelValue) }}
+
+
+
+
+
+
diff --git a/src/components/Global/ImageScaler.vue b/src/components/Global/Scaling/ImageScaler.vue
similarity index 58%
rename from src/components/Global/ImageScaler.vue
rename to src/components/Global/Scaling/ImageScaler.vue
index c4b04bd2..75f51444 100644
--- a/src/components/Global/ImageScaler.vue
+++ b/src/components/Global/Scaling/ImageScaler.vue
@@ -3,6 +3,7 @@ import { ref, computed, onMounted, defineEmits, defineProps } from 'vue'
import { useConfigurationStore } from '@/stores/configuration'
import { fetchApiCall } from '@/utils/api'
import RawScaledImage from './RawScaledImage.vue'
+import HistogramSlider from './HistogramSlider.vue'
// This component gets the raw image data from the server for an image
// and then displays the image and the scaling controls under it
@@ -33,7 +34,7 @@ const isLoading = ref(true)
const errorReason = ref('')
const rawData = ref({})
const sliderRange = ref([0, 65535])
-var zScaleValues = null
+const zScaleValues = ref([0, 65535])
const titleText = computed(() => {
return props.imageName.replace('_', ' ')
@@ -49,24 +50,29 @@ const maxPixelValue = computed(() => {
}
})
-function updateLowerScale(value) {
- sliderRange.value = [Number(value), sliderRange.value[1]]
- emit('updateScaling', props.imageName, sliderRange.value[0], sliderRange.value[1])
-}
-
-function updateUpperScale(value) {
- sliderRange.value = [sliderRange.value[0], Number(value)]
- emit('updateScaling', props.imageName, sliderRange.value[0], sliderRange.value[1])
-}
+const histogram = computed(() => {
+ if (rawData.value && rawData.value.histogram) {
+ return rawData.value.histogram
+ }
+ else {
+ return [0, 10, 10, 5, 4, 3, 2, 1]
+ }
+})
-function zScaleImage() {
- if (zScaleValues){
- sliderRange.value = [...zScaleValues]
+const bins = computed(() => {
+ if (rawData.value && rawData.value.bins) {
+ return rawData.value.bins
+ }
+ else {
+ return [0, 1, 2, 3, 4, 5, 6, 7]
}
+})
+
+function updateScaleRange(lowerValue, upperValue) {
+ sliderRange.value = [Number(lowerValue), Number(upperValue)]
emit('updateScaling', props.imageName, sliderRange.value[0], sliderRange.value[1])
}
-
onMounted(async () => {
const url = dataSessionsUrl + 'analysis/raw-data/'
const body = {
@@ -77,8 +83,7 @@ onMounted(async () => {
fetchApiCall({url: url, method: 'POST', body: body,
successCallback: (response) => {
rawData.value = response
- zScaleValues = [response.zmin, response.zmax]
- zScaleImage()
+ zScaleValues.value = [response.zmin, response.zmax]
isLoading.value = false
},
failCallback: (error) => {
@@ -106,46 +111,17 @@ onMounted(async () => {
-
-
-
-
-
-
-
-
- ZScale
-
-
+
+
+
+
diff --git a/src/components/Global/ImageScalingGroup.vue b/src/components/Global/Scaling/ImageScalingGroup.vue
similarity index 98%
rename from src/components/Global/ImageScalingGroup.vue
rename to src/components/Global/Scaling/ImageScalingGroup.vue
index 80b3370c..21c848f4 100644
--- a/src/components/Global/ImageScalingGroup.vue
+++ b/src/components/Global/Scaling/ImageScalingGroup.vue
@@ -69,7 +69,6 @@ watch(
:key="groupName"
:value="groupName"
>
-
-
diff --git a/src/components/Global/RawScaledImage.vue b/src/components/Global/Scaling/RawScaledImage.vue
similarity index 100%
rename from src/components/Global/RawScaledImage.vue
rename to src/components/Global/Scaling/RawScaledImage.vue
diff --git a/src/utils/imageLoader.js b/src/utils/imageLoader.js
new file mode 100644
index 00000000..b0e60631
--- /dev/null
+++ b/src/utils/imageLoader.js
@@ -0,0 +1,83 @@
+import { fetchApiCall } from '@/utils/api'
+import { useConfigurationStore } from '@/stores/configuration'
+
+const cacheOptions = { 'ignoreVary': true, 'ignoreMethod': true, 'ignoreSearch': true }
+
+
+async function getAllCacheKeys(size) {
+ const cacheName = size + 'Thumbnails'
+ return caches.open(cacheName).then((cache) => {
+ return cache.keys().then((keys) => {
+ return keys
+ })
+ })
+}
+
+async function getImageFromBasename(size, archive, url, imageBasename) {
+ // Clean up the -large or -small on the basename from ptr archive images
+ imageBasename = imageBasename.replace('-small', '').replace('-large', '')
+ const cacheName = size + 'Thumbnails'
+ return caches.open(cacheName).then((cache) => {
+ return cache.match(imageBasename, cacheOptions).then(function (response) {
+ // If not found in cache, then fetch image thumbnail from url or from archive and cache the result and return it
+ return response || cacheImageFromBasename(size, archive, url, imageBasename)
+ })
+ })
+}
+
+async function deleteCachedImageFromBasename(size, imageBasename) {
+ const cacheName = size + 'Thumbnails'
+ return caches.open(cacheName).then((cache) => {
+ return cache.delete(imageBasename, cacheOptions)
+ })
+}
+
+async function cacheImageFromUrl(size, url, imageBasename) {
+ const imageResponse = await fetch(url, { method: 'GET', mode: 'cors' })
+ const cacheName = size + 'Thumbnails'
+ caches.open(cacheName).then((cache) => {
+ cache.put(imageBasename, imageResponse.clone())
+ })
+ return imageResponse.clone()
+}
+
+async function cacheImageFromBasename(size, archive, url, imageBasename) {
+ // Right now we only have a ptr archive, but planning to maybe use this to differentiate later
+ // If url exists, it will use that to directly download and cache image. If not it will use
+ // the archive to decide how to fetch the image based on its basename and archive.
+ if (url) {
+ return cacheImageFromUrl(size, url, imageBasename)
+ }
+ else {
+ const store = useConfigurationStore()
+ if (archive == 'ptr') {
+ const thumbnailBasename = imageBasename + '-' + size
+ const frameUrl = store.datalabArchiveApiUrl + 'frames/?basename_exact=' + thumbnailBasename
+ const responseData = await fetchApiCall({ url: frameUrl, method: 'GET', mode: 'cors' })
+ if (responseData && responseData.results) {
+ url = responseData.results[0].url
+ }
+ }
+ else if (archive == 'lco') {
+ // Use the lco thumbnail service to get the image thumbnail given its basename
+ var width = 200
+ if (size == 'large') {
+ width = 1000
+ }
+ // Thumbnail service needs to set width and height or sometimes it creates a smaller thumbnail then requested
+ const thumbnailServiceUrl = store.thumbnailServiceUrl + imageBasename + '/?width=' + width + '&height=' + width
+ const responseData = await fetchApiCall({ url: thumbnailServiceUrl, method: 'GET'})
+ if (responseData && responseData.url) {
+ url = responseData.url
+ }
+ }
+ if (!url) {
+ console.error('Failed to get frame data for image ' + imageBasename)
+ }
+ else {
+ return cacheImageFromUrl(size, url, imageBasename)
+ }
+ }
+}
+
+export { getImageFromBasename, deleteCachedImageFromBasename, getAllCacheKeys }