UNPKG

@idmwx/idmui-gl3

Version:

idm webgl3

1,101 lines (1,086 loc) 466 kB
var mt = Object.defineProperty; var ut = (a, e, t) => e in a ? mt(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t; var se = (a, e, t) => (ut(a, typeof e != "symbol" ? e + "" : e, t), t); import { LayerHelper as $e, CompanyHelper as Ve } from "@idm-plugin/tag"; import ie from "moment"; import Ne from "axios"; import { resolveComponent as R, openBlock as u, createElementBlock as g, createElementVNode as o, normalizeStyle as de, createVNode as O, withCtx as Me, normalizeClass as te, Fragment as ee, renderList as ae, toDisplayString as k, createCommentVNode as q, createBlock as gt, createTextVNode as fe, withDirectives as Oe, createStaticVNode as yt, vShow as Fe, defineComponent as ft, withModifiers as Ze, mergeProps as K } from "vue"; import * as H from "@turf/turf"; import At from "@mapbox/sphericalmercator"; import Re from "mapbox-gl"; import { TropicalHelper as ct, LngLatHelper as ce, LaneHelper as We } from "@idm-plugin/geo"; import { TidesAssist as et, Meteo2Assist as Ke } from "@idm-plugin/meteo"; import Xe from "moment-timezone"; const Y = (a, e) => { const t = a.__vccOpts || a; for (const [r, i] of e) t[r] = i; return t; }, wt = { name: "IdmGlLayer", props: { map: { type: Object }, mapProjection: { type: String }, gateway: { type: String }, token: { type: String }, top: { type: Number, default: 60 }, layerToggle: { type: Boolean, default: !1 }, toggleVersion: { type: Number }, isLogin: { type: Boolean, default: void 0 }, showWindFeather: { type: Boolean, default: void 0 }, showWindParticle: { type: Boolean, default: void 0 }, showCurrentIsoband: { type: Boolean, default: void 0 }, showCurrentParticle: { type: Boolean, default: void 0 }, forecastModel: { type: String } }, emits: ["weather", "other", "toggleWindParticle", "toggleWindFeather", "toggleCurrentParticle", "toggleCurrentIsoband", "toggleWindParticeVersion", "toggleCurrentParticeVersion", "coordinate", "measure", "point", "3d", "layerToggle", "handleToggleVersion", "login", "forecastModel"], data() { return { autoActive: !0, layers: { weather: [ ...$e.WEATHER_LAYERS.filter((a) => a.enabled && !["swell-height", "swell-direction", "current-direction", "current-speed"].includes(a.key)) ], other: [...$e.OTHER_LAYERS.filter((a) => a.enabled)] }, activeWeatherLayers: [], activeWeatherLayersCollected: [], activeOtherLayers: [], autoActiveCache: "autoActiveCache", activeWeatherLayersCache: "activeWeatherLayersCache", activeOtherLayersCache: "activeOtherLayersCache", collectedLayerCache: "collectedLayerCache", sourceCache: "defaultSourceCache", windFeatherCollectedCache: "windFeatherCollectedCache", currentIsobandCollectedCache: "currentIsobandCollectedCache", showCoord: !1, showMeasure: !1, showPoint: !1, show3d: !1, version: { v: "0.1.1", k: "glCacheVersion" }, source: "Best Match", sourceList: [], right: 10, rampColorLayers: ["visibility", "precip3h", "temp", "water-temp", "ice-thickness", "ice-cover"], showWindParticleCollected: !1, showWindFeatherCollected: !0, showCurrentParticleCollected: !1, showCurrentIsobandCollected: !1 }; }, computed: { computeLayerClass() { return function(a, e) { var r; let t = "layer flex-between"; return e.some((i) => i.key === a.key) && (t = t + " active"), (!a.enabled || (r = this.layers.weather) != null && r.some((i) => i.key === a.key) && !this.autoActive || this.rampColorLayers.includes(a.key) && this.mapProjection === "globe") && (t = t + " disabled"), t; }; }, hasCollectedLayers() { var a; return ((a = this.layers.weather.filter((e) => e.collected)) == null ? void 0 : a.length) > 0; }, computeDateZ() { return function(a) { var e; if (a) { const t = ie(a); return `${(e = t == null ? void 0 : t.utc()) == null ? void 0 : e.format("MMM-DD/HHmm")}Z`; } return "-"; }; }, sourceCode() { var a; return (a = this.sourceList.find((e) => e.name === this.source)) == null ? void 0 : a.code; } }, watch: { toggleVersion: { handler() { this.$nextTick(() => { var a; this.right = (((a = document.getElementsByClassName("right-bar")[0]) == null ? void 0 : a.clientWidth) || 0) + 10; }); } }, source: { handler(a, e) { a && a !== e && this.$emit("forecastModel", this.source), a && e && a !== e && this.handleConfirm(); } }, activeWeatherLayers: { handler(a, e) { this.autoActive && (this.activeWeatherLayersCollected = this.activeWeatherLayers, localStorage.setItem(this.activeWeatherLayersCache, JSON.stringify(this.activeWeatherLayers))); } }, showWindParticle: { handler(a, e) { this.autoActive && (this.showWindParticleCollected = this.showWindParticle); } }, showWindFeather: { handler(a, e) { this.autoActive && (this.showWindFeatherCollected = this.showWindFeather, localStorage.setItem(this.windFeatherCollectedCache, this.showWindFeatherCollected)); } }, showCurrentParticle: { handler(a, e) { this.autoActive && (this.showCurrentParticleCollected = this.showCurrentParticle); } }, showCurrentIsoband: { handler(a, e) { this.autoActive && (this.showCurrentIsobandCollected = this.showCurrentIsoband, localStorage.setItem(this.currentIsobandCollectedCache, this.showCurrentIsobandCollected)); } } }, async mounted() { await this.fetchMeteoSource(), this.fetchCache(), this.handleConfirm(); }, methods: { async fetchMeteoSource() { var e; this.sourceList = []; let a = await Ne.get(`${this.gateway}/api/arc/meteo2/models`, { headers: { Authorization: this.token } }); (a == null ? void 0 : a.data.code) === 0 && (this.sourceList = (e = a == null ? void 0 : a.data.data) == null ? void 0 : e.weather); }, fetchCache() { const a = localStorage.getItem(this.version.k); this.version.v !== a && (localStorage.removeItem(this.autoActiveCache), localStorage.removeItem(this.activeWeatherLayersCache), localStorage.removeItem(this.activeOtherLayersCache), localStorage.removeItem(this.windFeatherCollectedCache), localStorage.removeItem(this.currentIsobandCollectedCache), localStorage.setItem(this.version.k, this.version.v)); let e = localStorage.getItem(this.autoActiveCache); this.autoActive = e !== "false", e = localStorage.getItem(this.collectedLayerCache); let t = JSON.parse( e || '[{"weight": 16, "name": "Sig Waves", "key": "sig-wave-height", "collected": true},{"weight": 1, "name": "Wind", "key": "wind", "h5": true, "collected": true},{"weight": 96, "name": "Current", "key": "current", "collected": true},{"weight": 256,"name": "Tropicals","key": "tropicals", "collected": true}]' ); this.layers.weather.forEach((r) => { r.collected = !!t.some((i) => i.key === r.key && i.collected); }), e = localStorage.getItem(this.activeWeatherLayersCache), e || localStorage.setItem(this.activeWeatherLayersCache, JSON.stringify( [ { weight: 1, name: "Wind", key: "wind", enabled: !0, type: "json", particle: !1 }, { weight: 16, name: "Sig Waves", key: "sig-wave-height", enabled: !0, type: "json" }, { weight: 256, name: "Tropicals", key: "tropicals", enabled: !0, type: "json" } ] )), e = localStorage.getItem(this.activeWeatherLayersCache), t = JSON.parse(e), this.autoActive ? this.activeWeatherLayers = [...t] : this.activeWeatherLayersCollected = [...t], t.some((r) => r.key === "wind" && r.particle) && (this.$emit("toggleWindParticle", !0), this.showWindParticleCollected = !0), t.some((r) => r.key === "current" && r.particle) && (this.$emit("toggleCurrentParticle", !0), this.showCurrentParticleCollected = !0), this.showWindFeatherCollected = JSON.parse(localStorage.getItem(this.windFeatherCollectedCache)) ? JSON.parse(localStorage.getItem(this.windFeatherCollectedCache)) : this.showWindFeatherCollected, this.showCurrentIsobandCollected = JSON.parse(localStorage.getItem(this.currentIsobandCollectedCache)) ? JSON.parse(localStorage.getItem(this.currentIsobandCollectedCache)) : this.showCurrentIsobandCollected, this.autoActive && (this.$emit("toggleWindFeather", this.showWindFeatherCollected), this.$emit("toggleCurrentIsoband", this.showCurrentIsobandCollected)), t.some((r) => r.key === "wind" && !r.particle && !this.showWindFeatherCollected) && (t = t.filter((r) => r.key !== "wind")), t.some((r) => r.key === "current" && !r.particle && !this.showCurrentIsobandCollected) && (t = t.filter((r) => r.key !== "current")), e = localStorage.getItem(this.activeOtherLayersCache), t = JSON.parse(e || '[{"weight":4,"name":"ECA Zones","key":"eca-zones","enabled":true,"type":"json"}, {"weight": 2048,"name": "ENC","key": "enc","h5": true,"enabled": true,"type": "origin"}]'), this.activeOtherLayers = t, e = localStorage.getItem(this.sourceCache), this.source = this.forecastModel ? this.forecastModel : e ? e === "CMEMS" ? "ECMWF" : e : this.source, this.$emit("forecastModel", this.source); }, handleConfirm() { this.autoActive && this.$emit("weather", JSON.parse(localStorage.getItem(this.activeWeatherLayersCache)), this.sourceCode), this.$emit("other", this.activeOtherLayers), localStorage.setItem(this.autoActiveCache, this.autoActive), localStorage.setItem(this.sourceCache, this.source); }, handleWeatherLayerPick(a) { if (this.activeWeatherLayers = JSON.parse(localStorage.getItem(this.activeWeatherLayersCache)), this.rampColorLayers.includes(a.key) && this.mapProjection === "globe" || !this.autoActive) return !1; (a.key === "wind" && !this.showWindFeather || a.key === "current" && !this.showCurrentIsoband) && (a.particle = !0), this.activeWeatherLayers.some((e) => e.key === a.key) ? this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.key !== a.key) : this.activeWeatherLayers.length < 6 && a.enabled && (["png", "jpg"].includes(a.type) ? (this.activeWeatherLayers.forEach((e) => { (e.key === "wind" && this.showWindFeather || a.key === "current" && this.showCurrentIsoband) && (e.particle = !1); }), this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.type === "json" && !(["wind", "current"].includes(e.key) && e.particle))) : a.key === "wind" ? (this.activeWeatherLayers.forEach((e) => { e.key === "current" && this.showCurrentIsoband && (e.particle = !1); }), this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.type === "json" && !(["wind", "current"].includes(e.key) && e.particle))) : a.key === "current" && (this.activeWeatherLayers.forEach((e) => { e.key === "wind" && this.showWindFeather && (e.particle = !1); }), this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.type === "json" && !(["wind", "current"].includes(e.key) && e.particle))), a.key === "sig-wave-height" && (this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.key !== "sig-wave")), a.key === "sig-wave" && (this.activeWeatherLayers = this.activeWeatherLayers.filter((e) => e.key !== "sig-wave-height")), this.activeWeatherLayers.push(a)), this.$emit("weather", this.activeWeatherLayers, this.sourceCode); }, handleWeatherLayerCollect(a) { var e; if (!this.autoActive) return !1; !a.collected && ((e = this.layers.weather.filter((t) => t.collected)) == null ? void 0 : e.length) >= 6 && (this.layers.weather.filter((t) => t.collected)[0].collected = !1), a.collected = !a.collected, localStorage.setItem(this.collectedLayerCache, JSON.stringify(this.layers.weather)), this.$emit("handleToggleVersion"); }, handleToggleWindParticle() { !this.showWindFeather && this.showWindParticle ? this.handleWeatherLayerPick({ weight: 1, name: "Wind", key: "wind", enabled: !0, type: "json", particle: !1 }) : (this.showCurrentParticle && (this.$emit("toggleCurrentParticle", !1), this.showCurrentIsoband || (this.activeWeatherLayers = this.activeWeatherLayers.filter((a) => a.key !== "current"))), this.$emit("toggleWindParticle", !this.showWindParticle), this.$emit("toggleWindParticeVersion")); }, handleToggleWindFeather() { this.showWindFeather && !this.showWindParticle && this.handleWeatherLayerPick({ weight: 1, name: "Wind", key: "wind", enabled: !0, type: "json", particle: !1 }), this.$emit("toggleWindFeather", !this.showWindFeather); }, handleToggleCurrentParticle() { !this.showCurrentIsoband && this.showCurrentParticle ? this.handleWeatherLayerPick({ weight: 96, name: "Current", key: "current", enabled: !0, type: "json", particle: !1 }) : (this.showWindParticle && (this.$emit("toggleWindParticle", !1), this.showWindFeather || (this.activeWeatherLayers = this.activeWeatherLayers.filter((a) => a.key !== "wind"))), this.$emit("toggleCurrentParticle", !this.showCurrentParticle), this.$emit("toggleCurrentParticeVersion")); }, handleToggleCurrentIsoband() { this.showCurrentIsoband && !this.showCurrentParticle && this.handleWeatherLayerPick({ weight: 96, name: "Current", key: "current", enabled: !0, type: "json", particle: !1 }), this.$emit("toggleCurrentIsoband", !this.showCurrentIsoband); }, handleOtherLayerPick(a) { this.activeOtherLayers.some((e) => e.key === a.key) ? this.activeOtherLayers = this.activeOtherLayers.filter((e) => e.key !== a.key) : a.enabled && this.activeOtherLayers.push(a), localStorage.setItem(this.activeOtherLayersCache, JSON.stringify(this.activeOtherLayers)), this.$emit("other", this.activeOtherLayers); }, handleMenuToggle() { this.$emit("layerToggle", !this.layerToggle); }, toggleAutoActive() { this.autoActive = !this.autoActive, localStorage.setItem(this.autoActiveCache, this.autoActive), this.autoActive ? (this.$emit("weather", this.activeWeatherLayersCollected, this.sourceCode), this.$emit("toggleWindFeather", localStorage.getItem(this.windFeatherCollectedCache) === "true"), this.$emit("toggleCurrentIsoband", localStorage.getItem(this.currentIsobandCollectedCache) === "true")) : (this.$emit("weather", [], this.sourceCode), this.$emit("toggleWindFeather", !1), this.$emit("toggleCurrentIsoband", !1)); }, handleCoordToggle() { this.showCoord = !this.showCoord, this.$emit("coordinate", this.showCoord); }, handlePointToggle() { this.isLogin ? (this.showPoint = !this.showPoint, this.$emit("point", this.showPoint)) : this.$emit("login"); }, handleMeasureToggle() { this.showMeasure = !this.showMeasure, this.$emit("measure", this.showMeasure); }, handle3DToggle() { this.show3d = !this.show3d, this.$emit("3d", this.show3d); } } }, vt = { class: "idm-gl3-layer" }, bt = { class: "bar-item layer-bars" }, Lt = { class: "bar-item tool-bars" }, Ct = { class: "flex-between" }, xt = { key: 0, class: "iconfont active" }, _t = { key: 1, class: "iconfont" }, Bt = ["onClick"], It = ["onClick"], Et = { key: 0, class: "flex-start" }, kt = { key: 1, class: "flex-start" }, Dt = { class: "header-box flex-between" }, Pt = { class: "weather-layers card-bg" }, zt = { class: "layers-title flex-between" }, Mt = { key: 0, class: "iconfont active" }, St = { key: 1, class: "iconfont" }, Tt = { class: "layers-body" }, Qt = { class: "flex-start" }, Ht = ["onClick"], Nt = ["onClick"], Ot = { key: 0, class: "flex-start" }, Ft = { key: 1, class: "flex-start" }, Rt = ["onClick"], jt = { key: 0, class: "iconfont bookmark-icon active" }, Wt = { key: 1, class: "iconfont bookmark-icon inactive" }, Gt = { class: "other-layers card-bg" }, Ut = { class: "layers-body" }, Yt = ["onClick"], Kt = { class: "flex-start" }, Xt = { class: "switch flex-center" }, Jt = { key: 0, class: "iconfont active" }, qt = { key: 1, class: "iconfont" }, Vt = { class: "source-layers card-bg" }, Zt = { class: "layers-body" }, $t = { key: 0 }, ea = { key: 1, class: "radio-tip" }, ta = { key: 2, class: "radio-tip" }; function aa(a, e, t, r, i, s) { const n = R("ElTooltip"), l = R("ElRadio"), c = R("ElRadioGroup"), d = R("ElScrollbar"); return u(), g("div", vt, [ o("div", { class: "menu-bar-box", style: de({ top: t.top + 10 + "px", right: i.right + "px" }) }, [ o("div", bt, [ O(n, { placement: "left", effect: "light", content: "Menu", "show-after": 1e3 }, { default: Me(() => [ o("div", { class: te(t.layerToggle ? "menu-icon active" : "menu-icon"), onClick: e[0] || (e[0] = (...h) => s.handleMenuToggle && s.handleMenuToggle(...h)) }, e[17] || (e[17] = [ o("span", { class: "iconfont" }, "", -1) ]), 2) ]), _: 1 }) ]) ], 4), o("div", { class: "menu-bar-box", style: de({ top: t.top + 160 + "px", right: i.right + "px" }) }, [ o("div", Lt, [ O(n, { placement: "left", effect: "light", content: "Measure", "show-after": 1e3 }, { default: Me(() => [ o("div", { class: te(i.showMeasure ? "menu-icon active" : "menu-icon"), onClick: e[1] || (e[1] = (...h) => s.handleMeasureToggle && s.handleMeasureToggle(...h)) }, e[18] || (e[18] = [ o("span", { class: "iconfont" }, "", -1) ]), 2) ]), _: 1 }), O(n, { placement: "left", effect: "light", content: "Point Meteo", "show-after": 1e3 }, { default: Me(() => [ o("div", { class: te(i.showPoint ? "menu-icon active" : "menu-icon"), onClick: e[2] || (e[2] = (...h) => s.handlePointToggle && s.handlePointToggle(...h)) }, e[19] || (e[19] = [ o("span", { class: "iconfont" }, "", -1) ]), 2) ]), _: 1 }), O(n, { placement: "left", effect: "light", content: "Grid", "show-after": 1e3 }, { default: Me(() => [ o("div", { class: te(i.showCoord ? "menu-icon active" : "menu-icon"), onClick: e[3] || (e[3] = (...h) => s.handleCoordToggle && s.handleCoordToggle(...h)) }, e[20] || (e[20] = [ o("span", { class: "iconfont" }, "", -1) ]), 2) ]), _: 1 }), O(n, { placement: "left", effect: "light", content: "3D", "show-after": 1e3 }, { default: Me(() => [ o("div", { class: te(i.show3d ? "menu-icon active" : "menu-icon"), onClick: e[4] || (e[4] = (...h) => s.handle3DToggle && s.handle3DToggle(...h)) }, e[21] || (e[21] = [ o("span", { class: "iconfont" }, "", -1) ]), 2) ]), _: 1 }) ]) ], 4), s.hasCollectedLayers ? (u(), g("div", { key: 0, class: "active-layers", style: de({ right: i.right + "px", bottom: "100px" }) }, [ o("div", Ct, [ e[22] || (e[22] = o("div", { style: { margin: "2px 5px" } }, "Weather Layers", -1)), o("div", { class: "switch flex-center", style: { "font-size": "28px", "margin-right": "0" }, onClick: e[5] || (e[5] = (...h) => s.toggleAutoActive && s.toggleAutoActive(...h)) }, [ i.autoActive ? (u(), g("i", xt, "")) : (u(), g("i", _t, "")) ]) ]), (u(!0), g(ee, null, ae(i.layers.weather.filter((h) => h.collected), (h) => (u(), g("div", { key: h.key, class: te(s.computeLayerClass(h, i.activeWeatherLayersCollected)) }, [ o("div", { class: "checkbox", onClick: (p) => s.handleWeatherLayerPick(h) }, null, 8, Bt), o("span", { class: "name", onClick: (p) => s.handleWeatherLayerPick(h) }, k(h.name), 9, It), h.key === "wind" && i.activeWeatherLayersCollected.some((p) => p.key === h.key) ? (u(), g("div", Et, [ o("i", { class: te(["iconfont sub-layer-icon", i.showWindParticleCollected ? "active" : ""]), onClick: e[6] || (e[6] = (p) => s.handleToggleWindParticle()) }, "", 2), o("i", { class: te(["iconfont sub-layer-icon", i.showWindFeatherCollected ? "active" : ""]), onClick: e[7] || (e[7] = (p) => s.handleToggleWindFeather()) }, "", 2) ])) : q("", !0), h.key === "current" && i.activeWeatherLayersCollected.some((p) => p.key === h.key) ? (u(), g("div", kt, [ o("i", { class: te(["iconfont sub-layer-icon", i.showCurrentParticleCollected ? "active" : ""]), onClick: e[8] || (e[8] = (p) => s.handleToggleCurrentParticle()) }, "", 2), o("i", { class: te(["iconfont sub-layer-icon", i.showCurrentIsobandCollected ? "active" : ""]), onClick: e[9] || (e[9] = (p) => s.handleToggleCurrentIsoband()) }, "", 2) ])) : q("", !0) ], 2))), 128)) ], 4)) : q("", !0), o("div", { class: "available-layers flex-center", style: de({ top: t.top + "px", right: t.layerToggle ? "0px" : "-240px" }) }, [ o("div", { class: te(["list-box", t.layerToggle ? "right-bar" : ""]) }, [ o("div", Dt, [ e[23] || (e[23] = o("div", null, "Layers", -1)), o("div", { class: "iconfont close-btn", onClick: e[10] || (e[10] = (...h) => s.handleMenuToggle && s.handleMenuToggle(...h)) }, "") ]), O(d, { style: { flex: "1" } }, { default: Me(() => [ o("div", Pt, [ o("div", zt, [ e[24] || (e[24] = o("div", null, "Weather Layers", -1)), o("div", { class: "switch flex-center", style: { "margin-right": "0" }, onClick: e[11] || (e[11] = (...h) => s.toggleAutoActive && s.toggleAutoActive(...h)) }, [ i.autoActive ? (u(), g("i", Mt, "")) : (u(), g("i", St, "")) ]) ]), o("div", Tt, [ (u(!0), g(ee, null, ae(i.layers.weather, (h) => (u(), g(ee, { key: h.key }, [ h.hide ? q("", !0) : (u(), g("div", { key: 0, class: te(s.computeLayerClass(h, i.activeWeatherLayersCollected)) }, [ o("div", Qt, [ o("div", { class: "checkbox", onClick: (p) => s.handleWeatherLayerPick(h) }, null, 8, Ht), o("span", { class: "name", onClick: (p) => s.handleWeatherLayerPick(h) }, k(h.name), 9, Nt), h.key === "wind" && i.activeWeatherLayersCollected.some((p) => p.key === h.key) ? (u(), g("div", Ot, [ o("i", { class: te(["iconfont sub-layer-icon", i.showWindParticleCollected ? "active" : ""]), onClick: e[12] || (e[12] = (p) => s.handleToggleWindParticle()) }, "", 2), o("i", { class: te(["iconfont sub-layer-icon", i.showWindFeatherCollected ? "active" : ""]), onClick: e[13] || (e[13] = (p) => s.handleToggleWindFeather()) }, "", 2) ])) : q("", !0), h.key === "current" && i.activeWeatherLayersCollected.some((p) => p.key === h.key) ? (u(), g("div", Ft, [ o("i", { class: te(["iconfont sub-layer-icon", i.showCurrentParticleCollected ? "active" : ""]), onClick: e[14] || (e[14] = (p) => s.handleToggleCurrentParticle()) }, "", 2), o("i", { class: te(["iconfont sub-layer-icon", i.showCurrentIsobandCollected ? "active" : ""]), onClick: e[15] || (e[15] = (p) => s.handleToggleCurrentIsoband()) }, "", 2) ])) : q("", !0) ]), o("div", { onClick: (p) => s.handleWeatherLayerCollect(h) }, [ h.collected ? (u(), g("i", jt, "")) : (u(), g("i", Wt, "")) ], 8, Rt) ], 2)) ], 64))), 128)), e[25] || (e[25] = o("div", { class: "tip flex-start" }, [ o("i", { class: "iconfont bookmark-icon", style: { "align-self": "flex-start", padding: "5px 5px 0 0" } }, ""), o("div", null, "You can add the layers to your favorites. (Max 6)") ], -1)) ]) ]), o("div", Gt, [ e[26] || (e[26] = o("div", { class: "layers-title" }, "Other Layers", -1)), o("div", Ut, [ (u(!0), g(ee, null, ae(i.layers.other, (h) => { var p; return u(), g("div", { key: h.key, class: te(["layer flex-between", s.computeLayerClass(h, i.activeOtherLayers)]), onClick: (L) => s.handleOtherLayerPick(h) }, [ o("div", Kt, [ o("div", Xt, [ (p = s.computeLayerClass(h, i.activeOtherLayers)) != null && p.includes("active") ? (u(), g("i", Jt, "")) : (u(), g("i", qt, "")) ]), o("span", null, k(h.name), 1) ]) ], 10, Yt); }), 128)) ]) ]), o("div", Vt, [ e[27] || (e[27] = o("span", { class: "layers-title" }, "Forecast Model", -1)), o("div", Zt, [ O(c, { modelValue: i.source, "onUpdate:modelValue": e[16] || (e[16] = (h) => i.source = h), class: "layer-radio flex-col-start-start", style: { width: "180px", "align-items": "flex-start" } }, { default: Me(() => [ (u(!0), g(ee, null, ae(i.sourceList, (h, p) => (u(), gt(l, { key: `source${h.name}`, value: h.name }, { default: Me(() => { var L, E, B, y, I, x; return [ fe(k(h.name) + " ", 1), p !== 0 ? (u(), g("span", $t, k(h.resolution) + "km " + k(h.length) + "days", 1)) : q("", !0), p === 0 ? (u(), g("div", ea, "Provides the best forecast")) : (B = (E = (L = h == null ? void 0 : h.update) == null ? void 0 : L.default) == null ? void 0 : E.meta) != null && B.initialisationTime ? (u(), g("div", ta, "Update: " + k(s.computeDateZ((x = (I = (y = h == null ? void 0 : h.update) == null ? void 0 : y.default) == null ? void 0 : I.meta) == null ? void 0 : x.initialisationTime)), 1)) : q("", !0) ]; }), _: 2 }, 1032, ["value"]))), 128)) ]), _: 1 }, 8, ["modelValue"]) ]) ]) ]), _: 1 }) ], 2) ], 4) ]); } const ia = /* @__PURE__ */ Y(wt, [["render", aa]]); const ra = { name: "IdmWindBarb", props: { map: { type: Object }, wind: { type: Object }, current: { type: Object }, beforeLayer: { type: String }, mapProjection: { type: String }, showWindFeather: { type: Boolean, default: !1 }, showWindParticle: { type: Boolean, default: !1 }, toggleParticeVersion: { type: Number }, toggleVersion: { type: Number } }, emits: ["particle", "showWindFeather"], data() { return { source: "wind-barb-source", barbs: [0, 2, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105], empty: H.featureCollection([]), right: 10, bottom: 125, windBarbLoaded: !1 }; }, watch: { "wind.version": { handler() { var a; (a = this.wind) != null && a.active && this.showWindFeather ? this.handleRender() : this.handleClear(); }, deep: !0 }, toggleParticeVersion: { handler() { this.handleParticle(); } // immediate: true, }, showWindFeather: { handler() { this.handleToggle(); } // immediate: true, } }, methods: { handleParticle() { this.$emit("particle", { particle: this.showWindParticle, key: "wind", weight: 1 }); }, handleRender() { var a, e, t, r; if (!this.map) setTimeout(() => { this.handleRender(); }, 500); else if (this.wind) { const i = (/* @__PURE__ */ new Date()).valueOf(); let s = 0, n = 0, l = this.empty; if ((a = this.wind) != null && a.active && (l = (e = this.wind) == null ? void 0 : e.data), (t = this.map) != null && t.getSource(this.source)) (r = this.map) == null || r.getSource(this.source).setData(l), n = (/* @__PURE__ */ new Date()).valueOf() - (i + s), console.log("[wind] update elapsed: ", n, ", total: ", s += n); else { this.map.addSource(this.source, { type: "geojson", data: l }); for (let c = 0; c < (this.barbs ?? []).length - 1; c++) { const d = (this.barbs ?? [])[c] || 0, h = (this.barbs ?? [])[c + 1] || 0, p = d < 10 ? `00${d}kts` : d < 100 ? `0${d}kts` : `${d}kts`; this.map.addLayer( { id: p, type: "symbol", filter: [ "all", // @ts-ignore [">=", "spd", d], // @ts-ignore ["<", "spd", h] ], source: this.source, layout: { "symbol-placement": "point", "icon-image": p, // mapbox sprite "icon-size": 0.14, "icon-offset": [0, -20], "icon-allow-overlap": !0, "icon-rotation-alignment": "map", "icon-rotate": { property: "dir", stops: [ [0, 0], [360, 360] ] } }, paint: { "icon-opacity": 1, "text-color": "#222" } }, this.beforeLayer ); } this.windBarbLoaded = !0, n = (/* @__PURE__ */ new Date()).valueOf() - (i + s), console.log("[wind] add elapsed: ", n, ", total: ", s += n); } } }, handleToggle() { if (!this.windBarbLoaded) this.handleRender(); else for (const a of this.barbs ?? []) { const e = a < 10 ? `00${a}kts` : a < 100 ? `0${a}kts` : `${a}kts`; this.map.getLayer(e) && this.map.setLayoutProperty(e, "visibility", this.showWindFeather ? "visible" : "none"); } }, handleClear() { for (const a of this.barbs ?? []) { const e = a < 10 ? `00${a}kts` : a < 100 ? `0${a}kts` : `${a}kts`; this.map.getLayer(e) && this.map.removeLayer(e); } this.map.getSource(this.source) && this.map.removeSource(this.source), this.windBarbLoaded = !1; } } }; function sa(a, e, t, r, i, s) { return null; } const oa = /* @__PURE__ */ Y(ra, [["render", sa]]); class tt { constructor(e) { se(this, "map"); se(this, "mercator"); se(this, "rampColorLayer"); se(this, "rampColorSource"); se(this, "particleLayer"); se(this, "particleSource"); se(this, "rampColorCanvas"); se(this, "particleCanvas"); se(this, "ratio"); this.map = e, this.mercator = new At(), this.rampColorLayer = "ramp-color-layer", this.rampColorSource = "ramp-color-source", this.particleLayer = "particle-layer", this.particleSource = "particle-source", this.rampColorCanvas = document.createElement("canvas"), this.particleCanvas = document.createElement("canvas"), this.ratio = window.devicePixelRatio; } /** * 转换为[-180, 180]的经度,且包含转换次数 * @param lng * @param n */ convertNLng(e, t = 0) { return e > 180 ? this.convertNLng(e - 360, t + 1) : e < -180 ? this.convertNLng(e + 360, t + 1) : [e, t]; } /** * [4326坐标] * 返回视窗边界经纬度(从西北方向逆时针返回四个角的经纬度) * 依次为: NW, NE, SE, SW * @param map * @return [[lng, lat], [lng, lat], [lng, lat], [lng, lat]] */ getBoundLngLat() { const e = this.map.getBounds(); return [ [e._sw.lng, e._ne.lat], [e._ne.lng, e._ne.lat], [e._ne.lng, e._sw.lat], [e._sw.lng, e._sw.lat] ]; } /** * [视窗像素坐标] * @see https://github.com/mapbox/sphericalmercator * 返回视窗边界像素 * 依次为: 左下角(lf = left bottom)、右上角(rt = right top) * @param [lb.x, lb.y, rt.x, rt.y] */ getBoundPixel() { const e = this.map.getBounds(), t = this.map.getZoom() + 1, r = [e._ne.lng, e._ne.lat], i = [e._sw.lng, e._sw.lat], [s, n] = this.convertNLng(r[0]), [l, c] = this.convertNLng(i[0]), [d, h] = this.mercator.px([s, r[1]], t), [p, L] = this.mercator.px([l, i[1]], t), E = Math.round(this.mercator.size * Math.pow(2, t) * (n + c)); return [p, L, d + E, h]; } /** * [视窗边界像素宽度] */ getBoundRange() { const e = this.map.getZoom() + 1, t = this.mercator.size * Math.pow(2, e), r = this.getBoundPixel(); return [r[0] / t, r[2] / t, r[3] / t, r[1] / t]; } /** * 获取视窗世界(多世界复本) * @param pixels * @param zoom */ getWorldCopy(e, t) { const r = 2 ** t, [i, s, n, l] = e.map((h) => ~~(h / (r * 256))), c = []; for (let h = l; h <= s; h++) for (let p = i; p <= n; p++) c.push([p, h]); return c.map((h) => { const p = 2 ** t * 256; return [h[0] * p, h[1] * p, p]; }); } resize() { let e = this.map.getSource(this.rampColorSource); e.setCoordinates(this.getBoundLngLat()), e = this.map.getSource(this.particleSource), e.setCoordinates(this.getBoundLngLat()), this.rampColorCanvas.width = this.map._canvas.clientWidth, this.rampColorCanvas.height = this.map._canvas.clientHeight, this.particleCanvas.width = this.map._canvas.clientWidth, this.particleCanvas.height = this.map._canvas.clientHeight; } toggle(e) { const t = this.map.getLayoutProperty(this.rampColorLayer, "visibility"), r = e ? "visible" : "none"; t !== r && this.map.setLayoutProperty(this.rampColorLayer, "visibility", r); } toggleParticle(e) { const t = this.map.getLayoutProperty(this.particleLayer, "visibility"), r = e ? "visible" : "none"; t !== r && this.map.setLayoutProperty(this.particleLayer, "visibility", r); } } class je { /** * 创建着色器 * @see https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-shaders-and-glsl.html * @param gl * @param type [VERTEX_SHADER, FRAGMENT_SHADER] * @param schema 着色器渲染代码[GLSL] */ createShader(e, t, r) { const i = e.createShader(t); if (i && (e.shaderSource(i, r), e.compileShader(i), !e.getShaderParameter(i, e.COMPILE_STATUS))) throw new Error(e.getShaderInfoLog(i) || "error happened while create shader..."); return i; } /** * 创建纹理 * @see https://blog.csdn.net/qq_37987033/article/details/128745577 * @param gl * @param minFilter * @param magFilter * @param wrapFilter * @param data * @param width?? * @param height?? */ createTexture(e, t, r, i, s, n, l) { const c = e.createTexture(); return e.bindTexture(e.TEXTURE_2D, c), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, t), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, r), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, i), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, i), s instanceof Uint8Array ? e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, n, l, 0, e.RGBA, e.UNSIGNED_BYTE, s) : e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, s), e.bindTexture(e.TEXTURE_2D, null), c; } /** * 创建数据资源 * @param type [array, element] * array: ARRAY_BUFFER * element: ELEMENT_ARRAY_BUFFER * @param resource 顶点数据 */ createDataBuffer(e, t, r) { if (e) { const i = e.createBuffer(); return t === "array" ? (e.bindBuffer(e.ARRAY_BUFFER, i), r && e.bufferData(e.ARRAY_BUFFER, r, e.STATIC_DRAW)) : t === "element" && (e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, i), r && e.bufferData(e.ELEMENT_ARRAY_BUFFER, r, e.STATIC_DRAW)), i; } return null; } /** * 创建程序 * @param gl * @param vertexSchema * @param fragmentSchema */ createProgram(e, t, r) { const i = e.createProgram(), s = this.createShader(e, e.VERTEX_SHADER, t), n = this.createShader(e, e.FRAGMENT_SHADER, r); if (i && s && n && (e.attachShader(i, s), e.attachShader(i, n), e.linkProgram(i), !e.getProgramParameter(i, e.LINK_STATUS))) throw new Error(e.getProgramInfoLog(i) || "error happened while creating ramp color program"); return i; } /** * 创建程序并提取attrib & uniform参数 * @param gl * @param vertexSchema * @param fragmentSchema */ createProgramWrapper(e, t, r) { const i = this.createProgram(e, t, r); if (i) { const s = { program: i }, n = e.getProgramParameter(i, e.ACTIVE_ATTRIBUTES); for (let c = 0; c < n; c++) { const d = e.getActiveAttrib(i, c); s[d.name] = e.getAttribLocation(i, d.name); } const l = e.getProgramParameter(i, e.ACTIVE_UNIFORMS); for (let c = 0; c < l; c++) { const d = e.getActiveUniform(i, c); s[d.name] = e.getUniformLocation(i, d.name); } return s; } } /** * 初始化渐变色纹理 * @param colors */ setup(e, t, r = !1, i, s) { const n = document.createElement("canvas"); n.width = 256, n.height = 1; const l = n.getContext("2d"); if (l && e) { const c = l == null ? void 0 : l.createLinearGradient(0, 0, 256, 0); return t.forEach(([d, h]) => { c.addColorStop(d, h); }), l.fillStyle = c, l.fillRect(0, 0, 256, 1), { canvas: n, texture: this.createTexture( e, e.LINEAR, e.LINEAR, e.CLAMP_TO_EDGE, r ? new Uint8Array(l.getImageData(0, 0, 256, 1).data) : n, i, s ) }; } } setupParticle(e, t = 1e3) { const r = Math.ceil(Math.sqrt(t)), i = r * r, s = new Uint8Array(i * 4); for (let h = 0; h < s.length; h++) s[h] = Math.floor(Math.random() * 256); const n = this.createTexture(e, e.NEAREST, e.NEAREST, e.CLAMP_TO_EDGE, s, r, r), l = this.createTexture(e, e.NEAREST, e.NEAREST, e.CLAMP_TO_EDGE, s, r, r), c = new Float32Array(i); for (let h = 0; h < i; h++) c[h] = h; const d = this.createDataBuffer(e, "array", c); return { resolution: r, total: i, texture0: n, texture1: l, indexBuffer: d }; } bind(e, t, r) { const i = this.createProgram(e, t, r); if (i) { const s = this.createDataBuffer(e, "array", void 0), n = e.getAttribLocation(i, "a_position"); e.enableVertexAttribArray(n), e.vertexAttribPointer(n, 2, e.FLOAT, !1, 0, 0); const l = new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]); this.createDataBuffer(e, "array", l); const c = e.getAttribLocation(i, "a_texCoord"); return e.enableVertexAttribArray(c), e.vertexAttribPointer(c, 2, e.FLOAT, !1, 0, 0), { program: i, aPositionBuffer: s }; } return {}; } bindParticle(e, t, r, i, s, n) { const l = this.createProgramWrapper(e, t, r), c = this.createProgramWrapper(e, i, s), d = this.createProgramWrapper(e, i, n), h = this.createDataBuffer(e, "array", new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1])), p = e.createFramebuffer(); return { particle: l, screen: c, update: d, quadBuffer: h, frameBuffer: p }; } draw(e, t, r, i, s, n, l) { var c, d; if (t && r) { e.resize(), t == null || t.viewport(0, 0, (c = t == null ? void 0 : t.canvas) == null ? void 0 : c.width, (d = t == null ? void 0 : t.canvas) == null ? void 0 : d.height), t.clearColor(0, 0, 0, 0), t.clear(t.COLOR_BUFFER_BIT | t.DEPTH_BUFFER_BIT); try { t.useProgram(r); const h = { resolution: t.getUniformLocation(r, "u_resolution"), image: t.getUniformLocation(r, "u_image"), color: t.getUniformLocation(r, "u_color"), scale: t.getUniformLocation(r, "u_scale"), uvRange: t.getUniformLocation(r, "u_range_u_v"), sRange: t.getUniformLocation(r, "u_range_s") }; h.resolution && t.uniform2f(h.resolution, t.canvas.width * e.ratio, t.canvas.height * e.ratio), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, i), h.image && t.uniform1i(h.image, 0), t.activeTexture(t.TEXTURE1), t.bindTexture(t.TEXTURE_2D, s), h.color && t.uniform1i(h.color, 1), l != null && l.uvRange && (l != null && l.sRange) && (h.uvRange && t.uniform2f(h.uvRange, l.uvRange[0], l.uvRange[1]), h.sRange && t.uniform2f(h.sRange, l.sRange[0], l.sRange[1])), h.scale && t.uniform1f(h.scale, (l == null ? void 0 : l.scale) || 1); const p = e.getBoundPixel(), L = e.map.getZoom() + 1, E = e.getWorldCopy(p, L); for (const B of E) { const y = (B[0] - p[0]) * e.ratio, I = (B[1] - p[3]) * e.ratio, x = B[2] * e.ratio, [f, v, m, b] = [y, x + y, I, x + I], A = new Float32Array([f, m, v, m, f, b, f, b, v, m, v, b]); t.bindBuffer(t.ARRAY_BUFFER, n), t.bufferData(t.ARRAY_BUFFER, A, t.STATIC_DRAW), t.drawArrays(t.TRIANGLES, 0, 6); } } catch (h) { console.log(`render failed...${h}`); } } } drawParticle(e, t, r, i, s) { var n, l; t && (t == null || t.viewport(0, 0, (n = t == null ? void 0 : t.canvas) == null ? void 0 : n.width, (l = t == null ? void 0 : t.canvas) == null ? void 0 : l.height), t.disable(t.DEPTH_TEST), t.disable(t.STENCIL_TEST), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, r), t.activeTexture(t.TEXTURE1), t.bindTexture(t.TEXTURE_2D, i.texture0), this.renderScreen(e, t, i, s), this.updateParticles(e, t, i, s)); } renderScreen(e, t, r, i) { t.bindFramebuffer(t.FRAMEBUFFER, r.frameBuffer), t.framebufferTexture2D(t.FRAMEBUFFER, t.COLOR_ATTACHMENT0, t.TEXTURE_2D, r.screenTexture, 0), t.viewport(0, 0, t.canvas.width, t.canvas.height), this.renderScreenTexture(t, r.backgroundTexture, r.screen, r.quadBuffer, 0.95), this.renderParticles(e, t, r, i), t.bindFramebuffer(t.FRAMEBUFFER, null), this.renderScreenTexture(t, r.screenTexture, r.screen, r.quadBuffer, 1); const s = r.backgroundTexture; r.backgroundTexture = r.screenTexture, r.screenTexture = s; } renderScreenTexture(e, t, r, i, s) { e && (e.useProgram(r.program), e.bindBuffer(e.ARRAY_BUFFER, i), e.enableVertexAttribArray(r.a_pos), e.vertexAttribPointer(r.a_pos, 2, e.FLOAT, !1, 0, 0), e.activeTexture(e.TEXTURE2), e.bindTexture(e.TEXTURE_2D, t), e.uniform1i(r.u_screen, 2), e.uniform1f(r.u_opacity, s), e.drawArrays(e.TRIANGLES, 0, 6)); } renderParticles(e, t, r, i) { if (t) { t.useProgram(r.particle.program), t.bindBuffer(t.ARRAY_BUFFER, r.indexBuffer), t.enableVertexAttribArray(r.particle.a_index), t.vertexAttribPointer(r.particle.a_index, 1, t.FLOAT, !1, 0, 0), t.activeTexture(t.TEXTURE2), t.bindTexture(t.TEXTURE_2D, r.color.texture), t.uniform1i(r.particle.u_factor, 0), t.uniform1i(r.particle.u_particles, 1), t.uniform1i(r.particle.u_color_ramp, 2), t.uniform1f(r.particle.u_particles_resolution, r.resolution * e.ratio), t.uniform1f(r.particle.u_point, e.ratio); const s = e.getBoundRange(); t.uniform4f(r.particle.u_viewport, s[0], s[1], s[2], s[3]), t.uniform2f(r.particle.u_factor_min, i.uvRange[0], i.uvRange[0]), t.uniform2f(r.particle.u_factor_max, i.uvRange[1], i.uvRange[1]), t.drawArrays(t.POINTS, 0, r.total); } } updateParticles(e, t, r, i) { var n, l; if (t) { t.bindFramebuffer(t.FRAMEBUFFER, r.frameBuffer), t.framebufferTexture2D(t.FRAMEBUFFER, t.COLOR_ATTACHMENT0, t.TEXTURE_2D, r.texture1, 0), t.viewport(0, 0, r.resolution, r.resolution), t.useProgram(r.update.program), t.bindBuffer(t.ARRAY_BUFFER, r.quadBuffer), t.enableVertexAttribArray(r.update.a_pos), t.vertexAttribPointer(r.update.a_pos, 2, t.FLOAT, !1, 0, 0), t.uniform1i(r.update.u_factor, 0), t.uniform1i(r.update.u_particles, 1); const c = e.getBoundRange(); t.uniform4f(r.update.u_viewport, c[0], c[1], c[2], c[3]), t.uniform1f(r.update.u_rand_seed, Math.random()), t.uniform2f(r.update.u_factor_res, (n = r == null ? void 0 : r.image) == null ? void 0 : n.width, (l = r == null ? void 0 : r.image) == null ? void 0 : l.height), t.uniform2f(r.update.u_factor_min, i.uvRange[0], i.uvRange[0]), t.uniform2f(r.update.u_factor_max, i.uvRange[1], i.uvRange[1]), t.uniform1f(r.update.u_speed_factor, i.speedFactor * e.ratio), t.uniform1f(r.update.u_drop_rate, i.dropRate), t.uniform1f(r.update.u_drop_rate_bump, i.dropRateBump), t.drawArrays(t.TRIANGLES, 0, 6); } const s = r.texture0; r.texture0 = r.texture1, r.texture1 = s; } resize(e, t) { e.resize(); const r = new Uint8Array(t.canvas.width * t.canvas.height * 4).fill(0, 0, t.canvas.width * t.canvas.height * 4), i = this.createTexture(t, t.NEAREST, t.NEAREST, t.CLAMP_TO_EDGE, r, t.canvas.width, t.canvas.height), s = this.createTexture(t, t.NEAREST, t.NEAREST, t.CLAMP_TO_EDGE, r, t.canvas.width, t.canvas.height); return { screenTexture: i, backgroundTexture: s }; } async loadImg(e) { return new Promise((t) => { const r = new Blob([e], { type: e.type }), i = URL.createObjectURL(r), s = new Image(); s.crossOrigin = "anonymous", s.src = i, s.onload = () => t(s); }); } } class oe { } // 顶点渲染 se(oe, "vertexSchema", ` //canvas 坐标系上的坐标 (x, y) attribute vec2 a_position; //像素坐标 attribute vec2 a_texCoord; //纹理坐标 // canvas 宽高 uniform vec2 u_resolution; //全局变量 varying vec2 v_texCoord; //向fragmentSchema传值 void main() { // 将屏幕坐标系转化为裁剪坐标(裁剪坐标系) convert the position from pixels to 0.0 to 1.0 vec2 position = (a_position / u_resolution) * 2.0 - 1.0; // canvas的 Y 轴坐标方向和 设备坐标系的相反 gl_Position = vec4(position * vec2(1, -1), 0.0, 1.0); v_texCoord = a_texCoord; }`), // 类如风、流等u v双变量片元渲染 se(oe, "uvFragmentSchema", ` precision mediump float; uniform sampler2D u_image; uniform vec2 u_range_u_v; uniform vec2 u_range_s; uniform float u_scale; uniform sampler2D u_color; varying vec2 v_texCoord; void main() { vec4 uv = texture2D(u_image, v_texCoord); float u = uv.r * (u_range_u_v.y - u_range_u_v.x) + u_range_u_v.x; float v = uv.g * (u_range_u_v.y - u_range_u_v.x) + u_range_u_v.x; float s = sqrt(u * u + v * v) * u_scale; float r = (s - u_range_s.x) / (u_range_s.y - u_range_s.x); float f = 1.0 - uv.b; vec4 color = texture2D(u_color, vec2(r, 0.5)) * f; gl_FragColor = color; }`), // 类如浪、气压等单变量片元渲染 se(oe, "fragmentSchema", ` precision mediump float; uniform sampler2D u_image; // 灰度 uniform sampler2D u_color; // 色值映射 varying vec2 v_texCoord;// 坐标 void main() { vec4 rgba = texture2D(u_image, v_texCoord); vec4 color = texture2D(u_color, vec2(rgba.r, 0)); gl_FragColor = color; }`); class Ie { } se(Ie, "vertexSchema", ` precision mediump float; attribute float a_index; // 索引 uniform sampler2D u_particles; // 粒子纹理 uniform float u_particles_resolution; // Math.ceil(Math.sqrt(numParticles))) uniform float u_point; uniform vec4 u_viewport; varying vec2 v_particle_pos_uv; void main() { vec4 color = texture2D(u_particles, vec2( fract(a_index / u_particles_resolution), floor(a_index / u_particles_resolution) / u_particles_resolution)); vec2 v_particle_pos = vec2(color.r / 255.0 + color.b, color.g / 255.0 + color.a); v_particle_pos_uv = vec2(fract(v_particle_pos.x * (u_viewport.y - u_viewport.x) + u_viewport.x), v_particle_pos.y * (u_viewport.w - u_viewport.z) + u_viewport.z); gl_PointSize = 1.0; // gl_PointSize = u_point; gl_Position = vec4(2.0 * v_particle_pos.x - 1.0, 1.0 - 2.0 * v_particle_pos.y, 0, 1); }`), se(Ie, "fragmentSchema", ` precision mediump float; uniform sampler2D u_factor; uniform vec2 u_factor_min; uniform vec2 u_factor_max; uniform sampler2D u_color_ramp; varying vec2 v_particle_pos_uv; void main() { vec4 uv = texture2D(u_factor, v_particle_pos_uv); vec2 velocity = mix(u_factor_min, u_factor_max, uv.rg); float speed_t = length(velocity) / length(u_factor_max); // color ramp is