【sgTileImage】自定义组件:瓦片图拖拽局部加载、实现以鼠标为中心缩放

简介: 【sgTileImage】自定义组件:瓦片图拖拽局部加载、实现以鼠标为中心缩放


特性:

  1. 支持缩放瓦片图,定义瓦片图初始缩放比例,以鼠标所在位置为中心缩放
  2. 支持局部拖拽加载

sgTileImage源码

<template>
    <div :class="$options.name">
        <div class="sg-ctrl">
            <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>
        <div class="sg-tile-img" ref="scrollContainer">
            <div ref="dragContainer" :style="{ width: `${tileSize * colCount}px` }">
                <img v-for="(a, i) in tiles" :key="i" :ref="`tile${i}`" :loaded="a.loaded" :width="tileSize"
                    :height="tileSize" draggable="false">
            </div>
        </div>
        <sgDragMoveTile :data="dragMoveTileData" @dragMove="dragMove" />
    </div>
</template>
<script>
import sgDragMoveTile from "@/vue/components/admin/sgDragMoveTile";
export default {
    name: 'sgTileImage',
    components: {
        sgDragMoveTile
    },
    data() {
        return {
            dragMoveTileData: {},
            scaleValue: 100,
            orginTileSize: 0,
            tileSize: 0,
            colCount: 0,
            rowCount: 0,
            tiles: [],//瓦片图数组
            mousePoint_bk: null,
        }
    },
    props: [
        "data",
        /* data格式:{
            orginTileSize:500,//瓦片图原始尺寸
            colCount: 20,//行数
            rowCount: 20,//列数
            scaleValue: 100,//缩放百分比
            tiles: [],//瓦片图数组
        } */
    ],
    watch: {
        data: {
            handler(newValue, oldValue) {
                if (newValue && Object.keys(newValue).length) {
                    newValue.orginTileSize && (this.orginTileSize = newValue.orginTileSize);
                    newValue.colCount && (this.colCount = newValue.colCount);
                    newValue.rowCount && (this.rowCount = newValue.rowCount);
                    newValue.scaleValue && (this.scaleValue = newValue.scaleValue);
                    newValue.tiles && (this.tiles = newValue.tiles);
                    this.$nextTick(() => { this.loadScreenViewTiles(); });
                }
            },
            deep: true,//深度监听
            immediate: true,//立即执行
        },
        scaleValue: {
            handler(newValue, oldValue) {
                this.tileSize = this.orginTileSize * 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) {
            // 记录缩放前的数据
            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;
         }
     }
     .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 .382s;
                 &[loaded] {
                     opacity: 1;
                 }
             }
         }
     }
 }
</style>

用例

<template>
  <div>
    <sgTileImage :data="tileImageData" />
  </div>
</template>
<script>
import sgTileImage from "@/vue/components/admin/sgTileImage";
export default {
  components: { sgTileImage },
  data() {
    return {
      tileImageData: {
        orginTileSize: 500,//瓦片图原始尺寸
        colCount: 20,//行数
        rowCount: 20,//列数
        tiles: [],//瓦片图数组
      }
    }
  },
  created() {
    this.tileImageData.tiles = [...Array(this.tileImageData.colCount * this.tileImageData.rowCount)].map((v, i) => ({
      loaded: false,
      img: `http://shuzhiqiang.com/tiles/${i}.jpg`,
    }));//瓦片图数组
  },
};
</script>

依赖组件

image.png


相关文章
|
6月前
|
小程序
小程序右上角的胶囊颜色怎么修改?
小程序右上角的胶囊颜色怎么修改?
70 0
|
10月前
|
定位技术
百度地图:监听地图缩放自动显示和隐藏的富文本标签
百度地图:监听地图缩放自动显示和隐藏的富文本标签
130 0
|
8月前
|
索引 容器
Bootstrap4----网络系统、图像形状、轮播、滚动监听、多媒体对象、下拉菜单导航及按钮
Bootstrap4----网络系统、图像形状、轮播、滚动监听、多媒体对象、下拉菜单导航及按钮
|
22天前
|
索引
【sgPhotoPlayer】自定义组件:图片预览,支持点击放大、缩小、旋转图片
【sgPhotoPlayer】自定义组件:图片预览,支持点击放大、缩小、旋转图片
|
5月前
【sgDragMove】自定义组件:自定义拖拽组件,仅支持拖拽、设置吸附屏幕边界距离。
【sgDragMove】自定义组件:自定义拖拽组件,仅支持拖拽、设置吸附屏幕边界距离。
|
5月前
|
测试技术 定位技术
【sgDragMoveTile】自定义组件:拖拽瓦片图、地图、大图,滚动条对应同步滚动
【sgDragMoveTile】自定义组件:拖拽瓦片图、地图、大图,滚动条对应同步滚动
|
5月前
【sgOvalMenu】自定义组件:椭圆形菜单,菜单按钮可以随着椭圆轨迹进行循环运动
【sgOvalMenu】自定义组件:椭圆形菜单,菜单按钮可以随着椭圆轨迹进行循环运动
|
8月前
|
图形学
|
10月前
|
定位技术
echarts. registerMap选项specialAreas将地图中的部分区域缩放到合适的位置,可以使得整个地图的显示更加好看
echarts. registerMap选项specialAreas将地图中的部分区域缩放到合适的位置,可以使得整个地图的显示更加好看
70 0
|
11月前
图片和文件预览组件(部分源码),可拖动,缩小,放大。 #41
图片和文件预览组件(部分源码),可拖动,缩小,放大。 #41
90 0

热门文章

最新文章