UNPKG

vue-photo-zoom-pro

Version:
816 lines (776 loc) 19.8 kB
import { openBlock, createElementBlock, normalizeStyle, createElementVNode, renderSlot, createCommentVNode, normalizeClass, mergeProps, resolveComponent, withDirectives, createBlock, vShow, withCtx } from 'vue'; var script$7 = { name: 'VuePhotoZoomProMask', props: { width: { type: Number, default: 0 }, height: { type: Number, default: 0 }, selector: { type: Object, default: () => ({ left: 0, top: 0, width: 0, height: 0 }) }, maskColor: { type: String, default: '' } }, computed: { topStyle () { const { selector } = this; return { width: `${this.width}px`, height: `${selector.top}px` } }, leftStyle () { const { selector } = this; return { width: `${selector.left}px`, height: `${selector.height}px` } }, rightStyle () { const { selector } = this; return { width: `${this.width - selector.left - selector.width}px`, height: `${selector.height}px` } }, bottomStyle () { const { selector } = this; return { width: `${this.width}px`, height: `${this.height - selector.top - selector.height}px` } }, maskStyle () { return { backgroundColor: this.maskColor } } } }; function render$7(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("div", { class: "mask", style: normalizeStyle($options.maskStyle) }, [ createElementVNode("div", { class: "block top", style: normalizeStyle($options.topStyle) }, null, 4), createElementVNode("div", { class: "block left", style: normalizeStyle($options.leftStyle) }, null, 4), createElementVNode("div", { class: "block right", style: normalizeStyle($options.rightStyle) }, null, 4), createElementVNode("div", { class: "block bottom", style: normalizeStyle($options.bottomStyle) }, null, 4) ], 4)) } script$7.render = render$7; script$7.__scopeId = "data-v-15e50313"; var script$6 = { name: 'VuePhotoZoomProZoomer', props: { left: { type: Number, default: 0 }, top: { type: Number, default: 0 }, scale: { type: Number, default: 2 }, zoomRegion: { type: Object, default: () => ({ width: 0, height: 0 }) }, width: { type: Number, default: 0 }, height: { type: Number, default: 0 } }, computed: { zoomerStyle () { return { width: `${this.width}px`, height: `${this.height}px` } }, positionStyle () { return { transform: `translate3d(${-this.left}px, ${-this.top}px, 0)` } }, zoomedStyle () { const { zoomRegion } = this; return { transform: `scale(${this.scale}) translateZ(0)`, width: `${zoomRegion.width}px`, height: `${zoomRegion.height}px` } } } }; function render$6(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("div", { class: "zoomer", style: normalizeStyle($options.zoomerStyle) }, [ createElementVNode("div", { class: "position", style: normalizeStyle($options.positionStyle) }, [ (_ctx.$slots.default) ? (openBlock(), createElementBlock("div", { key: 0, class: "custom-zoomer", style: normalizeStyle($options.zoomedStyle) }, [ renderSlot(_ctx.$slots, "default") ], 4)) : createCommentVNode("", true) ], 4) ], 4)) } script$6.render = render$6; script$6.__scopeId = "data-v-1bae271a"; var script$5 = { name: 'VuePhotoZommProSelector', props: { left: { type: Number, default: 0 }, top: { type: Number, default: 0 }, width: { type: Number, default: 0 }, height: { type: Number, default: 0 }, type: { type: String, default: 'square' } }, computed: { selectorStyle () { return { width: `${this.width}px`, height: `${this.height}px`, transform: `translate3d(${this.left}px, ${this.top}px, 0)` } } } }; function render$5(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("div", { class: normalizeClass(['selector', $props.type]), style: normalizeStyle($options.selectorStyle) }, [ renderSlot(_ctx.$slots, "default") ], 6)) } script$5.render = render$5; script$5.__scopeId = "data-v-3c631a3a"; var script$4 = { name: 'ImgPreview', props: { url: { type: String, default: '' } } }; const _hoisted_1$1 = ["src"]; function render$4(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("img", mergeProps({ class: "img-preview", style: {"display":"block","width":"100%"}, src: $props.url }, _ctx.$attrs), null, 16, _hoisted_1$1)) } script$4.render = render$4; var script$3 = { name: 'ImgZoomer', props: { url: { type: String, default: '' } } }; const _hoisted_1 = ["src"]; function render$3(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("img", mergeProps({ class: "img-zoomer", style: {"display":"block","width":"100%","height":"100%"}, src: $props.url }, _ctx.$attrs), null, 16, _hoisted_1)) } script$3.render = render$3; const getBoundingClientRect = (element) => { const rect = element.getBoundingClientRect(); // whether the IE version is lower than 11 const isIE = navigator.userAgent.indexOf('MSIE') !== -1; // fix ie document bounding top always 0 bug const rectTop = isIE && element.tagName === 'HTML' ? -element.scrollTop : rect.top; return { left: rect.left, top: rectTop, right: rect.right, bottom: rect.bottom, width: rect.right - rect.left, height: rect.bottom - rectTop } }; function clamp (num, min, max) { const MIN = min; const MAX = max; return Math.min(Math.max(num, MIN), MAX) } const getBoundValue = (value, bound) => { return { x: clamp(value.x, bound.left, bound.right), y: clamp(value.y, bound.top, bound.bottom) } }; const generateBound = (width, height, boundWidth, boundHeight) => { return { left: boundWidth, top: boundHeight, right: width - boundWidth, bottom: height - boundHeight } }; const getScrollInfo = () => { const { documentElement, body } = document; const scrollTop = documentElement.scrollTop || window.pageYOffset || body.scrollTop; const scrollLeft = documentElement.scrollLeft || window.pageXOffset || body.scrollLeft; return { scrollTop, scrollLeft } }; /** * load img * @param {String} img url * @return {Promise} */ const loadImg = (url, callback) => { const img = document.createElement('img'); img.addEventListener('load', () => callback(null, img)); img.addEventListener('error', callback); img.src = url; }; function rotateCanvas (canvas, img, width, height, step) { const ctx = canvas.getContext('2d'); const degree = (step * 90 * Math.PI) / 180; const { width: imgWidth, height: imgHeight } = img; switch (step) { case 0: canvas.width = imgWidth; canvas.height = imgHeight; ctx.drawImage(img, 0, 0, imgWidth, imgHeight); canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; break case 1: canvas.width = imgHeight; canvas.height = imgWidth; ctx.rotate(degree); ctx.drawImage(img, 0, -imgHeight, imgWidth, imgHeight); canvas.style.width = height + 'px'; canvas.style.height = width + 'px'; break case 2: canvas.width = imgWidth; canvas.height = imgHeight; ctx.rotate(degree); ctx.drawImage(img, 0, 0, -imgWidth, -imgHeight); canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; break case 3: canvas.width = imgHeight; canvas.height = imgWidth; ctx.rotate(degree); ctx.drawImage(img, -imgWidth, 0, imgWidth, imgHeight); canvas.style.width = height + 'px'; canvas.style.height = width + 'px'; break } } var script$2 = { name: 'CanvasPreview', props: { url: { type: String, default: '' }, rotate: { type: Number, default: 0 }, width: { type: Number, default: 0 }, height: { type: Number, default: 0 } }, computed: { step () { return parseInt((this.rotate % 360) / 90, 10) } }, watch: { step (newValue) { this.handleRotate(newValue); }, url: { handler (url) { loadImg(url, (err, img) => { if (err) return console.error(err) this.$img = img; this.handleRotate(this.step); }); }, immediate: true } }, mounted () { this.$canvas = this.$refs.canvas; }, methods: { handleRotate (step) { rotateCanvas( this.$canvas, this.$img, this.width || this.$img.width, this.height || this.$img.height, step ); } } }; function render$2(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("canvas", mergeProps({ ref: "canvas", class: "canvas-preview" }, _ctx.$attrs), null, 16)) } script$2.render = render$2; var script$1 = { name: 'CanvasZoomer', props: { url: { type: String, default: '' }, rotate: { type: Number, default: 0 }, width: { type: Number, default: 0 }, height: { type: Number, default: 0 } }, computed: { step () { return parseInt((this.rotate % 360) / 90, 10) } }, watch: { step (newValue) { this.handleRotate(newValue); }, url: { handler (url) { loadImg(url, (err, img) => { if (err) return console.error(err) this.$img = img; this.handleRotate(this.step); }); }, immediate: true } }, mounted () { this.$canvas = this.$refs.canvas; }, methods: { handleRotate (step) { rotateCanvas( this.$canvas, this.$img, this.width || this.$img.width, this.height || this.$img.height, step ); } } }; function render$1(_ctx, _cache, $props, $setup, $data, $options) { return (openBlock(), createElementBlock("canvas", mergeProps({ ref: "canvas", class: "canvas-zoomer" }, _ctx.$attrs), null, 16)) } script$1.render = render$1; var script = { name: 'VuePhotoZoomPro', components: { PhotoMask: script$7, Selector: script$5, Zoomer: script$6, ImgPreview: script$4, ImgZoomer: script$3 }, props: { width: { type: Number, default: 168 }, height: { type: Number, default: -1 }, url: { type: String, default: '' }, highUrl: { type: String, default: '' }, type: { type: String, default: 'square', validator: function (value) { return ['circle', 'square'].indexOf(value) !== -1 } }, scale: { type: Number, default: 2 }, selector: { type: [Boolean, Object], default: true }, outZoomer: { type: [Boolean, Object], default: false }, disabledReactive: { type: Boolean, default: false }, disabledEvent: { type: Boolean, default: false }, mask: { type: Boolean, default: false }, maskColor: { type: String, default: '' } }, data () { return { mouseEnterFlag: false, outZoomerTop: 0, mouse: { x: 0, y: 0 }, zoomRegionRect: { left: 0, top: 0, width: 0, height: 0 } } }, computed: { selectorOptions () { return typeof this.selector === 'object' ? this.selector : { release: false } }, outZoomerOptions () { return typeof this.outZoomer === 'object' ? this.outZoomer : { sticky: false } }, selectorWidth () { return this.width }, selectorHeight () { return this.height > -1 ? this.height : this.width }, selectorHalfWidth () { return this.selectorWidth / 2 }, selectorHalfHeight () { return this.selectorHeight / 2 }, zoomerWidth () { return this.outZoomer ? this.selectorWidth * this.scale : this.selectorWidth }, zoomerHeight () { return this.outZoomer ? this.selectorHeight * this.scale : this.selectorHeight }, zoomerHalfWidth () { return this.zoomerWidth / 2 }, zoomerHalfHeight () { return this.zoomerHeight / 2 }, zoomRegionAbsolute () { const { zoomRegionRect } = this; const { scrollTop, scrollLeft } = getScrollInfo(); return { left: zoomRegionRect.left + scrollLeft, top: zoomRegionRect.top + scrollTop } }, pointBound () { const { zoomRegionRect } = this; return generateBound( zoomRegionRect.width, zoomRegionRect.height, this.selectorHalfWidth, this.selectorHalfHeight ) }, vPointBound () { const { zoomRegionRect, scale } = this; return generateBound( zoomRegionRect.width * scale, zoomRegionRect.height * scale, this.zoomerHalfWidth, this.zoomerHalfHeight ) }, point () { const { mouse, selectorOptions } = this; return !selectorOptions.release ? getBoundValue(mouse, this.pointBound) : mouse }, vPoint () { const { mouse, scale, selectorOptions } = this; const scaleMouse = { x: mouse.x * scale, y: mouse.y * scale }; return !selectorOptions.release ? getBoundValue(scaleMouse, this.vPointBound) : scaleMouse }, selectorProps () { const { point } = this; return { width: this.selectorWidth, height: this.selectorHeight, left: point.x - this.selectorHalfWidth, top: point.y - this.selectorHalfHeight } }, zoomerProps () { const { vPoint } = this; return { scale: this.scale, zoomRegion: this.zoomRegionRect, width: this.zoomerWidth, height: this.zoomerHeight, left: vPoint.x - this.zoomerHalfWidth, top: vPoint.y - this.zoomerHalfHeight } }, outZoomerPosition () { return { top: `${this.outZoomerTop}px` } } }, watch: { scale () { this.handleMouseMove(this.pointerInfo); }, zoomRegionRect: { handler () { this.$emit('update', this.zoomRegionRect); }, deep: true } }, mounted () { this.$zoomRegion = this.$refs.zoomRegion; this.update(); this.$emit('created'); }, methods: { handleMouseEnter () { this.mouseEnter(); }, handleMouseMove (e) { e = this.pointerInfo = e || this.pointerInfo; if (e) { const { pageX, pageY } = e; const { zoomRegionAbsolute } = this; this.mouseMove( pageX - zoomRegionAbsolute.left, pageY - zoomRegionAbsolute.top ); if (this.outZoomer && this.outZoomerOptions.sticky) { this.outZoomerTop = Math.max(pageY - e.clientY, 0); } } }, handleMouseLeave () { this.mouseLeave(); }, mouseEnter () { !this.disabledReactive && this.update(); this.mouseEnterFlag = true; }, mouseMove (x, y) { !this.disabledReactive && this.update(); const { mouse } = this; mouse.x = x; mouse.y = y; }, mouseLeave () { this.mouseEnterFlag = false; }, update () { Object.assign( this.zoomRegionRect, getBoundingClientRect(this.$zoomRegion) ); } } }; function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_PhotoMask = resolveComponent("PhotoMask"); const _component_ImgZoomer = resolveComponent("ImgZoomer"); const _component_Zoomer = resolveComponent("Zoomer"); const _component_Selector = resolveComponent("Selector"); const _component_ImgPreview = resolveComponent("ImgPreview"); return (openBlock(), createElementBlock("div", { ref: "zoomRegion", class: "vue-photo-zoom-pro", onMouseenter: _cache[0] || (_cache[0] = $event => (!$props.disabledEvent && $options.handleMouseEnter($event))), onMousemove: _cache[1] || (_cache[1] = $event => (!$props.disabledEvent && $options.handleMouseMove($event))), onMouseleave: _cache[2] || (_cache[2] = $event => (!$props.disabledEvent && $options.handleMouseLeave($event))) }, [ ($props.mask) ? withDirectives((openBlock(), createBlock(_component_PhotoMask, { key: 0, width: $data.zoomRegionRect.width, height: $data.zoomRegionRect.height, "mask-color": $props.maskColor, selector: $options.selectorProps }, null, 8, ["width", "height", "mask-color", "selector"])), [ [vShow, $data.mouseEnterFlag] ]) : createCommentVNode("", true), ($props.selector) ? withDirectives((openBlock(), createBlock(_component_Selector, mergeProps({ key: 1 }, $options.selectorProps, { type: $props.type }), { default: withCtx(() => [ (!$props.outZoomer) ? (openBlock(), createBlock(_component_Zoomer, mergeProps({ key: 0, class: "inner-zoomer" }, $options.zoomerProps), { default: withCtx(() => [ ($props.highUrl || $props.url) ? (openBlock(), createBlock(_component_ImgZoomer, { key: 0, url: $props.highUrl || $props.url }, null, 8, ["url"])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "zoomer") ]), _: 3 }, 16)) : createCommentVNode("", true), renderSlot(_ctx.$slots, "selector") ]), _: 3 }, 16, ["type"])), [ [vShow, $data.mouseEnterFlag] ]) : createCommentVNode("", true), ($props.outZoomer) ? withDirectives((openBlock(), createBlock(_component_Zoomer, mergeProps({ key: 2, class: "out-zoomer" }, $options.zoomerProps, { style: $options.outZoomerPosition }), { default: withCtx(() => [ ($props.highUrl || $props.url) ? (openBlock(), createBlock(_component_ImgZoomer, { key: 0, url: $props.highUrl || $props.url }, null, 8, ["url"])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "zoomer") ]), _: 3 }, 16, ["style"])), [ [vShow, $data.mouseEnterFlag] ]) : createCommentVNode("", true), ($props.url) ? (openBlock(), createBlock(_component_ImgPreview, { key: 3, url: $props.url }, null, 8, ["url"])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "default") ], 544)) } script.render = render; script.__scopeId = "data-v-61213061"; export { script$2 as CanvasPreview, script$1 as CanvasZoomer, script$4 as ImgPreview, script$3 as ImgZoomer, script as default };