UNPKG

wangbd-myui

Version:

MY前端基础框架核心组件库

195 lines (190 loc) 5.43 kB
/** * 散点图 * @module $ui/map/my-map-scatter */ import Point from 'ol/geom/Point' import {easeOut} from 'ol/easing' import featureMixin from '../../mixins/feature' import parseStyle from '../../utils/style' // 涟漪动画默认配置 const defaultRippleEffect = { color: null, // 默认与 fill 参数一致 period: 1.5, // 动画周期,秒数 scale: 5, // 动画中波纹的最大缩放比 strokeColor: null, strokeWidth: 2, // 边框宽度 type: 'fill' // 渲染类型 fill 或 stroke } export default { name: 'MyMapScatter', mixins: [featureMixin], /** * 属性参数, 继承 [$ui/map/mixins/feature]{@link module:$ui/map/mixins/feature} * @member props * @property {number[]} [coordinate] 经纬度 * @property {number} [radius=10] 散点半径 * @property {boolean} [effect=true] 开启动画效果 * @property {string} [fill] 散点颜色 * @property {object} [stroke] 描边 * @property {number} [delay] 动画延时开始,毫秒 * @property {boolean} [loop] 是否循环 * @property {object} [ripple] 涟漪动画配置 * @property {string} [ripple.color] 颜色,默认取fill * @property {number} [ripple.period=1.5] 动画周期,秒数 * @property {number} [ripple.scale=5] 动画中波纹的最大缩放比 * @property {string} [ripple.strokeColor] 描边颜色,默认取fill * @property {number} [ripple.strokeWidth=2] 边框宽度 * @property {string} [ripple.type=fill] 动画渲染类型,支持 fill 或 stroke * */ props: { // 坐标 coordinate: Array, // 散点半径 radius: { type: Number, default: 10 }, // 开启效果动画 effect: { type: Boolean, default: true }, // 重置填充颜色默认值 fill: { type: String, default: '#409eff' }, stroke: { type: Object }, // 涟漪动画效果配置 ripple: { type: Object, default() { return defaultRippleEffect } }, // 动画延时开始 delay: { type: Number, default: 0 }, // 动画循环 loop: { type: Boolean, default: true } }, computed: { rippleOptions() { const color = this.ripple.color || this.fill const strokeColor = this.ripple.strokeColor || this.fill return { ...defaultRippleEffect, ...this.ripple, color, strokeColor } } }, methods: { drawHandler() { return new Point(this.coordinate) }, modifyHandler(geometry) { geometry.setCoordinates(this.coordinate) }, delayStart(func) { if (this.delay) { clearTimeout(this.delayId) this.delayId = setTimeout(func, this.delay) } else { func() } }, setStyle() { if (!this.feature) return const center = parseStyle({ zIndex: this.zIndex, circle: { fill: this.fill, radius: this.radius, stroke: this.stroke }, text: this.styleText }) let styles = [center] if (this.effect) { const ripple = this.getRipple(this.rippleOptions) const stroke = this.getRippleStroke(this.rippleOptions) styles = [stroke, ripple].concat(styles) this.delayStart(() => { this.rippleEffect(styles, this.rippleOptions) }) } this.feature.setStyle(styles) }, getRipple({color}, opts = {}) { return parseStyle({ zIndex: this.zIndex, circle: { fill: color, radius: this.radius, ...opts } }) }, getRippleStroke({strokeColor, strokeWidth}, opts = {}) { return parseStyle({ zIndex: this.zIndex, circle: { fill: 'transparent', radius: this.radius, stroke: { color: strokeColor, width: strokeWidth }, ...opts } }) }, rippleEffect(styles, rippleOptions) { const {scale, period, type} = rippleOptions let [stroke, ripple, center] = styles // const image = type === 'fill' // ? ripple.getImage() // : stroke.getImage() const start = new Date().getTime() // eslint-disable-next-line no-unused-vars const animate = () => { const tick = new Date().getTime() const ratio = (tick - start) / (period * 1000) if (ratio > 1) { this.loop && this.rippleEffect(styles, rippleOptions) return } const val = easeOut(ratio) const radius = this.radius * scale * val const opacity = 1 - val if (type === 'fill') { ripple = this.getRipple(this.rippleOptions, { radius }) ripple.getImage().setOpacity(opacity) } else { stroke = this.getRippleStroke(this.rippleOptions, { radius }) stroke.getImage().setOpacity(opacity) } this.feature.setStyle([stroke, ripple, center]) this.aId = window.requestAnimationFrame(animate) } animate() } }, beforeDestroy() { this.aId && window.cancelAnimationFrame(this.aId) } }