特性:
- 支持缩放瓦片图,定义瓦片图初始缩放比例,以鼠标所在位置为中心缩放
- 支持局部拖拽加载
- 支持设置瓦片图原始宽高度
- <template>
- <div :class="$options.name" :fullscreen="fullScreenAll">
-
- <template>
- <div class="sg-ctrl" v-if="tiles.length">
- <label>缩放百分比label>
- <el-input-number
- style="width: 150px"
- v-model.trim="scaleValue"
- :precision="0"
- :step="10"
- :min="10"
- :max="100"
- :controls-position="`left`"
- @change="changeScaleValue"
- />
-
-
- <div class="btn" v-if="!$store.getters._global.inWindow">
- <fullscreenHtml :size="`default`" @change="(d) => (fullScreenAll = d)" />
- div>
-
-
- <el-button class="btn" type="primary" @click="showreviewImg = true"
- >查看预览图
- >
- div>
- <div class="sg-tile-img" ref="scrollContainer">
- <div
- ref="dragContainer"
- :style="{ width: `${width * colCount}px`, height: `${height * rowCount}px` }"
- >
- <img
- v-for="(a, i) in tiles"
- :key="i"
- :ref="`tile${i}`"
- :loaded="a.loaded"
- :width="width"
- :height="height"
- draggable="false"
- />
- div>
- div>
- template>
-
-
- <template v-if="previewImgURL && showreviewImg">
- <div class="preview-sm-image">
- <img :src="previewImgURL" />
- <el-tooltip
- :content="`查看瓦片图`"
- :effect="`light`"
- :enterable="false"
- :placement="`top-start`"
- :popper-class="`sg-el-tooltip`"
- :transition="`none`"
- ><el-button
- class="sg-closeModalBtn"
- type="primary"
- icon="el-icon-close"
- @click="showreviewImg = false"
- circle
- />
- el-tooltip>
- <div class="bg" @click="showreviewImg = false">div>
- div>
- template>
-
-
- <sgDragMoveTile :data="dragMoveTileData" @dragMove="dragMove" />
- div>
- template>
- <script>
- import fullscreenHtml from "@/vue/components/admin/fullscreenHtml";
- import sgDragMoveTile from "@/vue/components/admin/sgDragMoveTile";
- export default {
- name: "sgTileImage",
- components: {
- fullscreenHtml,
- sgDragMoveTile,
- },
- data() {
- return {
- fullScreenAll: false,
- dragMoveTileData: {},
- scaleValue: 100,
- orginWidth: 0, //瓦片图原始宽度
- orginHeight: 0, //瓦片图原始高度
- width: 0, //瓦片图实时宽度
- height: 0, //瓦片图实时高度
- colCount: 0,
- rowCount: 0,
- tiles: [], //瓦片图数组
- previewImgURL: ``, //预览图片路径
- showreviewImg: true,
- mousePoint_bk: null,
- };
- },
- props: [
- "data",
- /* data格式:{
- width:500,//瓦片图原始宽度
- height:500,//瓦片图原始高度
- colCount: 20,//行数
- rowCount: 20,//列数
- scaleValue: 100,//缩放百分比
- tiles: [],//瓦片图数组
- } */
- ],
- watch: {
- data: {
- handler(newValue, oldValue) {
- if (newValue && Object.keys(newValue).length) {
- newValue = JSON.parse(JSON.stringify(newValue));
- newValue.width && (this.orginWidth = newValue.width); //记录原始宽度
- newValue.height && (this.orginHeight = newValue.height); //记录原始高度度
- newValue.width && (this.width = newValue.width);
- newValue.height && (this.height = newValue.height);
- newValue.colCount && (this.colCount = newValue.colCount);
- newValue.rowCount && (this.rowCount = newValue.rowCount);
- newValue.tiles && (this.tiles = newValue.tiles);
- newValue.scaleValue && (this.scaleValue = newValue.scaleValue);
- newValue.previewImgURL && (this.previewImgURL = newValue.previewImgURL);
- this.$nextTick(() => {
- this.loadScreenViewTiles();
- });
- }
- },
- deep: true, //深度监听
- immediate: true, //立即执行
- },
- scaleValue: {
- handler(newValue, oldValue) {
- this.width = (this.orginWidth * newValue) / 100;
- this.height = (this.orginHeight * newValue) / 100;
- this.$nextTick(() => {
- this.loadScreenViewTiles();
- });
- },
- deep: true, //深度监听
- immediate: true, //立即执行
- },
- },
- destroyed() {
- removeEventListener("mousewheel", this.mousewheel);
- },
- mounted() {
- this.dragMoveTileData = {
- scrollContainer: this.$refs.scrollContainer,
- dragContainer: this.$refs.dragContainer,
- };
- let rect_scrollContainer = this.$refs.scrollContainer.getBoundingClientRect();
- this.mousePoint_bk = {
- x: rect_scrollContainer.width / 2,
- y: rect_scrollContainer.height / 2,
- };
- setTimeout(() => {
- this.loadScreenViewTiles();
- addEventListener("mousewheel", this.mousewheel, { passive: false });
- }, 1000);
- },
- methods: {
- // 校正放大缩小后,瓦片图的坐标(目的是为了让缩放看起来是以鼠标坐标为中心点)
- centerPosition(
- e,
- { rect_dragContainer_orign, scrollLeft_orgin, scrollTop_orgin, mousePoint }
- ) {
- let scrollContainer = this.$refs.scrollContainer;
- let dragContainer = this.$refs.dragContainer;
- let rect_dragContainer = dragContainer.getBoundingClientRect();
- let scale = rect_dragContainer.width / rect_dragContainer_orign.width; //缩放比例
- let mouse_left_dis_orgin = scrollLeft_orgin + mousePoint.x; //缩放前鼠标距离瓦片图最左侧的距离
- let mouse_top_dis_orgin = scrollTop_orgin + mousePoint.y; //缩放前鼠标距离瓦片图最顶部的距离
- let mouse_left_dis = mouse_left_dis_orgin * scale; //缩放后鼠标距离瓦片图最左侧的距离
- let mouse_top_dis = mouse_top_dis_orgin * scale; //缩放后鼠标距离瓦片图最顶部的距离
- let scrollLeft = mouse_left_dis - mousePoint.x;
- let scrollTop = mouse_top_dis - mousePoint.y;
- scrollContainer.scrollLeft = scrollLeft;
- scrollContainer.scrollTop = scrollTop;
- this.mousePoint_bk = mousePoint;
- },
- mousewheel(e) {
- if (!this.$refs.dragContainer || this.showreviewImg) return false;
- // 记录缩放前的数据
- let rect_dragContainer_orign = this.$refs.dragContainer.getBoundingClientRect();
- let scrollContainer = this.$refs.scrollContainer;
- let mousePoint = { x: e.x, y: e.y };
- let scrollLeft_orgin = scrollContainer.scrollLeft;
- let scrollTop_orgin = scrollContainer.scrollTop;
- // 开始缩放
- e.deltaY < 0 && (this.scaleValue += 10);
- e.deltaY > 0 && (this.scaleValue -= 10);
- // 开始计算坐标
- this.$nextTick(() => {
- this.centerPosition(e, {
- rect_dragContainer_orign,
- scrollLeft_orgin,
- scrollTop_orgin,
- mousePoint,
- });
- });
- e.preventDefault && e.preventDefault(); //阻止默认的滚轮事件
- return false;
- },
- // 获取浏览器可视范围的瓦片图,并加载图片
- loadScreenViewTiles(d) {
- let scrollContainer = this.$refs.scrollContainer;
- if (scrollContainer) {
- let rect_scrollContainer = scrollContainer.getBoundingClientRect();
- this.tiles.forEach((v, i) => {
- let tile = this.$refs[`tile${i}`];
- if (tile) {
- tile = tile[0];
- let rectTile = tile.getBoundingClientRect();
- if (
- rectTile.x + rectTile.width > rect_scrollContainer.x - rectTile.width &&
- rectTile.y + rectTile.height > rect_scrollContainer.y - rectTile.height &&
- rectTile.x < rect_scrollContainer.x + rect_scrollContainer.width &&
- rectTile.y < rect_scrollContainer.y + rect_scrollContainer.height
- ) {
- tile.onload = (d) => {
- v.loaded = true;
- };
- tile.src = v.img;
- }
- }
- });
- }
- },
- dragMove(d) {
- this.loadScreenViewTiles();
- },
- changeScaleValue(d) {
- this.mousewheel(this.mousePoint_bk);
- },
- },
- };
- script>
- <style lang="scss" scoped>
- .sgTileImage {
- .sg-ctrl {
- position: absolute;
- left: 10px;
- top: 10px;
- z-index: 1;
- box-sizing: border-box;
- padding: 10px 20px;
- background-color: white;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- border-radius: 4px;
- display: flex;
- align-items: center;
- justify-content: flex-end;
-
- label {
- margin-right: 10px;
- }
- .btn {
- margin-left: 10px;
- }
- }
-
- .sg-tile-img {
- position: absolute;
- left: 0;
- top: 0;
- overflow: auto;
- width: 100%;
- height: 100%;
-
- div {
- display: flex;
- flex-wrap: wrap;
-
- img {
- border: none;
- opacity: 0;
- transition: opacity 0.382s;
-
- &[loaded] {
- opacity: 1;
- }
- }
- }
- }
- .preview-sm-image {
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- // background-color: #000000cc;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
- z-index: 2;
- img {
- width: 100%;
- height: 100%;
- object-position: center;
- object-fit: contain;
- pointer-events: none;
- z-index: 1;
- }
- .bg {
- background-color: #000000cc;
- width: 100%;
- height: 100%;
- position: absolute;
- left: 0;
- top: 0;
- }
- }
- &[fullscreen] {
- position: fixed;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- z-index: 2000;
- background-color: white;
- }
- }
- style>
用例
- <template>
- <div>
- <sgTileImage :data="tileImageData" />
- div>
- template>
- <script>
- import sgTileImage from "@/vue/components/admin/sgTileImage";
- export default {
- components: { sgTileImage },
- data() {
- return {
- tileImageData: {
- width: 500, //瓦片图原始宽度(API提供)
- height: 500, //瓦片图原始高度(API提供)
- colCount: 0, //行数(API提供)
- rowCount: 0, //列数(API提供)
- tiles: [], //瓦片图数组(API提供)
- },
- };
- },
- created() {
- this.tileImageData.tiles = [
- ...Array(this.tileImageData.colCount * this.tileImageData.rowCount),
- ].map((v, i) => ({
- loaded: false,
- img: `http://rp.wedoyun.cn/tiles/${i}.jpg`,
- })); //瓦片图数组
- },
- };
- script>