您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
广东省气象业务网数值预报页面修改
当前为
// ==UserScript== // @name NWP helper in GuangDong // @description 广东省气象业务网数值预报页面修改 // @namespace minhill.com // @include http://10.148.8.228/to_fore_homepage.action* // @version 1.3.5 // @grant GM_addStyle // @grant @grant unsafeWindow // @license The MIT License (MIT); http://opensource.org/licenses/MIT // @compatible firefox // @compatible chrome // @compatible edge // @note 2018/01/08 增加时效转换按钮 // @note 2018/01/15 增加经纬度功能 // @note 2018/12/03 增加显示JMA功能,暂时隐藏经纬度 // @supportURL https://gf.qytechs.cn/scripts/26259 // @author Hanchy Hill // ==/UserScript== // console.log($settings); // @require https://cdn.bootcss.com/lodash.js/4.17.11/lodash.min.js // select the target node let userConfig = { // 用户设置 alterDate : false, // 默认不修改时次 }; let $ = unsafeWindow.$; const elemsConfig = { latLonInput: undefined, showJMA:false, $doc:()=>unsafeWindow.$doc, $settings:()=>unsafeWindow.$settings, $home:unsafeWindow.$home, }; const helperConfig = { region:{ hn:{//华南 isMap: true,// 是否是等经纬地图 projection:'Equidistant',// 投影 latLon:{ xRight:636.98, xLeft:172.56, yTop:56.516, yBottom:547.576, lon0:105.0, lon1:120.0, lat0:15.0, lat1:30.0, }, }, cn:{//中国 isMap: true,// 是否是等经纬地图 projection:'Lambert', latLon:{ refLon0:110.25,refLat0:20, m0:342.98333,n0:382.51666, // refLon0:110,refLat0:20, // m0:338.98,n0:382.51, refLat1:1.001,refLat2:25.0, lonr : 80,latr :40, mr:94.983,nr:167.51, }, }, oy:{//欧亚 isMap: true,// 是否是等经纬地图 projection:'Mercator', latLon:{ xRight:692.9833, xLeft:156.9833, yTop:54.51666, yBottom:533.51666, lon0:60.0, lon1:160.0, lat0:10.0, lat1:70.0, }, }, gd:{//广东 isMap: true,// 是否是等经纬地图 projection:'Equidistant',// 投影 latLon:{ xRight:589.98334, xLeft:124.98334, yTop:104.51666, yBottom:437.51666, lon0:110, lon1:116, lat0:21.0, lat1:25.0, }, }, hy:{//海洋 isMap: true,// 是否是等经纬地图 projection:'Lambert',// 投影 latLon:{ refLon0:110,refLat0:0, m0:274.983,n0:490.51666, refLat1:1.001,refLat2:25.0, lonr : 100,latr: 20, mr:171.983,nr:270.51666, }, }, '86st':{//单站 isMap: false, }, rainnest:{//雨涡 isMap: false, }, }, currentRegion:'hn', matchLoc:()=>{},// 获取经纬度的函数 matchParam:'',// 调用上式的第二参数 }; // /** * unsafeWindow函数 * selectProItem */ const utils = { changeRegion(region){ helperConfig.currentRegion = region; return helperConfig.region[region].isMap;// 返回是否是地图 }, projection:{ Mercator:{// 墨卡托投影 calBasicInfo(lat1=0,lat2=0,n1=0,n2=0){ /*参数lat 纬度, n坐标数值 n0 赤道,d0放大系数 */ const y1 = Math.log(Math.tan(lat1)+1/Math.cos(lat1)); const y2 = Math.log(Math.tan(lat2)+1/Math.cos(lat2)); const n0 = (n1 - (y1/y2) * n2) / (1.0 - y1/y2); const d0 = y1/(n0 - n1); return {n0,d0}; }, calLatLon(mouseXY,dims){ // console.log(dims); const n0 = dims.n0; const d0 = dims.d0; // console.log(Math.sinh((n0-mouseXY.y)*d0)); const lat = Math.atan(Math.sinh((n0-mouseXY.y)*d0)); ///---------------// const r = dims.xLeft; const o = dims.xRight; const s = (dims.lon1 - dims.lon0) / (o - r); const u = dims.lon0 + (mouseXY.x - r) * s; return {lat:lat*180/Math.PI,lon:u}; }, }, Equidistant:{//等经纬度 calBasicInfo(){ return helperConfig.region[helperConfig.currentRegion].latLon }, calLatLon(mouseXY,dims){ // console.log(dims); const r = dims.xLeft; const o = dims.xRight; const i = dims.yTop; const l = dims.yBottom; const s = (dims.lon1 - dims.lon0) / (o - r); // o - r 内框宽度 -> s = lon/height const d = (dims.lat1 - dims.lat0) / (i - l);// i - l 内框高度 -> d = lat/width const u = dims.lon0 + (mouseXY.x - r) * s; const m = dims.lat1 + (mouseXY.y - i) * d; return {lat:m,lon:u}; }, }, Lambert:{// 兰伯特投影 calBasicInfo({refLon0,refLat0,m0,n0, refLat1,refLat2,lonr,latr,mr,nr}){ /* refLat0,refLon0,m0,n0 参考纬度、经度,屏幕X坐标,Y坐标; 屏幕坐标与实际坐标映射: x = (m-m0)*dx // dx为x方向比例系数 y = (n0-n)*dy // dy为y方向比例系数,y方向屏幕坐标反向,所以取反 refLat1,refLat2 2个平行纬度 latr,lonr,mr,nr 选取的另外一个点的经纬度和屏幕坐标 phi 纬度,lambda经度 */ const ang2rad = (x=0)=> Math.PI * x/180.0; const [phi0,phi1,phi2] = [ang2rad(refLat0),ang2rad(refLat1),ang2rad(refLat2)]; //console.log(phi0,phi1,phi2); const lambda0 = ang2rad(refLon0); const [tan,cos,sin,pow,PI,ln] = [Math.tan,Math.cos,Math.sin,Math.pow,Math.PI,Math.log]; const cot = (x=0)=> Math.cos(x)/Math.sin(x);// 余切 const sec = (x=0)=> 1/Math.cos(x);// 正割 const n = ln(cos(phi1)*sec(phi2))/ln(tan(0.25*PI+0.5*phi2)*cot(0.25*PI+0.5*phi1)); const F = (cos(phi1)*pow(tan(0.25*PI+0.5*phi1),n))/n; // n,F常量参数 let rho = (phi=0)=>F*pow(cot(0.25*PI+0.5*phi),n); // rho变量 let rho0 = rho(phi0); let fx = (phi,lambda)=>rho(phi)*sin(n*(lambda-lambda0)); let fy = (phi,lambda)=>rho0 - rho(phi)*cos(n*(lambda-lambda0)); const dx = fx(ang2rad(latr),ang2rad(lonr))/(mr-m0); const dy = fy(ang2rad(latr),ang2rad(lonr))/(n0-nr); // console.log(dx,dy); return {dx, dy, F, n, rho0, lambda0, m0, n0}; }, calLatLon(mouseXY,{dx,dy,F,n,rho0, lambda0, m0,n0}){ const x = (mouseXY.x - m0)*dx; const y = (n0-mouseXY.y)*dy; let rho = (x,y)=>Math.sign(n)*Math.sqrt(Math.pow(x,2)+Math.pow((rho0-y),2)); let theta = (x,y)=>Math.atan(x/(rho0-y)); let phi = (rho)=>2*Math.atan(Math.pow(F/rho,1/n))-0.5*Math.PI; let lambda = (theta)=>lambda0 + theta/n; const lat = phi(rho(x,y))*180/Math.PI; const lon = lambda(theta(x,y))*180/Math.PI; // console.log(mouseXY.x-m0,n0-mouseXY.y); //console.log(mouseXY.x - m0,n0-mouseXY.y); return {lat,lon}; }, } }, debounce:(fn, delay, scope)=>{ let timer = null; // 返回函数对debounce作用域形成闭包 return function () { // setTimeout()中用到函数环境总是window,故需要当前环境的副本; let context = scope || this, args = arguments; // 如果事件被触发,清除timer并重新开始计时 clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); } }, throttle(fn, threshold, scope) { let timer; let prev = Date.now(); return function () { let context = scope || this, args = arguments; let now = Date.now(); if (now - prev > threshold) { prev = now; fn.apply(context, args); } } }, }; var NWP_init = function(){ var fcHour = document.getElementById('forecast_hour'); var iniTime = document.getElementById('create_day'); var infoBar = document.getElementById('pic_info'); var referNode = document.getElementById('to_contrast'); var divTime = document.createElement('span'); divTime.textContent = 'hello world'; divTime.setAttribute('class', 'lcTime'); divTime.style.position = 'relative'; divTime.style.float = 'right'; divTime.style.right = '120px'; infoBar.insertBefore(divTime, referNode); // document.querySelector("#forecast_hours div").textContent = "日期"; // create an observer instance var UTC8 = new MutationObserver(function (mutations) { var dateString = iniTime.textContent.match(/(\d+).*?(\d+).*?(\d+).*?(\d+)/); var fcDate = []; fcDate[0] = Number(dateString[1]); fcDate[1] = Number(dateString[2]); fcDate[2] = Number(dateString[3]); fcDate[3] = Number(dateString[4]); fcDate[4] = Number(fcHour.textContent.match(/\d+/)); fcDate[5] = new Date(fcDate[0], fcDate[1] - 1, fcDate[2], fcDate[3] + fcDate[4] + 8); var localTime = String(fcDate[5].getMonth() + 1) + '月' + fcDate[5].getDate() + '日' + fcDate[5].getHours() + '时 GMT+8'; divTime.textContent = localTime; }); // configuration of the observer: var config = { attributes: true, childList: true, characterData: true }; UTC8.observe(fcHour, config); // later, you can stop observing //observer.disconnect(); // // ///////////////////////////////////////////////////////////// // /// ////////////////////修改时效列///////////////////////////////////////// var alterTimelist = function (mutations) { //alert(timeBar.length); if(!userConfig.alterDate) return; // 不修改则直接返回 var dateString = iniTime.textContent.match(/(\d+).*?(\d+).*?(\d+).*?(\d+)/); var fcDate = []; fcDate[0] = Number(dateString[1]); fcDate[1] = Number(dateString[2]); fcDate[2] = Number(dateString[3]); fcDate[3] = Number(dateString[4]); for (let i = 0; i < timeBar.length; i++) { let oValue = timeBar[i].value; fcDate[4] = Number(timeBar[i].value); fcDate[5] = new Date(fcDate[0], fcDate[1] - 1, fcDate[2], fcDate[3] + fcDate[4] + 8); let iday = String(fcDate[5].getDate()); iday = Array(2 > iday.length ? 2 - iday.length + 1 || 0 : 0).join(0) + iday; let ihour = String(fcDate[5].getHours()); ihour = Array(2 > ihour.length ? 2 - ihour.length + 1 || 0 : 0).join(0) + ihour; let localTime = iday+' ' + ihour+' ;'; let styleText = '#'+timeBar[i].getAttribute("id")+':before{white-space:pre;content: " '+localTime+' "}'; GM_addStyle(styleText); switch(fcDate[5].getHours()){ case 5: timeBar[i].style.cssText = "border-left:2px solid #9B30FF"; break; case 14: timeBar[i].style.cssText = "border-left:2px solid #EE3B3B"; break; case 20: timeBar[i].style.cssText = "border-bottom:1px dotted #8E8E8E;border-left:2px solid #ffffff;"; break; default: timeBar[i].style.cssText = "border-left:2px solid #ffffff;"; } } }; ///////////////////////////////////////////////////////////// /// var selectObserver = new MutationObserver(alterTimelist); // configuration of the observer: var timeBar = document.querySelector("#forecast_hours select"); var config2 = { attributes: false, childList: true, characterData: false, }; selectObserver.observe(timeBar, config2); GM_addStyle("#forecast_hours option{width: 50px!important; overflow: hidden!important;}"); //-----------------------------------------------------------------------------// let imgObserver = new MutationObserver(fitImgLoc); imgObserver.observe(timeBar, config2); //-----------------------------------绑定坐标-----------------------------------// function fitImgLoc(){ // 绑定img包含的div元素 // console.log(unsafeWindow._region); // TODO const isMap = utils.changeRegion(unsafeWindow._region); // 改变地图; if(!isMap) return; // 如果不是地图直接返回 /////TODO 判断地图逻辑分离 const currMap = helperConfig.region[helperConfig.currentRegion]; const currProjection = currMap.projection; //let matchLoc = ({}); //let param = ({}); switch (currProjection) { case 'Mercator':{const dims = currMap.latLon; const lat1 = Math.PI/180.0 * dims.lat0; const lat2 = Math.PI/180.0 *dims.lat1; const n1 = dims.yBottom; const n2 = dims.yTop; // console.log(dims); const param1 = utils.projection.Mercator.calBasicInfo( lat1, lat2, n1, n2 ); helperConfig.matchParam = {...param1, xRight:dims.xRight, xLeft:dims.xLeft, lon0:dims.lon0, lon1:dims.lon1, }; // console.log(helperConfig.matchParam); helperConfig.matchLoc = utils.projection.Mercator.calLatLon; break; } case 'Lambert':{ const LamDim = currMap.latLon; /* const LamParam1 = [ LamDim.refLon0, LamDim.refLat0, LamDim.m0, LamDim.n0, LamDim.refLat1, LamDim.refLat2, LamDim.lonr, LamDim.latr, LamDim.mr, LamDim.nr]; */ const LamParam2 = utils.projection.Lambert.calBasicInfo(LamDim); // console.log(LamParam2); helperConfig.matchParam = LamParam2; helperConfig.matchLoc = utils.projection.Lambert.calLatLon; break; } default: helperConfig.matchParam = currMap.latLon; helperConfig.matchLoc = utils.projection.Equidistant.calLatLon; break; } let wrapDiv = document.querySelector('#pic_frame div'); if(wrapDiv){ wrapDiv.addEventListener('mousemove', utils.debounce(getMouseLatLon,100)); // console.log(wrapDiv.clientWidth);// offsetWidth , clientWidth, scrollWidth } } function getElemRelPos (e, t, n) {// e.target, e.clientX, e.clientY var a = e.getBoundingClientRect(), r = getComputedStyle(e); return { x: t - (a.left + parseFloat(r.paddingLeft) + parseFloat(r.borderLeftWidth)), y: n - (a.top + parseFloat(r.paddingTop) + parseFloat(r.borderTopWidth)) }; } function getMouseLatLon(event){ let target = event.target;// //let dims = helperConfig.region[helperConfig.currentRegion].latLon; /*let dims = {"width": 875, "height": 601, "pagewidth": 876, "pageheight": 601, "Xplot0": 211.0, "Xplot1": 812.0, "Yplot0": 53, "Yplot1": 676,// 从下往上算 "lon0": 105.0, "lon1": 120.0, "lat0": 15.0, "lat1": 30.0}; */ //"pagewidth": 876, "pageheight": 602, //"Xplot0": 87, "Xplot1": 773, //"Yplot0": 54, "Yplot1": 549, //"lon0": 101, "lon1": 126.314, //"lat0": 15, "lat1": 30.15}; const mouseXY = getElemRelPos(target, event.clientX, event.clientY); // 相对图像的像素位置{x,y} // console.log(mouseXY); // const r = dims.Xplot0 / dims.pagewidth * target.clientWidth;// r ->x右值 // const o = dims.Xplot1 / dims.pagewidth * target.clientWidth;// o ->x左值 // const i = (dims.pageheight - dims.Yplot1) / dims.pageheight * target.clientHeight;// y 上值 // const l = (dims.pageheight - dims.Yplot0) / dims.pageheight * target.clientHeight;// y 下值 /* const r = dims.xLeft; const o = dims.xRight; const i = dims.yTop; const l = dims.yBottom; const s = (dims.lon1 - dims.lon0) / (o - r); // o - r 内框宽度 -> s = lon/height const d = (dims.lat1 - dims.lat0) / (i - l);// i - l 内框高度 -> d = lat/width const u = dims.lon0 + (mouseXY.x - r) * s; const m = dims.lat1 + (mouseXY.y - i) * d; */ const loc = helperConfig.matchLoc(mouseXY, helperConfig.matchParam); //elemsConfig.latLonInput.lat.innerHTML = mouseXY.x//loc.lat; // elemsConfig.latLonInput.lon.innerHTML = mouseXY.y//loc.lon; elemsConfig.latLonInput.lat.innerHTML = loc.lat; elemsConfig.latLonInput.lon.innerHTML = loc.lon; // console.log(mouseXY.x, mouseXY.y); // console.log(mouseXY.x, mouseXY.y); //console.log(m,u,mouseXY.x,mouseXY.y); return {lat: loc.lat, lon: loc.lon}; } //------------------------------24小时跳跃-------------------------------------// const timeJump = function(){ //var hourBar = document.getElementById('from_hour');float-l var jumpParent = document.querySelector('.float-l'); var pre24 = document.createElement('button'); pre24.addEventListener("click", function(){timeTrigger(-24);}); pre24.textContent = "-24"; jumpParent.appendChild(pre24); var next24 = document.createElement('button'); next24.addEventListener("click", function(){timeTrigger(24);}); next24.textContent = "+24"; jumpParent.appendChild(next24); var timeTrigger = function(timer){ let selectedVal = timeBar[timeBar.selectedIndex].getAttribute("data-hour"); let nextVal = String(Number(selectedVal) + timer); var posi = 3; nextVal = Array(posi > nextVal.length ? posi - nextVal.length + 1 || 0 : 0).join(0) + nextVal; let nextopt = timeBar.querySelector("#option_"+nextVal); //alert(nextopt); if(!nextopt) return; timeBar[timeBar.selectedIndex].selected = false; nextopt.selected = true; //var oitem = document.getElementById('option_018'); //oitem.selected = true; var changeEvt = document.createEvent('HTMLEvents'); changeEvt.initEvent('change',true,true); timeBar.dispatchEvent(changeEvt); }; }; timeJump(); /////切换时效 function switchDate(){ userConfig.alterDate = !userConfig.alterDate; if(userConfig.alterDate){ switchDateBtn.textContent = "切换成时效"; alterTimelist(); } else{ switchDateBtn.textContent = "切换成日期"; for(let ele of timeBar){ ele.style.cssText = ''; let styleText = '#'+ele.getAttribute("id")+':before{white-space:pre;content: ""}'; GM_addStyle(styleText); } } } var switchParent = document.querySelector('.float-l'); let switchDateBtn = document.createElement('button'); switchDateBtn.addEventListener("click", switchDate); switchDateBtn.textContent = "切换成日期"; switchParent.appendChild(switchDateBtn); /////end 切换时效 ///// }; function showJMA(){ var getXML = function(_url, callback, errorcall){ return $.ajax({ type: "GET", url: _url, dataType: "text", success: function(xml){ var alterString = xml.replace(/<!-- <Products name="jmathin_d"/,'<Products name="jmathin_d"') .replace(/<\/Products>-->\n\s+<Pro.*?专业/,`</Products><Products comparable="flase" show="true" item="专业`); //.replace(/<!--<Products name="ecmwf_b"/,`<Products name="ecmwf_b"`) //.replace(/<\/Products>-->\n\s+<Pro.*?ec/,`</Products><Products name="ec`); var parser = new DOMParser(); var xmlDoc = parser.parseFromString(alterString, "text/xml"); var $xml = $(xmlDoc); callback($xml); }, error: function(XMLHttpRequest, textStatus, errorThrown) { $.holdReady(false); if(errorcall && $.isFunction(errorcall)) errorcall(XMLHttpRequest, textStatus, errorThrown); } }); }; // 加载XML配置文件 /** * 加载左侧菜单 */ function reloadMenu(){ document.getElementById('items').innerHTML = ''; //doSetLeftMenu(); let products=[]; var span = '<span class="lm_item lm_item_ex lm_item_ep"></span>'; var titleSpan='<a class="lm_item_a"></a>' // 添加对比菜单项 unsafeWindow.$doc.find('Comparison[show="true"]').each( function(i, pros) { $(span).attr("id", $(pros).attr("name")).attr("name", $(pros).attr("item")).text($(pros).attr("item")).click( function() { unsafeWindow.doComparClick(this.id); }).appendTo($("#leftMenu #items")).attr("title",$(pros).attr("item")) .addClass("lm_item_a").removeClass('lm_item_ep') .css({'height':'30px','line-height':'30px','font-size':'14px','text-indent':'8px','text-align':'left','cursor': 'pointer'}); }); // 添加预报模式 //var o = $doc.find('Products[show="true"]'); var options=""; unsafeWindow.$doc.find('Products[show="true"]').each( function(i, pros) { if(!$(pros).attr("name")){ var ts = $(titleSpan).text($(pros).attr("item")).appendTo($("#leftMenu #items")).attr("title",$(pros).attr("item")); if($(pros).attr("close") == "true"){ ts.addClass("menu-close"); } return; } var formatItem=$(pros).attr("item"); options+="<option value='"+formatItem+"'>"+formatItem+"</option>"; $(span).attr("id", $(pros).attr("name")).attr("name", $(pros).attr("item")).attr( "path", undefined == ($(pros).attr("path")) ? null : $(pros) .attr("path")).text($(pros).attr("item")) .click( function() { unsafeWindow.doClickPors(this.id); }).appendTo($("#leftMenu #items")).attr("title",$(pros).attr("item")); }); // console.log(options); var impLabWeb = "<a id='rdszdsys'"+ "href='http://www.grapes-trams.org.cn/Products.aspx?mode=1'"+ " target='_blank' "+ " style=' width: 104px; height: 32px; line-height: 32px; text-align: center; background: none repeat scroll 0 0 #3381CF; color: #FFFFFF; z-index: 10;display:block'>重点实验室外网</a>" $("#leftMenu #items").append(impLabWeb); $('#jmathin_d').click() }; getXML(unsafeWindow.$home + '/data/forecastInfo.xml', function($xml) { unsafeWindow.$doc = $xml; reloadMenu(); }, function() { alert("加载XML配置文件失败!"); }); elemsConfig.showJMA = !elemsConfig.showJMA; } function createPanel(){ //-创建面板-// const panelWrap = document.createElement("div"); panelWrap.setAttribute("id","helper_panel"); panelWrap.setAttribute("class","show_panel"); /* 设置添加JMA*/ const addJMA = document.createElement('div'); addJMA.innerHTML = `<div id="show-jma" class="jma-button not-active">显示JMA</div>`; panelWrap.appendChild(addJMA); addJMA.addEventListener('click', showJMA); /* 设置Lat lon面板*/ const latLonWarp = document.createElement("div"); latLonWarp.setAttribute("id","helper_latLon"); latLonWarp.setAttribute("class","show_latLon"); latLonWarp.innerHTML = '<span>Lat <span class="fixLoc" id="helper_lat"></span> Lon <span class="fixLoc" id="helper_lon"></span></span>'; panelWrap.appendChild(latLonWarp); const ibody = document.getElementsByTagName("body")[0]; ibody.appendChild(panelWrap); //-------// //-注册(不可用)到全局变量-// elemsConfig.latLonInput = { lat:document.getElementById('helper_lat'), lon:document.getElementById('helper_lon'), }; } // 添加面板样式 GM_addStyle(`.show_panel{display:block!important;z-index:1001;} #helper_panel{ position:absolute; top:5px;right:500px; background-color: rgb(45,53,63); border-bottom: 0px solid rgb(20,20,20); padding:5px; border-bottom: 0px solid rgb(20,20,20);border-radius: 4px;border: 1px solid rgb(22,25,28); box-shadow:0 1px 0 rgba(162,184,204,0.25) inset,0 0 4px hsla(0,0%,0%,0.95); color: white;} .jma-button{ cursor:pointer; } `); /**暂时隐藏按钮 */ // GM_addStyle(`#helper_latLon .fixLoc{display:inline-block;width:40px;height:15px;overflow:hidden;}`); GM_addStyle(`#helper_latLon{display:none;}`); /**重要添加十字鼠标 */ // GM_addStyle('#pic_frame div{border:1px solid !important;cursor:crosshair !important;}'); createPanel(); NWP_init();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址