您需要先安装一个扩展,例如 篡改猴、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.5.3 // @require https://lib.baomitu.com/echarts/4.6.0/echarts.min.js // @require https://lib.baomitu.com/moment.js/2.24.0/moment.min.js // @grant GM_addStyle // @grant @grant unsafeWindow // @grant GM_openInTab // @grant GM_xmlhttpRequest // @license The MIT License (MIT); http://opensource.org/licenses/MIT // @connect 172.22.1.175 // @connect api.map.baidu.com // @compatible firefox // @compatible chrome // @note 2018/01/08 增加时效转换按钮 // @note 2018/01/15 增加经纬度功能 // @supportURL https://greasyfork.org/scripts/26259 // @author Hanchy Hill // TODO 数据格式错误时显示提示 // TODO require resData // TODO 风向tooltip改进 // TODO 增加气压 // TODO 增加集合预报-32天预报 // TODO 单站停止经纬度捕捉 // TODO 分钟降水时时效切换错误 // TODO 显示单击的点 // TODO 垂直剖面NCL测试 // TODO 垂直探空曲线 // TODO 降水量, 风力分级 // ==/UserScript== let mvPatternList = [ [{ "elem": "t2mm", "elemCN": "2m气温", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "t2mm24", "elemCN": "2m气温24h变温", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "wind10m", "elemCN": "10m风", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "10gust3", "elemCN": "10m阵风(过去3h)", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }] ] let userConfig = { // 用户设置 alterDate : false, // 默认不修改时次 timelineMove: false,//是否启用滑动时间触发 }; let $ = unsafeWindow.$; const elemsConfig = { latLonInput: undefined, $doc:()=>unsafeWindow.$doc, $settings:()=>unsafeWindow.$settings, $home:unsafeWindow.$home, fixPoint: undefined, pointerPoint:{lat:0,lon:0},// 地图锚点位置 point01: undefined, point02: undefined, state:'timeseries',//'vertical','skewT' compareImgDOM:{img:[],info:[]},//前后预报时次对比DOM引用 mvImgDOM:{//四分图DOM引用 img:[], info:[], mode:'multiElem',//multiTime, multiModel, multiElem,multiInitime matchPattens:[ { "elem": "t2mm", "elemCN": "2m气温", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "t2mm24", "elemCN": "2m气温24h变温", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "wind10m", "elemCN": "10m风", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" }, { "elem": "10gust3", "elemCN": "10m阵风(过去3h)", "region": "cn", "model": "ecmwffine_b", "modelFileName":"ecmwffine" },], }, }; 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', matchImgXY:()=>{},// 根据经纬度获取图像位置 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}; }, calImgLoc(latlon, dims={xLeft, xRight,lon1,lon0,n0,d0}){ const n0 = dims.n0; const d0 = dims.d0; const sec = (x=0)=> 1/Math.cos(x);// 正割 const lon = latlon.lon; const r = dims.xLeft; const o = dims.xRight; const s = (dims.lon1 - dims.lon0) / (o - r); const x = (lon - dims.lon0)/s + r; const phi = latlon.lat/180*Math.PI; const y = n0 - Math.log(Math.tan(phi) + sec(phi))/d0; const mouseXY = {x,y}; return mouseXY; }, }, 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}; }, calImgLoc(latlon={lat,lon},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 lat = latlon.lat; const lon = latlon.lon; const x = (lon - dims.lon0)/s + r; const y = (lat - dims.lat1)/d + i; const mouseXY = {x,y}; return mouseXY; }, }, 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, rho, 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}; }, calImgLoc(latlon,{dx, dy, rho=()=>{},rho0,m0,n0, lambda0}){ const [cos,sin,PI] = [Math.cos,Math.sin,Math.PI]; const phi = latlon.lat*PI/180; const lambda = latlon.lon*PI/180; const originX = (phi,lambda)=>rho(phi)*sin(n*(lambda-lambda0)); const originY = (phi,lambda)=>rho0 - rho(phi)*cos(n*(lambda-lambda0)); let mouseXY = {x:0, y:0}; mouseXY.x = originX(phi,lambda)/dx + m0; mouseXY.y = n0 - originY(phi,lambda)/dy; return mouseXY; } } }, 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); } } }, showSkewT(point={lat:21,lon:120},runtime='2019012018',fcHour='18'){ const latRange = [point.lat-0.125*2,point.lat+0.125*2]; const lonRange = [point.lon-0.125*2,point.lon+0.125*2]; let fcTime = utils.getFcTime(); const initTime = moment(fcTime.date+fcTime.hr,'YYYY-MM-DDHH'); runtime = initTime.format('YYYYMMDDHH'); fcHour = fcTime.fcHour; GM_openInTab(`https://www.tropicaltidbits.com/analysis/models/sounding/?model=gfs&runtime=${runtime}&fh=${fcHour}&domain=${lonRange[0].toFixed(2)},${lonRange[1].toFixed(2)},${latRange[0].toFixed(2)},${latRange[1].toFixed(2)}&stationID=&tc=&mode=regular`); // https://www.tropicaltidbits.com/analysis/models/sounding/?model=gfs&runtime=2018122418&fh=18&domain=120,122.5,20,22.5&stationID=&tc=&mode=regular }, showVertical(p0={lat:21,lon:120},p1={lat:23,lon:130},runtime='2019012018',fcHour='18'){ let fcTime = utils.getFcTime(); const initTime = moment(fcTime.date+fcTime.hr,'YYYY-MM-DDHH'); runtime = initTime.format('YYYYMMDDHH'); fcHour = fcTime.fcHour; let type = 'RH_and_Omega';//[FGEN,_%CE%B8%E2%82%91,_Omega,RH_and_Omega,Normal_Wind,In-Plane_Wind] GM_openInTab(`https://www.tropicaltidbits.com/analysis/models/xsection/?model=gfs&runtime=${runtime}&fh=${fcHour}&p0=${p0.lat.toFixed(2)},${p0.lon.toFixed(2)}&p1=${p1.lat.toFixed(2)},${p1.lon.toFixed(2)}&type=${type}&tc=`); // https://www.tropicaltidbits.com/analysis/models/xsection/?model=gfs&runtime=2018122500&fh=6&p0=31.23,-113.14&p1=39.72,-95.24&type=FGEN,_%CE%B8%E2%82%91,_Omega&tc= }, showTimeSeries(point={lat:21,lon:120}){ console.log(point); if(point.mouseXY){ const elem = document.getElementById('map-pointer'); elem.style.marginLeft = point.mouseXY.x + 29.31 + 'px'; elem.style.marginTop = point.mouseXY.y - 33.066 + 'px'; } const fcTime = utils.getFcTime(); const initTime = moment(fcTime.date+fcTime.hr,'YYYY-MM-DDHH'); const sT = initTime.format('YYYY-MM-DD%20HH:mm:ss'); const eT = moment(initTime).add(10*24,'hours').format('YYYY-MM-DD%20HH:mm:ss'); point.lat = utils.fix2Grid(point.lat); point.lon = utils.fix2Grid(point.lon);//取格点位置 getTimeSeries(model='ecmwfthin', sT,eT, lon=point.lon,lat=point.lat, eles=['t2mm','mn2t','mx2t','u10m','v10m','tcco','lcco','tppm']); }, fix2Grid(number,interval=0.125){ let fixNum = Math.round(number/interval)*interval; return fixNum; }, getFcTime(){ const fcHour = typeof(unsafeWindow.forecastHour)==='string'?unsafeWindow.forecastHour:unsafeWindow.forecastHour[0]; let idate = unsafeWindow.$settings.date; if(!idate.length) throw new Error('日期为空错误'); if(idate[6]=='-') idate = idate.slice(0,5)+'0'+idate.slice(5); if(idate.length===9) idate = idate.slice(0,8)+'0'+idate.slice(8); const hr = unsafeWindow.$settings.HH; return {date:idate,hr,fcHour};//format->date:'2019-01-22;, hr:'12';fcHour:'000' }, getTimeSeries(point={lat:21,lon:115},model='giftdaily',eles=[t2mm,tmax,tmin],start='2014-11-22%2000:00:00'){ //http://172.22.1.175/di/grid.action?userId=sqxt&pwd=shengqxt123&interfaceId=intGetMultElesDataTimeSerial&dataFormat=xml2&modelid=giftdaily&element=t2mm%20tmax%20tmin&level=1000&starttime=2014-11-22%2000:00:00&endtime=2014-11-25%2000:00:00&lon=113.5&lat=24.5 }, calWind(u10,v10){ const iSpeed = Math.sqrt(Math.pow(u10,2)+Math.pow(v10,2));//风速 const iR = Math.sign(v10)*Math.acos(u10/iSpeed);//标准坐标系弧度 const arrowR = iR - Math.PI/2;//矢量箭头偏移弧度 let northDir = -(iR + Math.PI - Math.PI/2);//与北向的角度差 if(northDir<0){ northDir = northDir + Math.PI*2; } const dir = northDir/Math.PI*180; if(dir>360) dir = dir - 360; return {speed:iSpeed,rotation:arrowR,northDir:northDir}; }, renderArrow(param, api) { let arrowSize = 10; var point = api.coord([ api.value(2),//dims.timeIndex api.value(0)//5//api.value(dims.windSpeed) ]); return { type: 'path', shape: { //pathData: 'M31 16l-15-15v9h-26v12h26v9z', pathData:'M250 0 L140 350 L250 250 L360 350 Z', x: -arrowSize / 2, y: -arrowSize / 2, width: arrowSize, height: arrowSize }, rotation: api.value(1),//api.value(dims.R),//Math.PI / 8 * index; position: point, style: api.style({ stroke: '#555', lineWidth: 1, fill:'green', }) }; }, createElement(type='div',props={}){ let newEle = document.createElement(type); for(let attr in props){ newEle.setAttribute(attr,props[attr]); } return newEle; }, getImgNow(imgSrc){ // TODO 改进匹配规则 let fcTime = utils.getFcTime(); //const initTime = moment(fcTime.date+fcTime.hr,'YYYY-MM-DDHH'); // runtime = initTime.format('YYYYMMDDHH'); fcHour = fcTime.fcHour; let url = imgSrc||unsafeWindow.imgSrc[fcHour]; if(!url) throw new Error('无法获取初始图像'); // url = 'http://10.148.8.228/files_home/znwp/ecmwffine_b/hn/20190128/ecmwffine_hn_mslp_000_2019012800.png'; const reg = /(http:.*?\/)(\d{8})(.*?_)(\d+)_(\d+)(.*?$)/; const matchUrl = url.match(reg); /*0: "http://10.148.8.228/files_home/znwp/ecmwffine_b/hn/20190128/ecmwffine_hn_mslp_030_2019012800.png" 1: "http://10.148.8.228/files_home/znwp/ecmwffine_b/hn/" 2: "20190128" 3: "/ecmwffine_hn_mslp_" 4: "030" 5: "2019012800" 6: ".png" index: 0 input: "http://10.148.8.228/files_home/znwp/ecmwffine_b/hn/20190128/ecmwffine_hn_mslp_030_2019012800.png" length: 7 */ const base = [matchUrl[1],matchUrl[3],matchUrl[6]]; const model = base[0].match(/znwp\/(.*?)\//)[1]; // console.log(base[1]); const eleName = base[1].match(/_.*?_(.+?)_$/)[1]; const date = matchUrl[2]; const hour = matchUrl[4]; const initDate = matchUrl[5]; const imgInfo = { url, date, base, hour, initDate, model, eleName, getUrl(date=date,hour=hour,initDate=initDate){ return base[0]+date+base[1]+hour+'_'+initDate+base[2]; } } return imgInfo; }, matchImgPattern(pat={elem: "t2mm",elemCN: "2m气温",region: "cn",model: "ecmwffine_b",modelFileName:"ecmwffine"}){ let base0 = `http://10.148.8.228/files_home/znwp/${pat.model}/${pat.region}/`; let base1 = `/${pat.modelFileName}_${pat.region}_${pat.elem}_`; return { // base:['http://10.148.8.228/files_home/znwp/ecmwffine_b/hn/','/ecmwffine_hn_mslp_','.png'], base:[base0,base1,'.png'], }; }, getImgUrl(base,date,hour,initDate){ return base[0]+date+base[1]+hour+'_'+initDate+base[2]; }, paddingInt(num, length=3) { //这里用slice和substr均可 return (Array(length).join("0") + num).slice(-length); }, 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)) }; }, }; 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.timelineMove){ timeMoveOver();//是否启用滑动时间触发 } 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; helperConfig.matchImgXY = utils.projection.Mercator.calImgLoc; 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; helperConfig.matchImgXY = utils.projection.Lambert.calImgLoc; break; } default: helperConfig.matchParam = currMap.latLon; helperConfig.matchLoc = utils.projection.Equidistant.calLatLon; helperConfig.matchImgXY = utils.projection.Equidistant.calImgLoc; break; } //let wrapDiv = document.querySelector('#pic_frame div'); let wrapDiv = document.querySelector('#pic_frame'); // document.addEventListener('keyup', console.log(elemsConfig.fixPoint)); if(wrapDiv){ wrapDiv.addEventListener('mousemove', utils.debounce(getMouseLatLon,100)); // wrapDiv.addEventListener('mousemove', getMouseLatLon); // 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); /** * e.getBoundingClientRect() * bottom: 916.1999969482422 height: 716 left: 686.9000244140625 right: 1565.1333618164062 top: 200.1999969482422 width: 878.2333374023438 x: 686.9000244140625 y: 200.1999969482422 borderLeftWidth: "1px" borderTopWidth: "1px" paddingLeft: "0px" paddingTop: "0px" */ return { x: t - (a.left + parseFloat(r.paddingLeft) + parseFloat(r.borderLeftWidth)), y: n - (a.top + parseFloat(r.paddingTop) + parseFloat(r.borderTopWidth)) }; } function getMouseLatLon(event){ // console.log(event); // console.log(event.target); // let target = event.target;// let target = document.querySelector('#pic_frame img[style~="inline;"]');// // console.log(target); const mouseXY = getElemRelPos(target, event.clientX, event.clientY); // 相对图像的像素位置{x,y} const loc = helperConfig.matchLoc(mouseXY, helperConfig.matchParam); elemsConfig.latLonInput.lat.innerHTML = loc.lat; // mouseXY.y elemsConfig.latLonInput.lon.innerHTML = loc.lon; // mouseXY.x // elemsConfig.latLonInput.lat.innerHTML = mouseXY.y // elemsConfig.latLonInput.lon.innerHTML = mouseXY.x elemsConfig.fixPoint = {lat: loc.lat, lon: loc.lon,mouseXY}; return {lat: loc.lat, lon: loc.lon,mouseXY}; } //------------------------------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 changeEvt = document.createEvent('HTMLEvents'); // changeEvt.initEvent('change',true,true); // timeBar.dispatchEvent(changeEvt); var changeEvt = new Event('change', { 'bubbles': 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 切换时效 ///// //设置鼠标事件// document.onkeydown = function(evt){ if(evt.key=='x'&&!evt.ctrlKey){ console.log(utils.showSkewT(elemsConfig.fixPoint)); } else if(evt.key=='x'&&evt.ctrlKey){ if(!elemsConfig.point01){ elemsConfig.point01 = Object.assign({},elemsConfig.fixPoint); } else{ elemsConfig.point02 = Object.assign({},elemsConfig.fixPoint); console.log(elemsConfig.point01,elemsConfig.point02); utils.showVertical(elemsConfig.point01,elemsConfig.point02); elemsConfig.point01 = null; elemsConfig.point02 = null; } } if(evt.key=='c'&&!evt.ctrlKey&&!evt.altKey){ utils.showTimeSeries(elemsConfig.fixPoint); } } //设置鼠标事件// /** * 时间鼠标滑过 */ function timeMoveOver(){ // var changeEvent = document.createEvent('HTMLEvents'); // changeEvent.initEvent("change", true, true); var changeEvent = new Event('change', { 'bubbles': true }); var clickOpt = (evt)=>{ console.log(evt.target); timeBar[timeBar.selectedIndex].selected = false; evt.target.selected = true; timeBar.dispatchEvent(changeEvent); } var timeBar = document.querySelector("#forecast_hours select"); var opts = document.querySelectorAll('#forecast_hours option'); opts.forEach(item => { item.addEventListener('mouseover',clickOpt); }); } }; function showNotification(text='测试'){ // 先检查浏览器是否支持 if (!("Notification" in window)) { alert("This browser does not support desktop notification"); } // 检查用户是否同意接受通知 else if (Notification.permission === "granted") { // If it's okay let's create a notification var notification = new Notification(text); } // 否则我们需要向用户获取权限 else if (Notification.permission !== 'denied') { Notification.requestPermission(function (permission) { // 如果用户同意,就可以向他们发送通知 if (permission === "granted") { var notification = new Notification(text); } }); } } function toggleSelectMode(){ let mapPointer = document.getElementById('map-pointer'); let bodyDOM = document.getElementsByTagName('body')[0]; let linePanel = document.getElementById('line_panel'); let selectModePanel = document.getElementById('select-mode-panel'); if(bodyDOM.classList.contains("full-screen-mode")){ bodyDOM.classList.remove("full-screen-mode"); linePanel.style.display='none'; selectModePanel.style.display='none'; mapPointer.classList.add("display-none"); return; }else{ bodyDOM.classList.add("full-screen-mode"); let contentWidth = window.innerWidth - document.body.clientWidth - 40; if(contentWidth<200){ linePanel.style.width='220px'; }else{ linePanel.style.width=contentWidth+'px'; } linePanel.style.display='block'; selectModePanel.style.display='block'; mapPointer.classList.add("display-none"); mapPointer.classList.remove("display-none"); } const imgXY = latlon2XY({lon:113.375,lat:23.125}); utils.showTimeSeries({lon:'113.375',lat:'23.125',mouseXY:imgXY}); } // http://172.22.1.175/di/grid.action?userId=idc&pwd=U3cuYV&interfaceId=intGetMultElesDataTimeSerial&dataFormat=xml2&modelid=giftdaily&element=t2mm%20tmax%20tmin&level=1000&starttime=2014-11-22%2000:00:00&endtime=2014-11-25%2000:00:00&lon=113.5&lat=24.5 function getTimeSeries(model='ecmwfthin',sT='2019-01-22%2012:00:00',eT='2019-02-01%2012:00:00',lon='113.0',lat='23.5',eles=['t2mm','mn2t','mx2t','u10m','v10m','tcco','lcco','tppm']){ const url = `http://172.22.1.175/di/grid.action?userId=sqxt&pwd=shengqxt123&dataFormat=json&interfaceId=intGetMultElesDataTimeSerial&modelid=${model}&element=${eles.join('%20')}&level=0&starttime=${sT}&endtime=${eT}&lon=${lon}&lat=${lat}`; console.log('获取数据'); showNotification('正在从数据中心获取数据'); console.log(url); GM_xmlhttpRequest({ //获取时间序列 method : 'GET', synchronous : false, url : url, onload : function (reDetails) { if (reDetails.status !== 200&&reDetails.status !== 304){ console.error('获取URL错误'); showNotification('数据中心数据获取异常'); return; } getLocation(lat,lon); const data = JSON.parse(reDetails.responseText); //console.log(data.DATA); if(data.DATA.length==0){ console.error('此时次数据为空,请等待更新'); showNotification('此时次数据为空,请等待更新'); return; } let series = decodeSeries(data.DATA, 241); series[1] = mixUndefined(series[0].map(v=>v[1]),series[1]); series[2] = mixUndefined(series[0].map(v=>v[1]),series[2]); //console.log(series[1]); drawLine(series); } }); } /** * 从百度接口获取地址 * @param {Number} lat 纬度 * @param {Number} lon 经度 */ function getLocation(lat,lon){ let ak = 'kMW5fXfhhsMat6Ud9jYPqnxCRQGbl2eV'; let url = `http://api.map.baidu.com/geocoder/v2/?callback=renderReverse&location=${lat},${lon}&output=json&pois=1&ak=${ak}`; let latlonSpan = document.querySelectorAll('#line_info > span'); latlonSpan[0].innerHTML = lat; latlonSpan[1].innerHTML = lon; latlonSpan[2].innerHTML = ''; console.log(url); GM_xmlhttpRequest({ //获取时间序列 method : 'GET', synchronous : false, url : url, onload : function (reDetails) { if (reDetails.status !== 200&&reDetails.status !== 304){ console.error('获取百度地址异常'); //showNotification('数据中心数据获取异常'); return; } let raw = reDetails.responseText.replace('renderReverse&&renderReverse(','').slice(0,-1); const addreJSON = JSON.parse(raw); if(addreJSON.result.formatted_address==''){ return; }else{ latlonSpan[2].innerHTML = ' 地址: '+ addreJSON.result.formatted_address; } //console.log(data); } }); } function mixUndefined(index,data){ let newData = []; for(let i of index){ let value = data.find(v=>v[1]==i); if(value===undefined){ newData.push([undefined,i]); }else{ newData.push([value[0],i]); } } return newData } /**解析数据 */ function decodeSeries(data=[], len=241){ if(!data.length) return []; let splitData = []; let eles = data.length/len;//元素个数 for(let ie=0;ie<eles;ie++){//看有几个要素 splitData.push(data.slice(ie*len,(ie+1)*len)); } splitData = splitData.map(data=>data.map((v,i)=>[Number(v),i]).filter(v=>v[0]>-999));//分离出[数值,时效]//-999.900024 // console.log(splitData); return splitData; } function drawLine(series=[]){ // getTimeSeries(); console.log('绘图'); if(series.length==0) return console.log('空数据'); const tempChart = echarts.init(document.getElementById('show-temp')); let fcTime = utils.getFcTime(); let initTime = moment(fcTime.date+fcTime.hr,'YYYY-MM-DDHH').add(8,'hours');//北京时 let temp = series[0].map(v=>(v[0]-273.15).toFixed(2)); let mn2t = series[1].map(v=>{ if(v[0]===undefined){ return undefined; }else{ return (v[0]-273.15).toFixed(2); } }); let mx2t = series[2].map(v=>{ if(v[0]===undefined){ return undefined; }else{ return (v[0]-273.15).toFixed(2); } }); let xTime = series[0].map(v=>{ const hour = v[1]; return moment(initTime).add(hour,'hours').format('DD-HH'); }); // console.log(mn2t); // 指定图表的配置项和数据 const OptionTemp = { /* title: { text: 'Temp.', // left: 'center' }, */ tooltip: { trigger: 'axis', }, toolbox: { // y: '30px', feature: { dataZoom: { yAxisIndex: 'none' }, restore: {}, //saveAsImage: {} } }, grid: {top:10,bottom:45,right:11,left:25}, dataZoom: [ { show: true, realtime: true, start: 0, end: 80, // handleSize: '50%', height: '20', bottom: '0', }, { type: 'inside', realtime: true, start: 0, end: 80, } ], legend: { y: '-5', data:['Temp','Pre6min','Pre6max'] }, xAxis: { type : 'category', data: xTime, // boundaryGap : false, //splitArea : {show : true}, splitLine:{show: true}, axisLine: {onZero: true}, }, yAxis: [{ name:'℃', type: 'value', scale:true, axisLabel: { formatter: '{value}' }, }, ], series: [ { name: 'Temp', smooth: true, //symbol: 'triangle', //symbolSize: 5, lineStyle: {normal: {color: 'green',width: 2,}},//type: 'dashed' //itemStyle: {normal: {borderWidth: 1,borderColor: 'green',color: 'green'}}, type: 'line', data: temp, }, { name: 'Pre6min', smooth: true, connectNulls: true, symbolSize: 0, lineStyle: {normal: {color: 'blue',width: 1,type: 'dashed'}},//type: 'dashed' type: 'line', data: mn2t, }, { name: 'Pre6max', smooth: true, connectNulls: true, symbolSize: 0, lineStyle: {normal: {color: 'red',width: 1,type: 'dashed'}},//type: 'dashed' type: 'line', data: mx2t, }, ] }; // 使用刚指定的配置项和数据显示图表。 tempChart.setOption(OptionTemp); /** * 风 */ const windChart = echarts.init(document.getElementById('show-wind')); let wind = series[3].map((v,i)=>utils.calWind(v[0],series[4][i][0])); let speed = wind.map(v=>v.speed); let rotation = wind.map(v=>v.rotation); let windData = speed.map((v,i)=>[v,rotation[i],i]); let dims = { speed:0, rotation:1, timeIndex:2, } const optionWind = { /* title: { text: 'Wind', }, */ tooltip: { trigger: 'axis', }, toolbox: { feature: { dataZoom: { yAxisIndex: 'none' }, // restore: {}, //saveAsImage: {} } }, grid: {show:true,top:10,bottom:45,right:11,left:25}, dataZoom: [ { show: true, realtime: true, start: 0, end: 80, // handleSize: '50%', height: '20', bottom: '0', }, { type: 'inside', realtime: true, start: 0, end: 80, } ], legend: { y: '-5', data:['w10m'], }, xAxis: { type : 'category', data: xTime, splitLine:{show: true}, axisLine: {onZero: true}, }, yAxis: { name:'m/s', type: 'value', axisLabel: { formatter: '{value}' }, }, series: [ { name: 'w10m', type: 'line', smooth: true, lineStyle: {normal: {width: 2,}},//type: 'dashed' itemStyle: {normal: {borderWidth: 1,borderColor: 'black',color: 'black'}}, data: speed.map(v=>v.toFixed(1)), }, { type: 'custom', name:'dir', renderItem: utils.renderArrow, encode: { x: dims.timeIndex, y: dims.speed, }, data: windData, z: 10 }, ] }; windChart.setOption(optionWind); /** * 云 */ const cloudChart = echarts.init(document.getElementById('show-cloud')); let totalCloud = series[5].map(v=>v[0]*100); let lowCloud = series[6].map(v=>v[0]*100); const optionCloud = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, toolbox: { feature: { dataZoom: { yAxisIndex: 'none' }, // restore: {},//saveAsImage: {} } }, grid: {show:true,top:10,bottom:45,right:11,left:30}, dataZoom: [ { show: true, realtime: true, start: 0, end: 80, height: '20', bottom: '0', }, { type: 'inside', realtime: true, start: 0, end: 80, } ], legend: { y: '-5', data:['中高云','低云'], }, xAxis: { type : 'category', data: xTime, splitLine:{show: true}, axisLine: {onZero: true}, }, yAxis: { name:'%', type: 'value', axisLabel: { formatter: '{value}' }, }, series: [ { name: '低云', type: 'bar', stack: '云量', data: lowCloud.map(v=>v.toFixed(1)), }, { name: '中高云', type: 'bar', stack: '云量', data: totalCloud.map((v,i)=>(v-lowCloud[i]).toFixed(1)), }, ] }; cloudChart.setOption(optionCloud); /** * 降水 */ const preChart = echarts.init(document.getElementById('show-pre')); let preSeri = series[7]; let precipitaion = preSeri.map((v,i)=>{ let pre = i===0? v[0]: v[0] - preSeri[i-1][0]; //(v[0]*1000).toFixed(1) return (pre*1000).toFixed(1); } ); //let lowCloud = series[6].map(v=>v[0]); const optionPre = { tooltip: { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type : 'shadow' // 默认为直线,可选为:'line' | 'shadow' } }, toolbox: { feature: { dataZoom: { yAxisIndex: 'none' }, } }, grid: {show:true,top:10,bottom:45,right:11,left:30}, dataZoom: [ { show: true, realtime: true, start: 0, end: 80, height: '20', bottom: '0', }, { type: 'inside', realtime: true, start: 0, end: 80, } ], legend: { y: '-5', data:['Precipitaion'], }, xAxis: { type : 'category', data: xTime, splitLine:{show: true}, axisLine: {onZero: true}, }, yAxis: { name:'mm', type: 'value', axisLabel: { formatter: '{value}' }, }, series: [ { name: 'Precipitaion', type: 'bar', stack: 'Rain', data: precipitaion, }, ] }; preChart.setOption(optionPre); } function createPanel(){ //-创建面板-// const panelWrap = document.createElement("div"); panelWrap.setAttribute("id","helper_panel"); panelWrap.setAttribute("class","top_panel show_panel"); panelWrap.innerHTML = '多图模式: '; /* 设置添加对比模式*/ const compareMode = document.createElement('div'); compareMode.innerHTML = `<span class="panel-button" id="open-compare">多起报</span>`; panelWrap.appendChild(compareMode); /* 设置添加多时效模式*/ const mvTime = document.createElement('div'); mvTime.innerHTML = `<span class="panel-button" id="open-mvTime">多时效</span>`; panelWrap.appendChild(mvTime); /* 设置添加多模式 const mvModel = document.createElement('div'); mvModel.innerHTML = `<span class="panel-button" id="open-mvModel">多模式</span>`; panelWrap.appendChild(mvModel);*/ /* 设置添加多图模式 const mvElem = document.createElement('div'); mvElem.innerHTML = `<span class="panel-button" id="open-mv">多要素</span>`; panelWrap.appendChild(mvElem);*/ /* 设置添加点选模式*/ const panelWrap2 = utils.createElement('div',{id:'edit-helper-panel',class:'top_panel show_panel'}); const pointMode = document.createElement('div'); pointMode.innerHTML = `<span class="panel-button">点选模式</span>`; panelWrap2.appendChild(pointMode); pointMode.addEventListener('click', ()=>{toggleSelectMode()}); // pointMode.addEventListener('click', ()=>toggleSelectMode()); /* 设置Lat lon面板*/ // const latLonWarp = document.createElement("span"); // 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>'; // panelWrap2.appendChild(latLonWarp); // const ibody = document.getElementsByTagName("body")[0]; ibody.appendChild(panelWrap); ibody.appendChild(panelWrap2); //-------// //-注册到全局变量-// elemsConfig.latLonInput = { lat:document.getElementById('helper_lat'), lon:document.getElementById('helper_lon'), }; } // 添加面板样式 function createTlinePanel(){ //-创建面板-// const fragment = document.createDocumentFragment(); const panelWrap = document.createElement("div"); panelWrap.setAttribute("id","line_panel"); panelWrap.setAttribute("class","show_panel"); panelWrap.style.display='none'; const infoWrap = document.createElement('div'); infoWrap.setAttribute("id","line_info"); infoWrap.innerHTML = 'EC模式预报<br>纬度:<span></span> 经度:<span></span><span></span>'; panelWrap.appendChild(infoWrap); /* 设置添加temp*/ const tempWrap = document.createElement('div'); tempWrap.innerHTML = `温度<div id="show-temp"></div>`; panelWrap.appendChild(tempWrap); const windWrap = document.createElement('div'); windWrap.innerHTML = `风MSLP<div id="show-wind"></div>`; panelWrap.appendChild(windWrap); const preWrap = document.createElement('div'); preWrap.innerHTML = `降水<div id="show-pre"></div>`; panelWrap.appendChild(preWrap); const cloudWrap = document.createElement('div'); cloudWrap.innerHTML = `云量<div id="show-cloud"></div>`; panelWrap.appendChild(cloudWrap); fragment.appendChild(panelWrap); const ibody = document.getElementsByTagName("body")[0]; ibody.appendChild(fragment); //-------// } function createSelectModePanel(){ //-创建面板-// const fragment = document.createDocumentFragment(); const panelWrap = document.createElement("div"); panelWrap.setAttribute("id","select-mode-panel"); panelWrap.setAttribute("class","show_panel"); panelWrap.style.display='none'; panelWrap.innerHTML = `快捷键[C] -> 单点时间序列`; /*<br> [X] -> 垂直探空; 两次[Ctrl+X] -> 垂直剖面 */ fragment.appendChild(panelWrap); const ibody = document.getElementsByTagName("body")[0]; ibody.appendChild(fragment); /* 设置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); //-------// } //console.log(compareMode.imgDOM); // compareMode.forward(); GM_addStyle(` .show_panel{ z-index:11; font-size: 18px; } .top_panel{ 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; } #helper_panel{ position:absolute; top:5px; left:740px; } #edit-helper-panel{ position:absolute; top:45px; left:740px; } .panel-button{ cursor:pointer; } #select-mode-panel{ position:absolute; top:5px;left:370px; 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;} `); /**暂时隐藏按钮 */ GM_addStyle(`#helper_latLon .fixLoc{display:inline-block;width:55px;height:15px;overflow:hidden;}`); //GM_addStyle(`#helper_latLon{display:none;}`); /**重要添加十字鼠标 */ // GM_addStyle('#pic_frame div{border:1px solid !important;cursor:crosshair !important;}'); createSelectModePanel(); createPanel(); NWP_init(); createTlinePanel(); //创建对比框 function createComparePanel(){ const panel = document.createDocumentFragment(); const mainWrapper = utils.createElement('div',{id:'compare-main',class:'display-none'}); const controlWrapper = utils.createElement('div',{class:'compare-warpper'}); controlWrapper.innerHTML = `<div id="compare-backward" class="my-button">step -6</div><div class="my-button" id="compare-foreward">step +6</div>`; controlWrapper.innerHTML += `<select id="compare-interval"><option value="48">间隔48小时</option> <option selected="selected" value="24">间隔24小时</option> <option value="12">间隔12小时</option></select> <div id="close-compare" class="my-button">关闭对比</div> <span class="info"></span>`; const imgWrapper = utils.createElement('div',{class:'compare-img-main'}); imgWrapper.innerHTML = `<div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div>`; panel.append(mainWrapper); mainWrapper.append(controlWrapper,imgWrapper); //mainWrapper.append(forewardBut,backwardBut,intervalInput); document.body.append(panel); } function createCompareMode(){ const compareHandler = { set(obj, prop, value,receiver){ if(prop === 'interval'){ obj.interval = value; receiver.firstImg = obj.firstImg; //obj.img[1] = obj.img[0] + value; //obj.img[2] = obj.img[0] + value*2; //obj.img[3] = obj.img[0] + value*3; }else if(prop === 'firstHr'){ // console.log(obj.imgInfo.toSource()); // const initURL = obj.imgInfo.url; const date = obj.imgInfo.date; const initDate = obj.imgInfo.initDate; const hour = utils.paddingInt(value,3); const url = obj.imgInfo.getUrl(date,hour,initDate) receiver.firstImg = url; //receiver.interval = obj.interval; }else if(prop === 'imgInfo'){ console.log('设置初始图像为:'+value.url); }else if(prop === 'firstImg'){ const imgList = obj.fit2sameday(value); // console.log(imgList); obj.showInfo(value); imgList.forEach((imgSrc,i)=>{ receiver.img[i] = imgSrc; }) //obj.img[0] = imgList; // obj.img[1] = ; } Reflect.set(obj,prop,value); }, }; const imgHandler = { set(obj, prop, value,receiver){ console.log(`第${Number(prop)+1}个图像地址为${value}`); elemsConfig.compareImgDOM.img[prop].src = value; iImgInfo = utils.getImgNow(value); const initTime = moment(iImgInfo.initDate,'YYYYMMDDHH'); const nowTime = moment(initTime).add(Number.parseInt(iImgInfo.hour)+8,'hours'); elemsConfig.compareImgDOM.info[prop].innerHTML = `起报: ${initTime.format('MM-DD HH')} UTC, 【北京时${nowTime.format('MM月DD日HH时')}(${iImgInfo.hour}h)】${iImgInfo.model}, ${iImgInfo.eleName}`; //console.log(value); //let imgDom = document.querySelectorAll('.compare .imgSrc'); //imgDom[prop].src = value; Reflect.set(obj,prop,value); }, }; let imgSrc = new Proxy([1,2,3,4], imgHandler); const modeProto = { img:imgSrc, firstImg:'', interval:24, foreward(step=6){ this.firstHr = this.firstHr + step; console.log('步进'); }, backward(step=6){ if(this.firstHr - step>=0){ this.firstHr = this.firstHr - step; }else{ alert('不能再退了'); } }, firstHr:1, urlMode(base='http://10.148'){ let url = base; return url; }, initIMG(){// TODO addEventListener('error',(evt)=>{evt.srcElement.src}) let DOMs = document.querySelectorAll('#compare-main .compare-img'); let imgDOM = []; for(let img of DOMs){ img.addEventListener('error',(evt)=>{let ele = evt.target;ele.onerror=null;ele.src='/images/weather/nopic_800_600.jpg';}); imgDOM.push(img); }; elemsConfig.compareImgDOM.img = imgDOM; let infoDOMs = document.querySelectorAll('#compare-main .compare-img-info'); let infoList = []; for(let ele of infoDOMs){ infoList.push(ele); }; elemsConfig.compareImgDOM.info = infoList; //return imgDOM; }, imgInfo:{}, openCompare(){ const wrapper = document.getElementById('compare-main'); //if(wrapper.classList.contains('display-none')) wrapper.classList.remove('display-none') wrapper.classList.remove('display-none'); try{ this.imgInfo = utils.getImgNow(); this.firstHr = Number.parseInt(this.imgInfo.hour); }catch(err){ alert(err.message); console.error(err); } }, closeCompare(){ const wrapper = document.getElementById('compare-main'); //if(wrapper.classList.contains('display-none')) wrapper.classList.remove('display-none') wrapper.classList.add('display-none'); // this.imgInfo = utils.getImgNow(); }, fit2sameday(firstImg){ const interval = this.interval; const firstInfo = utils.getImgNow(firstImg); // console.log(firstImg); // console.log(firstInfo); const imgList = [firstImg]; const iniTime = moment(firstInfo.initDate,'YYYYMMDDHH'); for (let i = 1; i < 4; i++){ const fitTime = moment(iniTime).add(-1*interval*i,'hours'); const iDate = moment(fitTime).format('YYYYMMDD'); const iInit = moment(fitTime).format('YYYYMMDDHH'); const hour = Number.parseInt(firstInfo.hour)+interval*i; // console.log('预报时效'+hour); const iHour = utils.paddingInt(hour,3); const url = firstInfo.getUrl(iDate,iHour,iInit); imgList.push(url); } return imgList; }, changeInterval(evt){ this.interval = Number.parseInt(evt.target.value); console.log(evt); }, showInfo(img){ const controlInfo = document.querySelector('#compare-main .compare-warpper .info'); const imgInfo = utils.getImgNow(img); const nowTime = moment(imgInfo.initDate,'YYYYMMDDHH').add(Number.parseInt(imgInfo.hour)+8,'hours'); controlInfo.innerHTML = ' UTC+8 '+ nowTime.format('YYYY年MM月DD日HH时'); controlInfo.innerHTML += ' | GMT'+ nowTime.add(-8,'hours').format('YYYY-MM-DD HH:00'); }, }; const compareMode = new Proxy(modeProto,compareHandler); return compareMode; } createComparePanel();//创建对比DOM框架 const compareMode = createCompareMode(); compareMode.hook = function(selector='', listener='',callback=()=>{},bindObj=compareMode) { var targetEle = document.querySelector(selector); targetEle.addEventListener(listener,()=>callback.call(bindObj),false); }; compareMode.hook('#compare-backward','click',compareMode.backward,compareMode); compareMode.hook('#compare-foreward','click',compareMode.foreward,compareMode); compareMode.hook('#open-compare','click',compareMode.openCompare,compareMode); compareMode.hook('#close-compare','click',compareMode.closeCompare,compareMode); //compareMode.hook('#compare-interval','change',(evt)=>compareMode.changeInterval(evt),compareMode); document.getElementById('compare-interval').addEventListener('change',(evt)=>compareMode.changeInterval(evt)); compareMode.initIMG(); //compareMode.imgInfo = utils.getImgNow(); GM_addStyle(` #line_panel { position: absolute; top: 5px; right: 5px; background-color: #f5f5f5; border-bottom: 0px solid rgb(20, 20, 20); padding: 5px; 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: black; width: 0px; } #show-temp,#show-wind,#show-pre,#show-cloud{ width: 100%; height:210px; } #show-pre{ display:block; } .full-screen-mode{ float:left; padding-left:10px; } .full-screen-mode #float_icons{ display:none!important; } .full-screen-mode #pic_frame div{ border:1px solid !important;cursor:crosshair !important; } .top_panel div{ display:inline-block; margin-left:5px; margin-right:5px; padding:2px; border: 1px solid white; } .top_panel div:hover{ background-color:orange; } #compare-main, #multiviews-main{ z-index: 12; position: absolute; top: 0px; right: 1%; bottom: 1%; left: 1%; display: flex; flex-direction: column; align-items: center; } #float_icons{ display:none!important; } .compare-warpper { display: flex; justify-content: center; min-width: 1000px; background: white; font-size: 18px; align-items: center; } .compare-img-main { border: 1px dotted red; max-width: 1520px; height: 100%; display: grid; grid-template-columns: 1fr 1fr; background-color: white; } .compare-img-main .compare-img-wrapper { border: 2px solid blue; overflow: hidden; position:relative; } .compare-img-main .compare-img { border: 2px solid yellow; position: relative; top: -50px; height: 120%; } .my-button{ cursor:pointer; margin-left:2px; margin-right:2px; padding:1px; 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; } .my-button:hover{ background-color:orange; } .display-none{ display:none!important; } .compare-img-info { position: absolute; top: 0; left: 0; background-color: rgba(0, 121, 13, 0.6); color: white; padding:2px; font-size:20px; font-family:"Arial","Microsoft YaHei","黑体","STXihei","华文细黑"; } `) //创建多视窗对比框 function createMVPanel(){ const panel = document.createDocumentFragment(); const mainWrapper = utils.createElement('div',{id:'multiviews-main',class:'display-none'}); const controlWrapper = utils.createElement('div',{class:'compare-warpper'}); controlWrapper.innerHTML = `<div id="mv-backward" class="my-button">step -6</div><div class="my-button" id="mv-foreward">step +6</div>`; controlWrapper.innerHTML += `<select id="mv-interval"><option selected="selected" value="6">间隔6小时</option> <option value="12">间隔12小时</option> <option value="24">间隔24小时</option></select> <div id="close-mv" class="my-button">关闭多图模式</div> <span class="info"></span>`; const imgWrapper = utils.createElement('div',{class:'compare-img-main'}); imgWrapper.innerHTML = `<div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div> <div class="compare-img-wrapper"><img class="compare-img" src=""><div class="compare-img-info">init Time</div></div>`; panel.append(mainWrapper); mainWrapper.append(controlWrapper,imgWrapper); //mainWrapper.append(forewardBut,backwardBut,intervalInput); document.body.append(panel); } function createMultiviewsMode(){ const compareHandler = { set(obj, prop, value,receiver){ if(prop === 'interval'){ obj.interval = value; // receiver.firstImg = obj.firstImg; receiver.step = value * obj.imgArr.length; const firstImg = obj.imgArr[0]; let imgInfo = utils.getImgNow(firstImg); let iHour = Number.parseInt(imgInfo.hour); for(let i = 0; i < obj.imgArr.length; i++){ let currentHour = iHour + i * value; const hourString = utils.paddingInt(currentHour); obj.imgArr[i] = utils.getImgUrl(imgInfo.base,imgInfo.date,hourString,imgInfo.initDate); } }else if(prop === 'firstHr'){ const date = obj.imgInfo.date; const initDate = obj.imgInfo.initDate; const hour = utils.paddingInt(value,3); const url = obj.imgInfo.getUrl(date,hour,initDate) receiver.firstImg = url; }else if(prop === 'step'){ // console.log('step'); // obj.step = value; document.getElementById('mv-foreward').innerText = 'step +' + value; document.getElementById('mv-backward').innerText = 'step -' + value; }else if(prop === 'imgInfo'){ console.log('设置初始图像为:'+value.url); }else if(prop === 'firstImg'){ const imgList = obj.fit2sameday(value); // console.log(imgList); obj.showInfo(value); imgList.forEach((imgSrc,i)=>{ receiver.imgArr[i] = imgSrc; }) //obj.img[0] = imgList; // obj.img[1] = ; } Reflect.set(obj,prop,value); }, }; const imgHandler = { set(obj, prop, value){ console.log(`第${Number(prop)+1}个图像地址为${value}`); elemsConfig.mvImgDOM.img[prop].src = value; iImgInfo = utils.getImgNow(value); const initTime = moment(iImgInfo.initDate,'YYYYMMDDHH'); const nowTime = moment(initTime).add(Number.parseInt(iImgInfo.hour)+8,'hours'); // controlInfo.innerHTML = ' UTC+8 '+ nowTime.format('YYYY年MM月DD日HH时'); elemsConfig.mvImgDOM.info[prop].innerHTML = `【北京时${nowTime.format('MM月DD日HH时')}(${iImgInfo.hour}h)】${iImgInfo.model}, ${iImgInfo.eleName}, 起报: ${initTime.format('MM-DD HH')} UTC`; Reflect.set(obj,prop,value); }, }; let imgSrc = new Proxy([1,2,3,4], imgHandler); const modeProto = { imgArr:imgSrc, firstImg:'', interval:6, step:6, foreward(step=6){ // this.firstHr = this.firstHr + step; // console.log(this); this.changeHour(this.step); console.log('步进'); }, backward(step=-6){ let imgInfo = utils.getImgNow(this.imgArr[0]); // console.dir(imgInfo); // console.log(Number.parseInt(imgInfo.hour) - this.step>=0) if(Number.parseInt(imgInfo.hour) - this.step>=0){ this.changeHour(-1*this.step); console.log('步退'); }else{ alert('不能再退了'); } }, changeHour(hr=6){ let hour = parseInt(hr); for(let i = 0; i<this.imgArr.length;i++){ let iInfo = utils.getImgNow(this.imgArr[i]); let newHour = parseInt(iInfo.hour) + hour; // console.log(newHour); this.imgArr[i] = iInfo.getUrl(iInfo.date,utils.paddingInt(newHour),iInfo.initDate); } }, firstHr:1, urlMode(base='http://10.148'){ let url = base; return url; }, initIMG(){// TODO addEventListener('error',(evt)=>{evt.srcElement.src}) let DOMs = document.querySelectorAll('#multiviews-main .compare-img'); let imgDOM = []; for(let img of DOMs){ img.addEventListener('error',(evt)=>{let ele = evt.target;ele.onerror=null;ele.src='/images/weather/nopic_800_600.jpg';}); imgDOM.push(img); }; elemsConfig.mvImgDOM.img = imgDOM; let infoDOMs = document.querySelectorAll('#multiviews-main .compare-img-info'); let infoList = []; for(let ele of infoDOMs){ infoList.push(ele); }; elemsConfig.mvImgDOM.info = infoList; //return imgDOM; }, imgInfo:{}, openCompare(){ const wrapper = document.getElementById('multiviews-main'); //if(wrapper.classList.contains('display-none')) wrapper.classList.remove('display-none') wrapper.classList.remove('display-none'); try{ let imgInfo = utils.getImgNow(); if(elemsConfig.mvImgDOM.mode === 'multiElem'){ for(let i = 0; i < this.imgArr.length; i++){ const iPatt = elemsConfig.mvImgDOM.matchPattens[i]; // console.log(iPatt); const iMatch = utils.matchImgPattern(iPatt); console.log(iMatch); this.imgArr[i] = utils.getImgUrl(iMatch.base,imgInfo.date,imgInfo.hour,imgInfo.initDate); } }else if(elemsConfig.mvImgDOM.mode === 'multiTime'){ this.step = this.interval * this.imgArr.length; let iHour = Number.parseInt(imgInfo.hour); for(let i = 0; i < this.imgArr.length; i++){ let currentHour = iHour + i * this.interval; const hourString = utils.paddingInt(currentHour); this.imgArr[i] = utils.getImgUrl(imgInfo.base,imgInfo.date,hourString,imgInfo.initDate); } } }catch(err){ alert(err.message); console.error(err); } }, closeCompare(){ const wrapper = document.getElementById('multiviews-main'); //if(wrapper.classList.contains('display-none')) wrapper.classList.remove('display-none') wrapper.classList.add('display-none'); // this.imgInfo = utils.getImgNow(); }, fit2sameday(firstImg){ const interval = this.interval; const firstInfo = utils.getImgNow(firstImg); // console.log(firstImg); // console.log(firstInfo); const imgList = [firstImg]; const iniTime = moment(firstInfo.initDate,'YYYYMMDDHH'); for (let i = 1; i < 4; i++){ const fitTime = moment(iniTime).add(-1*interval*i,'hours'); const iDate = moment(fitTime).format('YYYYMMDD'); const iInit = moment(fitTime).format('YYYYMMDDHH'); const hour = Number.parseInt(firstInfo.hour)+interval*i; // console.log('预报时效'+hour); const iHour = utils.paddingInt(hour,3); const url = firstInfo.getUrl(iDate,iHour,iInit); imgList.push(url); } return imgList; }, changeInterval(evt){ this.interval = Number.parseInt(evt.target.value); // console.log(evt); }, showInfo(img){ const controlInfo = document.querySelector('#multiviews-main .compare-warpper .info'); const imgInfo = utils.getImgNow(img); const nowTime = moment(imgInfo.initDate,'YYYYMMDDHH').add(Number.parseInt(imgInfo.hour)+8,'hours'); controlInfo.innerHTML = ' UTC+8 '+ nowTime.format('YYYY年MM月DD日HH时'); controlInfo.innerHTML += ' | GMT'+ nowTime.add(-8,'hours').format('YYYY-MM-DD HH:00'); }, }; const compareMode = new Proxy(modeProto,compareHandler); return compareMode; } createMVPanel();//创建对比DOM框架 const mvMode = createMultiviewsMode(); mvMode.hook = function(selector='', listener='',callback=()=>{},bindObj=mvMode) { var targetEle = document.querySelector(selector); targetEle.addEventListener(listener,()=>callback.call(bindObj),false); }; mvMode.hook('#mv-backward','click',mvMode.backward,mvMode); mvMode.hook('#mv-foreward','click',mvMode.foreward,mvMode); // mvMode.hook('#open-mv','click',mvMode.openCompare,mvMode); mvMode.hook('#close-mv','click',mvMode.closeCompare,mvMode); //compareMode.hook('#compare-interval','change',(evt)=>compareMode.changeInterval(evt),compareMode); document.getElementById('mv-interval').addEventListener('change',(evt)=>mvMode.changeInterval(evt)); mvMode.initIMG(); let openMvTime = document.getElementById('open-mvTime'); // console.log(openMvTime) openMvTime.addEventListener('click',()=>{ elemsConfig.mvImgDOM.mode = 'multiTime'; mvMode.openCompare(); }); // let openMv = document.getElementById('open-mv'); // openMv.addEventListener('click',()=>{ // elemsConfig.mvImgDOM.mode = 'multiElem'; // mvMode.openCompare(); // }); /** * 地图单点标志 */ function createMapIndicator(){ let wrapDiv = document.querySelector('#main_frame'); let pointer = utils.createElement('div',{id:'map-pointer',draggable:'true',class:'display-none'}); pointer.innerHTML = '<span class="water-dot scale-lg"></span>' wrapDiv.insertAdjacentElement('afterbegin', pointer); //保存位置的状态值 var pos={ // parent_top:0, // parent_left:0, // cur_top:0, // cur_left:0, x_diff:0,// 鼠标相对目标物的位置 y_diff:0, } function allowDrop(ev){ //ev是事件对象 ev.preventDefault(); //取消事件已经关联的默认活动 } function drag(ev){ //dataTransfer是一个媒介,将目标对象放入媒介 //dataTransfer对象用来保存被拖动的数据,仅在拖动事件有效 //这里将被拖动元素的id保存为名为Text的键值对中 ev.dataTransfer.setData("Pointer",ev.target.id); //获取被拖动对象相对于上层元素顶边和左边位置 let mouseXY = utils.getElemRelPos(ev.currentTarget,ev.clientX, ev.clientY); // let eStyle = getComputedStyle(ev.target); pos.x_diff = mouseXY.x; pos.y_diff = mouseXY.y; // console.log('current'); // console.log(ev.currentTarget); // console.log(ev.target); // pos.parent_top=ev.target.offsetTop; // pos.parent_left=ev.target.offsetLeft; // pos.cur_top=ev.screenY; // pos.cur_left=ev.screenX; // console.log(mouseXY); // console.log(eStyle.marginLeft); // console.log(ev); } function drop(ev){ var new_top,new_left; ev.preventDefault(); // alert(2); var data=ev.dataTransfer.getData("Pointer"); //从媒介中获取目标对象 var elem=document.getElementById(data); //这里不能这样使用,因为offset*的值是只读的,不能改变 // elem.offsetLeft=v.parent_left+ev.screenX-v.cur_left+"px"; // elem.offsetTop=v.parent_top+ev.screenY-v.cur_top+"px"; let mouseXY = utils.getElemRelPos(ev.target,ev.clientX, ev.clientY); // let eStyle = getComputedStyle(elem); // console.log(mouseXY); // console.log(mouseXY.x+eStyle.width); // 此处有微小的位移 elem.style.marginLeft = mouseXY.x - pos.x_diff + 35.8 + "px"; elem.style.marginTop = mouseXY.y - pos.y_diff + "px"; // console.log([parseFloat(elem.style.marginTop)+23.2 + 12.3,parseFloat(elem.style.marginLeft)+10]); let newMouseXY = { x:parseFloat(elem.style.marginLeft) - 29.31, // x:parseFloat(elem.style.marginLeft) + 5.0, y:parseFloat(elem.style.marginTop) + 33.066, }; const loc = helperConfig.matchLoc(newMouseXY, helperConfig.matchParam); elemsConfig.latLonInput.lat.innerHTML = loc.lat; // mouseXY.y elemsConfig.latLonInput.lon.innerHTML = loc.lon; // mouseXY.x elemsConfig.fixPoint = {lat: loc.lat, lon: loc.lon}; // console.log(elemsConfig.fixPoint); utils.showTimeSeries(elemsConfig.fixPoint); // elem.style.marginLeft=pos.parent_left+ev.screenX-pos.cur_left-1+"px"; // elem.style.marginTop=pos.parent_top+ev.screenY-pos.cur_top-23.2+"px"; /* TODO const imgXY = { x: elem.style.marginLeft; y: elem.style.marginTop; } const loc = helperConfig.matchLoc(imgXY, helperConfig.matchParam); elemsConfig.pointerPoint.lat = loc.lat; elemsConfig.pointerPoint.lon = loc.lon; utils.showTimeSeries(elemsConfig.pointerPoint); */ } pointer.addEventListener('dragstart',drag); wrapDiv.addEventListener('dragover',allowDrop); wrapDiv.addEventListener('drop',drop); } createMapIndicator(); GM_addStyle(` .water-dot { position: relative; display: inline-block; height: 26px; width: 16px; } .water-dot:before, .water-dot:after { content: ''; position: absolute; display: inline-block; } .water-dot:before { left: 0; width: 16px; height: 16px; border-radius: 50%; background-image: repeating-radial-gradient(8px 8px at 50% 8px, transparent 0%, transparent 3px, #dd1010 3px, #dd1010 100%); } .water-dot:after { bottom: 0; left: 50%; border: 14px solid #dd1010; border-bottom-width: 0; border-right-width: 7px; border-left-width: 7px; transform: translate(-50%,0); border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } .water-dot.scale-lg{ transform: scale(1.5); } `); /** * 经纬度到图像位置 */ function latlon2XY(loc={lat:10, lon:120}){ const imgXY = helperConfig.matchImgXY(loc, helperConfig.matchParam); return imgXY; } function createCrossSectionCanvas(){ // let wrapDiv = document.querySelector('#main_frame'); let wrapDiv = document.querySelector('#pic_frame'); const cv = utils.createElement('canvas',{id:'cv-draw-line',width:"800", height:"600",style:"border:1px solid #d3d3d3;"}); wrapDiv.insertAdjacentElement('afterbegin', cv); const ctx = cv.getContext('2d'); const line = {start:[0,0],end:[0,0],init:false}; const cvMsMove = function(ev){ // console.log('test2'); ctx.clearRect(0,0,800,600); ctx.beginPath(); ctx.lineWidth=3; let mouseXY = utils.getElemRelPos(ev.target,ev.clientX, ev.clientY); line.end = [mouseXY.x, mouseXY.y]; ctx.moveTo(...line.start); ctx.lineTo(...line.end); ctx.strokeStyle="green"; ctx.stroke(); // console.log(line); } const cvMsClick = function (ev) { // console.log('test'); if(line.init){ cv.removeEventListener('mousemove',cvMsMove, false); line.init = false; }else{ // ctx.beginPath(); // ctx.lineWidth=10; // ctx.moveTo(0,0); // ctx.lineTo(50,50); // ctx.strokeStyle="green"; // ctx.stroke(); let mouseXY = utils.getElemRelPos(ev.target,ev.clientX, ev.clientY); line.start = [mouseXY.x, mouseXY.y]; cv.addEventListener('mousemove',cvMsMove, false); line.init = true; } } cv.addEventListener('click', cvMsClick, false); ctx.fillStyle = 'rgba(255,255,255,0)'; } setTimeout(()=>{createCrossSectionCanvas()},5000); GM_addStyle(`.show_panel{z-index:11;} #pic_frame,#main_frame{ position:relative; } #map-pointer { position: absolute; top: 22px; left: 0px; /*background-color: rgba(0, 152, 50, 0.7);*/ color: white; /*width:15px;*/ /*height:15px;*/ display:inline-block; padding:2px; z-index:10; cursor:pointer; } #cv-draw-line{ position: absolute; z-index:9; left:0px; cursor:crosshair; display:none } `);