当前位置: 首页 > news >正文

基于cornerstone3D的dicom影像浏览器 第二章,初始化页面结构

完整效果:

cornerstone3D的dicom影像浏览器

本章效果预览:
 

1.在views/home/index.vue中:

<template><div class="container flex-vertical" ref="view2d"><div class="header flex-horizontal"><div class="logo">logo</div><div class="study-list">study list</div></div><div class="main" :class="mainClass"><div :class="toolbarClass" :style="toolbarStyle"></div><div class="nav-display" :class="navDisplayClass"><div :class="navClass" :style="navbarStyle">series list</div><div class="display-area"><displayer-area ref="displayArea"></displayer-area></div></div></div><div class="footer">study bar</div></div>
</template>
<script setup name="View2d">
import { ref, onMounted, computed } from "vue";
import displayerArea from "@/components/displayerArea/index.vue";
const view2d = ref(null);
const navbarHW = ref(146);
const toolbarHW = ref(300);
const toolbarPos = ref("right"); // top or right
const navbarPos = ref("lef"); // bottom or leftconst mainClass = computed(() => {const vorh = toolbarPos.value === "top" ? "vertical" : "horizontal-reverse";return "flex-" + vorh;
});const toolbarClass = computed(() => {return "toolbar-" + toolbarPos.value;
});const toolbarStyle = computed(() => {if (toolbarPos.value === "top") {return {height: toolbarHW.value + "px",};} else {return {width: toolbarHW.value + "px",};}
});const navDisplayClass = computed(() => {const vorh = navbarPos.value === "bottom" ? "vertical-reverse" : "horizontal";return "flex-" + vorh;
});const navClass = computed(() => {return "nav-" + navbarPos.value;
});const navbarStyle = computed(() => {if (navbarPos.value === "bottom") {return {height: navbarHW.value + "px",};} else {return {width: navbarHW.value + "px",};}
});</script>
<style scoped lang="scss">
$bg-color: #333;
$main-color: lightblue;
// $header-color: #108ee9;
$header-color: #45b7ec;
$footer-color: #45b7ec;
$resizer-width: 2px;
$header-height: 50px;
$footer-height: 100px;.container {background-color: $bg-color;height: 100vh;width: 100vw;max-width: 100%;max-height: 100%;justify-content: center;// align-items: center;text-align: center;color: black;user-select: none;
}.flex-vertical {display: flex;flex-direction: column;
}.flex-vertical-reverse {display: flex;flex-direction: column-reverse;
}.flex-horizontal {display: flex;flex-direction: row;
}.flex-horizontal-reverse {display: flex;flex-direction: row-reverse;
}.resizer-vertical {cursor: ew-resize;width: $resizer-width;background-color: gray;z-index: 10;
}.resizer-horizontal {cursor: ns-resize;height: $resizer-width;background-color: gray;width: 100%;z-index: 10;
}.header {height: $header-height;background-color: $header-color;border-bottom: gray solid 1px;.logo {height: 100%;width: 200px;border-right: gray solid 1px;flex-shrink: 0;}.study-list {flex: 1;height: 100%;// background-color: lightblue;}
}.main {width: 100%;height: calc(100vh - $header-height - $footer-height);background-color: $main-color;.nav-display {flex: 1;}.toolbar-top {height: 200px;width: 100%;}.toolbar-right {width: 200px;height: 100%;}.nav-display {.display-area {flex: 1;flex-shrink: 0;}.nav-left {height: 100%;}.nav-bottom {width: 100%;}}
}.footer {background-color: $footer-color;height: $footer-height;border-top: gray solid 1px;
}
</style>

2.displayerArea组件:

<script lang="js" setup name="DisplayerArea">
import { ref, onMounted, computed, reactive, nextTick } from "vue";
import Displayer from "@/components/Displayer/index.vue";
import { useAppStore } from "@/store/appStore.js";
import config from "@/config/index.js"
const appStore = useAppStore();
const { layout, pageSize } = appStore.$stateconst dispRefs = reactive([]);
const selected = [];
const maxDisp = null;
const domWidth = ref(0);const containerStyle = computed(() => {let result = {display: 'gird','grid-template-columns': repeat(layout.row, "1fr"),height: '100%'};return result
});const repeat = (n, s) => {let dst = "";for (let i = 0; i < n; i++) {dst += s + " ";}return dst;
};const getDispRef = (el, pos) => {if (el) {dispRefs[pos] = el;}
};const setLayout = (row, col) => {appStore.setLayout(row, col)selected.length = 0;
};onMounted(() => {const { row, col } = config.defLayout setLayout(row, col);
});
</script><template><div class="displayarea" :style="containerStyle"><Displayerv-for="(v, idx) in pageSize":key="idx":ref="el => getDispRef(el, idx)":pos="idx"/></div>
</template><style lang="scss" scoped>
.displayarea{display: grid;grid-gap: 1px 1px;background-color: black;color: #fff;
}
</style>

3.Displayer

<script lang="js" setup name="Displayer">
import { ref, reactive, onMounted, computed, getCurrentInstance, onUnmounted } from "vue";
const IsSel = ref(false);const borderClass = computed(() => {let s = "selected";if (IsSel.value) {s = "selected";} else {if (IsHover.value) {s = "hovered";} else {s = "unselect";}}return s;});</script><template><divclass="displaybox":class="borderClass"><div class="displayer" ref="displayer"></div></div>
</template>
<style lang="scss" scoped>
.displaybox {position: relative;display: flex;flex-direction: row;background-color: black;.scroll-right {width: 20px;}
}
.displayer {flex: 1;text-align: left;cursor: default;user-select: none;$font-size: 14px;@mixin orient($text-align: left) {position: absolute;color: white;font-size: $font-size;text-align: $text-align;z-index: 10;}.orient_top {@include orient(center);top: 2px;left: calc(50% - 30px);width: 60px;}.orient_bottom {@include orient(center);bottom: 2px;left: calc(50% - 30px);width: 60px;}.orient_left {@include orient();top: calc(50% - 20px);left: 2px;}.orient_right {@include orient();top: calc(50% - 20px);right: 2px;}
}.selected {border: 1px solid red;
}
.hovered {border: 1px dashed yellow;
}
.unselect {border: 1px solid #fff;
}
</style>

4.app store

import { defineStore } from "pinia";
export const useAppStore = defineStore("app", {state: () => {return {layout: {col: 2,row: 2},pageSize: 4}},actions:{setLayout(row, col){this.layout.col = colthis.layout.row = row}}
})

http://www.xdnf.cn/news/1128097.html

相关文章:

  • 亚矩阵云手机:破解 Yandex 广告平台多账号风控难题的利器
  • 跨平台游戏引擎 Axmol-2.7.1 发布
  • APP端定位实现(uniapp Vue3)(腾讯地图)
  • Ext系列文件系统知识点
  • Linux进程信号--1、信号产生
  • 时间复杂度和空间复杂度是衡量一个算法好坏的标准
  • A*算法详解
  • 9、线程理论1
  • eVTOL分布式电推进(DEP)适航审定探究
  • redisson tryLock
  • Spring MVC2
  • 尚庭公寓-----day1----@MapperScan爆红问题
  • 三十二、【核心功能改造】数据驱动:重构仪表盘与关键指标可视化
  • 【转】Rust: PhantomData,#may_dangle和Drop Check 真真假假
  • 【字节跳动】数据挖掘面试题0019:带货直播间推荐:现在有一个带货的直播间,怎么把它精准地推送给有需要的用户
  • 【C++】神奇的AVL树
  • WebView JSBridge 无响应问题排查实录 全流程定位桥接调用失效
  • 无人机故障响应模块运行与技术难点
  • Ubuntu24 辅助系统-屏幕键盘的back按键在网页文本框删除不正常的问题解决方法
  • RTL编程中常用的几种语言对比
  • 【C#地图显示教程:实现鼠标绘制图形操作】
  • 厂区车辆导航系统:基于 GPS+AI 动态路径规划的技术实现与实践
  • 春秋云镜 initial
  • 2025开放原子开源生态大会 | openKylin的技术跃迁和全球协作
  • 2025开放原子开源生态大会 | 开源欧拉的AI原生实践与全球协作
  • GaussDB 数据库架构师修炼(三) 集群管理概览
  • 李宏毅《生成式人工智能导论》 | 第11讲-第14讲:大型语言模型的可解释性、能力评估、安全性
  • React源码5 三大核心模块之一:render,renderRoot
  • docker-compose 配置启动2个MongoDB
  • 【Docker基础】Dockerfile构建与运行流程完全指南:从原理到实践优化