简体   繁体   English

将 CytoscapeJs 与 LeafletJs 集成

[英]Integrating CytoscapeJs with LeafletJs

I have made a graph component in CytoscapeJS and want to have a map as an overlay.我在 CytoscapeJS 中制作了一个图形组件,并希望将 map 作为叠加层。 Basically I want to represent the nodes based on their co-ordinates on Map (using LeafletJs).基本上我想根据 Map 上的坐标来表示节点(使用 LeafletJs)。 I have looked into the plugin (cytoscape-mapbox-gl by zakjan) and cytoscape-leaf extension (using this currently).我研究了插件(zakjan 的 cytoscape-mapbox-gl)和 cytoscape-leaf 扩展(目前正在使用)。

I am getting this error:我收到此错误:

Uncaught TypeError: obj.attachEvent is not a function Uncaught TypeError: Cannot read properties of undefined (reading 'lat') Uncaught Error: Map container is already initialized. Uncaught TypeError: obj.attachEvent is not a function Uncaught TypeError: Cannot read properties of undefined (reading 'lat') 未捕获错误:Map 容器已初始化。

I only want to integrate CytoscapeJs with LeafletJS.我只想将 CytoscapeJs 与 LeafletJS 集成。 I don't want to add any tile layer.我不想添加任何图块层。

Followed all the steps on the Cytoscape-leaf plugin documentation.遵循 Cytoscape-leaf 插件文档中的所有步骤。 I have registered the function, created the instance, added the co-ordinates in the data object,rendered the Map component alongside cytoscape component, Added the lat,lng field in the data object for cytoscape node(Node Position).我已经注册了 function,创建了实例,在数据 object 中添加了坐标,在 cytoscape 组件旁边渲染了 Map 组件,在数据 object 中为 cytoscape 节点(节点位置)添加了 lat,lng 字段。

cytoscape.use( leaflet );
   const map = useRef();
data: {
          id: ele.nodeAddr,
          label: `IP-${ele.nodeAddr}`,
          icon:Server,
          type:'parentNode',
          status:ele.status,
          lat:19.5,
          lng:72.8777,
          
        }
 const options = {
          
          container: map.current,
        
          // the data field for latitude
          latitude: 'lat',
        
          // the data field for longitude
          longitude: 'lng'
        };
        
        const leaf = cy.leaflet(options);
<div
          ref={divRef}
          style={{
            border: "1px solid",
            backgroundColor: "#f5f6fe",
            height: '600px',
          }}
        >
           <div ref={map}></div>

My answer is independent of your code and your intended plugins you want to use with cytoscape .我的回答与您的代码和您想要与cytoscape一起使用的预期plugins无关。 It may not answer your question, but it works to some extent that I consider it a good start to use cytoscapeJS within leaflet.它可能无法回答您的问题,但它在某种程度上起作用,我认为这是在 leaflet 中使用 cytoscapeJS 的良好开端。

One issue that I found, it wont work with browsers on iOS or ipadOS .我发现的一个问题是,它不适用于iOSipadOS上的浏览器。 I am sorry about that.对此我感到很抱歉。 Help is welcome to solve the issues why Webkit based browsers on iOS/ipadOS do not handle cytoscape's graph like Chrome browsers on android/windows.欢迎帮助解决 iOS/ipadOS 上基于 Webkit 的浏览器无法像 android/windows 上的 Chrome 浏览器那样处理 cytoscape 图形的问题。

Code:代码:

 const base_dc = 0.027589; const lon_ext = 0.5436; const lat_ext = 0.5436; const lonmin = 100.3257; const latmin = 13.4978; const lon_cor = lon_ext * base_dc; const lonmax = lonmin + lon_ext; const lonmid = (lonmin + lonmax) / 2; const lonmax2 = lonmax + lon_cor; const latmax = latmin + lat_ext; const latmid = (latmin + latmax) / 2; const latlng = { lat: latmin, lng: lonmin }; const latlng2 = { lat: latmax, lng: lonmax2 }; const clatlng = { lat: latmid, lng: lonmid }; const cbottom = { lat: latmin, lng: lonmid }; var zoom = 9; const myRenderer = L.canvas({ padding: 0.0 }); //svg or canvas /* Cytoscape global vars */ // must match SVG viewbox w h. // and width, height of #cyOnSvg DIV const cy_size = 1600; const params = { width: cy_size, height: cy_size, latmin: latmin, latmax: latmax, lonmin: lonmin, lonmax: lonmax2 }; // Update CSS to use new cy_size let root = document.documentElement; root.style.setProperty("--svg-width", cy_size + "px"); root.style.setProperty("--svg-height", cy_size + "px"); /* choice of maps */ var mymap = L.map("mapid", { renderer: myRenderer, preferCanvas: false }).setView(clatlng, zoom); L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: "Map data &copy; OpenStreetMap contributors" }).addTo(mymap); const svg_pin = '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,11.5A2.5,2.5 0 0,1 9.5,9A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 14.5,9A2.5,2.5 0 0,1 12,11.5M12,2A7,7 0 0,0 5,9C5,14.25 12,22 12,22C12,22 19,14.25 19,9A7,7 0 0,0 12,2Z" fill="firebrick"></path></svg>'; const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin); const svgpin_Icon = L.icon({ iconUrl: svgpin_Url, iconSize: [24, 24], iconAnchor: [12, 24], popupAnchor: [0, -22] }); var marker2 = L.marker(latlng2, { renderer: myRenderer, icon: svgpin_Icon //draggable: true, //autoPan: true }).addTo(mymap); marker2.bindPopup("<b>Control_UR</b>").openPopup(); marker2.openPopup(); var marker0 = L.marker(latlng, { renderer: myRenderer, icon: svgpin_Icon }).addTo(mymap); marker0.bindPopup("<b>Control_LL</b>").openPopup(); marker0.openPopup(); /* Embed SVG Element in the web page */ let svgElem = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgElem.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgElem.setAttribute("id", "Svg0"); svgElem.setAttribute("preserveAspectRatio", "xMinYMax slice"); svgElem.setAttribute("viewBox", `0 0 ${cy_size} ${cy_size}`); /* SVGOverlay with foreignObject-div-text */ svgElem.innerHTML = `<foreignObject x="0" y="0" width="100%" height="100%"> <div id="cyOnSvg" style="background-color:rgba(200,200,200,0.25);padding:0;"></div> <div id="upperlefttext">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div> </foreignObject>`; // Note: lonmax2 (=lonmax + correction) const svgElementBounds = [ [latmin, lonmin], [latmax, lonmax2] ]; const svgobj = L.svgOverlay(svgElem, svgElementBounds, { renderer: myRenderer, zIndex: 15, opacity: 0.65, interactive: false }).addTo(mymap); //svgobj.bindPopup("SVG vector layer"); //var draggable = new L.Draggable(svgElem); //draggable.enable(); //make draggable (must set=> interactive: true) /* SVG OK */ /* set events */ mymap.on("click", onMapClick); //svgobj.on("click", onSvgClick); /* other useful settings */ mymap.scrollWheelZoom.disable(); const popup = L.popup(); //leaflet popup object function onMapClick(e) { popup.setLatLng(e.latlng).setContent(e.latlng.toString()).openOn(mymap); } /* -------cytoscape-------- */ function lnglat2xy(lon, lat, pars) { //let w = pars.width; //let h = pars.height; let L = pars.lonmax - pars.lonmin; //lonmax2-lonmin let B = pars.latmax - pars.latmin; let y = ((B - (lat - pars.latmin)) * pars.height) / B; let x = ((lon - pars.lonmin) * pars.width) / L; return { x: x, y: y }; } const lngMidLatMid = lnglat2xy( (lonmin + lonmax2) / 2, (latmin + latmax) / 2, params ); //console.log("lngMidLatMid: "+lngMidLatMid.x+"; "+lngMidLatMid.y); const bkk = lnglat2xy(100.5348327, 13.7567441, params); const bda = lnglat2xy(100.4094999, 13.7108552, params); const hoc = lnglat2xy(100.6076988, 13.5676449, params); const han = lnglat2xy(100.7522551, 13.6982529, params); const nay = lnglat2xy(100.4081876, 13.8923587, params); var cy = cytoscape({ container: document.querySelector("#cyOnSvg"), elements: { nodes: [ { data: { id: "LL", name: "LowerLeft" }, classes: "controlpoint", position: { x: 0, y: cy_size } }, { data: { id: "UL", name: "UpperLeft" }, classes: "controlpoint", position: { x: 0, y: 0 } }, { data: { id: "UR", name: "UpperRight" }, classes: "controlpoint", position: { x: cy_size, y: 0 } }, { data: { id: "LR", name: "LowerRight" }, classes: "controlpoint", position: { x: cy_size, y: cy_size } }, /* Nodes with (long,lat) coordinates */ { data: { id: "bkk", name: "A8" }, position: { x: bkk.x, y: bkk.y } }, { data: { id: "bda", name: "BL38" }, position: { x: bda.x, y: bda.y } }, { data: { id: "hoc", name: "E23" }, position: { x: hoc.x, y: hoc.y } }, { data: { id: "han", name: "A1" }, position: { x: han.x, y: han.y } }, { data: { id: "nay", name: "PP01" }, position: { x: nay.x, y: nay.y } }, ], edges: [ { data: { id: "LLUR", source: "LL", target: "UR" }, classes: "controlline" }, { data: { id: "ULLR", source: "UL", target: "LR" }, classes: "controlline" }, { data: { id: "bkk_bda", source: "bkk", target: "bda" }, classes: "edge" }, { data: { id: "bkk_han", source: "bkk", target: "han" }, classes: "edge" }, { data: { id: "bkk_hoc", source: "bkk", target: "hoc" }, classes: "edge" }, { data: { id: "bkk_nay", source: "bkk", target: "nay" }, classes: "edge" }, ] }, style: [ { selector: "node", style: { shape: "hexagon", width: "50px", height: "50px", "background-color": "blue", label: "data(name)", opacity: 1, "text-background-color": "yellow" } }, { selector: ".controlline", style: { width: "2px", "line-color": "black", opacity: 1 } }, { selector: ".edge", style: { width: "3px", "line-color": "red", opacity: 1 } }, ], layout: { name: "preset" } }); cy.pan({ x: 0.0, y: 0.0 }); //match TOP-LEFT corner cy.fit(cy.$("#LLUR"));
 :root { --svg-width: 1600px; --svg-height: 1600px; } #cyOnSvg{ /* foreignObject, and canvas */ position: absolute; width: 100%; //5%; height: 100%; //10%; top: 0; left: 0; background-color: lightgray; overflow: visible; margin: 0; padding: 0; } #Svg0{ /* svg elem */ position: absolute; width: var(--svg-width); height: var(--svg-height); top: 0; left: 0; display: block; background-color: lightyellow; /*border: 0.5px solid gray; border-style: dashed;*/ overflow: visible; margin: 0; padding: 0; } #mapid { height: 480px; width: 480px; } #lorem { width: var(--svg-width); position: absolute; background-color: gray; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.9.2/cytoscape.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-browser/0.1.0/jquery.browser.min.js"></script> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" /> <div id="mapid"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM