@graphty/graph-io 0.3.48 → 0.3.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{approximations-C2riR4NT.js → approximations-BRXsll0T.js} +2 -2
- package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-BRXsll0T.js.map} +1 -1
- package/dist/chunks/bends-BGXjv_U4.js +129 -0
- package/dist/chunks/bends-BGXjv_U4.js.map +1 -0
- package/dist/chunks/{block-Cu22ewuS.js → block-yl0f_qLO.js} +931 -164
- package/dist/chunks/block-yl0f_qLO.js.map +1 -0
- package/dist/chunks/choose-CczZJaX_.js +717 -0
- package/dist/chunks/choose-CczZJaX_.js.map +1 -0
- package/dist/chunks/{codes-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
- package/dist/chunks/codes-BE2xir2k.js.map +1 -0
- package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
- package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
- package/dist/chunks/{context-cgmmOxZ2.js → context-DizmppHy.js} +5 -4
- package/dist/chunks/{context-cgmmOxZ2.js.map → context-DizmppHy.js.map} +1 -1
- package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
- package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
- package/dist/chunks/{credentials-BiQsnMTb.js → credentials-CmvJXYeH.js} +67 -16
- package/dist/chunks/credentials-CmvJXYeH.js.map +1 -0
- package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
- package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
- package/dist/chunks/descriptor-B28U25x4.js +60 -0
- package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
- package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-Dhez_Cew.js} +11 -2
- package/dist/chunks/descriptor-Dhez_Cew.js.map +1 -0
- package/dist/chunks/{emit-CD8xnY8s.js → emit-7Jkpg0yd.js} +1788 -133
- package/dist/chunks/emit-7Jkpg0yd.js.map +1 -0
- package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
- package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
- package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
- package/dist/chunks/export-Cha4dRFz.js.map +1 -0
- package/dist/chunks/{exporter-ChjL5fmP.js → exporter-1Ajud15J.js} +9 -8
- package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-1Ajud15J.js.map} +1 -1
- package/dist/chunks/{exporter-BIdaoIgh.js → exporter-B6yvL3wy.js} +7 -7
- package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-B6yvL3wy.js.map} +1 -1
- package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
- package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
- package/dist/chunks/{exporter-DtVU80Fa.js → exporter-CA5q8ROP.js} +9 -8
- package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-CA5q8ROP.js.map} +1 -1
- package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-CQQZFJ2v.js} +1284 -156
- package/dist/chunks/exporter-CQQZFJ2v.js.map +1 -0
- package/dist/chunks/format-BXiAb-1h.js +408 -0
- package/dist/chunks/format-BXiAb-1h.js.map +1 -0
- package/dist/chunks/{generic-CP6YD34u.js → generic-Dc21MAdg.js} +387 -31
- package/dist/chunks/generic-Dc21MAdg.js.map +1 -0
- package/dist/chunks/{importer-B87_fmVx.js → importer-C6NVpCXp.js} +327 -84
- package/dist/chunks/importer-C6NVpCXp.js.map +1 -0
- package/dist/chunks/{importer-DPZDN40-.js → importer-CKFe4q54.js} +25 -17
- package/dist/chunks/importer-CKFe4q54.js.map +1 -0
- package/dist/chunks/{importer-Bji2MeWr.js → importer-CKbUbsJA.js} +13 -10
- package/dist/chunks/{importer-Bji2MeWr.js.map → importer-CKbUbsJA.js.map} +1 -1
- package/dist/chunks/{importer-CB_zV5_L.js → importer-ClCsdgTJ.js} +208 -1104
- package/dist/chunks/importer-ClCsdgTJ.js.map +1 -0
- package/dist/chunks/{importer-e3huMZbm.js → importer-CyVZTrf0.js} +14 -10
- package/dist/chunks/importer-CyVZTrf0.js.map +1 -0
- package/dist/chunks/{importer-CVT-JyDE.js → importer-DgG4v1Ms.js} +1537 -355
- package/dist/chunks/importer-DgG4v1Ms.js.map +1 -0
- package/dist/chunks/{importer-Cyy6UseH.js → importer-asFUrIsj.js} +66 -13
- package/dist/chunks/importer-asFUrIsj.js.map +1 -0
- package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
- package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
- package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
- package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
- package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-IVRq2Uoo.js} +282 -74
- package/dist/chunks/lexicon-IVRq2Uoo.js.map +1 -0
- package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
- package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
- package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
- package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
- package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
- package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
- package/dist/chunks/round-trip-Cy3_SHRZ.js +79 -0
- package/dist/chunks/round-trip-Cy3_SHRZ.js.map +1 -0
- package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-BXwVbza3.js} +5 -5
- package/dist/chunks/sigv4-BXwVbza3.js.map +1 -0
- package/dist/chunks/{styles-CaABMoO1.js → styles-CAVmBLgp.js} +1237 -138
- package/dist/chunks/styles-CAVmBLgp.js.map +1 -0
- package/dist/chunks/styles-CPczw1Jz.js +1928 -0
- package/dist/chunks/styles-CPczw1Jz.js.map +1 -0
- package/dist/chunks/styles-boK6Ln54.js +2847 -0
- package/dist/chunks/styles-boK6Ln54.js.map +1 -0
- package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-XeFBQ6VS.js} +506 -175
- package/dist/chunks/styles-yed-XeFBQ6VS.js.map +1 -0
- package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
- package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
- package/dist/csv.js +7 -7
- package/dist/cx.js +2 -2
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +8 -4
- package/dist/dot.js.map +1 -1
- package/dist/gexf.js +42 -12
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +848 -194
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +230 -193
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -3
- package/dist/json.js +3 -2
- package/dist/neo4j.js +6 -6
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/positions.js +45 -3
- package/dist/positions.js.map +1 -1
- package/dist/sources-cypher.js +141 -23
- package/dist/sources-cypher.js.map +1 -1
- package/dist/sources-ndex.js +2 -2
- package/dist/sources-rest.js +32 -6
- package/dist/sources-rest.js.map +1 -1
- package/dist/sources-sparql.d.ts +1 -0
- package/dist/sources-sparql.js +439 -0
- package/dist/sources-sparql.js.map +1 -0
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +5 -1
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts +24 -1
- package/dist/src/formats/cx/styles.d.ts.map +1 -1
- package/dist/src/formats/cx/styles.js +117 -11
- package/dist/src/formats/cx/styles.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +1 -0
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/styles.d.ts.map +1 -1
- package/dist/src/formats/cx2/styles.js +3 -1
- package/dist/src/formats/cx2/styles.js.map +1 -1
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +1 -0
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/styles.d.ts +2 -0
- package/dist/src/formats/cys/styles.d.ts.map +1 -1
- package/dist/src/formats/cys/styles.js +15 -7
- package/dist/src/formats/cys/styles.js.map +1 -1
- package/dist/src/formats/dot/drawing.d.ts +98 -0
- package/dist/src/formats/dot/drawing.d.ts.map +1 -0
- package/dist/src/formats/dot/drawing.js +734 -0
- package/dist/src/formats/dot/drawing.js.map +1 -0
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +34 -2
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts +6 -1
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +170 -33
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +3 -1
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +2 -1
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/label-places.d.ts +41 -0
- package/dist/src/formats/dot/label-places.d.ts.map +1 -0
- package/dist/src/formats/dot/label-places.js +185 -0
- package/dist/src/formats/dot/label-places.js.map +1 -0
- package/dist/src/formats/dot/names.d.ts +13 -0
- package/dist/src/formats/dot/names.d.ts.map +1 -1
- package/dist/src/formats/dot/names.js +13 -0
- package/dist/src/formats/dot/names.js.map +1 -1
- package/dist/src/formats/dot/record.d.ts +50 -0
- package/dist/src/formats/dot/record.d.ts.map +1 -0
- package/dist/src/formats/dot/record.js +275 -0
- package/dist/src/formats/dot/record.js.map +1 -0
- package/dist/src/formats/dot/styles.d.ts +72 -2
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +1500 -119
- package/dist/src/formats/dot/styles.js.map +1 -1
- package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
- package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
- package/dist/src/formats/gexf/dialog-metrics.js +59 -0
- package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
- package/dist/src/formats/gexf/importer.d.ts +7 -0
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +41 -5
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/preview.d.ts +77 -0
- package/dist/src/formats/gexf/preview.d.ts.map +1 -0
- package/dist/src/formats/gexf/preview.js +191 -0
- package/dist/src/formats/gexf/preview.js.map +1 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +2 -1
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +58 -31
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +848 -225
- package/dist/src/formats/gexf/styles.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +5 -2
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +258 -71
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +1 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +1 -1
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/positions.d.ts +7 -0
- package/dist/src/formats/gml/positions.d.ts.map +1 -1
- package/dist/src/formats/gml/positions.js +29 -7
- package/dist/src/formats/gml/positions.js.map +1 -1
- package/dist/src/formats/gml/styles.d.ts.map +1 -1
- package/dist/src/formats/gml/styles.js +754 -102
- package/dist/src/formats/gml/styles.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-plain.js +6 -10
- package/dist/src/formats/graphml/styles-plain.js.map +1 -1
- package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yed.js +695 -164
- package/dist/src/formats/graphml/styles-yed.js.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.js +431 -64
- package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +3 -3
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +16 -6
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts +3 -2
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +39 -5
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +13 -2
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +42 -6
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/index.d.ts +1 -1
- package/dist/src/formats/json/index.d.ts.map +1 -1
- package/dist/src/formats/json/index.js +1 -1
- package/dist/src/formats/json/index.js.map +1 -1
- package/dist/src/formats/json/positions.d.ts +5 -2
- package/dist/src/formats/json/positions.d.ts.map +1 -1
- package/dist/src/formats/json/positions.js +20 -4
- package/dist/src/formats/json/positions.js.map +1 -1
- package/dist/src/formats/json/styles.d.ts +12 -1
- package/dist/src/formats/json/styles.d.ts.map +1 -1
- package/dist/src/formats/json/styles.js +1843 -136
- package/dist/src/formats/json/styles.js.map +1 -1
- package/dist/src/formats/pajek/draw.d.ts +104 -0
- package/dist/src/formats/pajek/draw.d.ts.map +1 -0
- package/dist/src/formats/pajek/draw.js +382 -0
- package/dist/src/formats/pajek/draw.js.map +1 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +70 -51
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +9 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +233 -102
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +1 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts +15 -7
- package/dist/src/formats/pajek/styles.d.ts.map +1 -1
- package/dist/src/formats/pajek/styles.js +1395 -114
- package/dist/src/formats/pajek/styles.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts +10 -1
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +26 -2
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +1 -0
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +65 -5
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts +23 -3
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
- package/dist/src/formats/xgmml/styles.js +277 -60
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/positions/convert.d.ts.map +1 -1
- package/dist/src/positions/convert.js +11 -1
- package/dist/src/positions/convert.js.map +1 -1
- package/dist/src/positions/extract.d.ts.map +1 -1
- package/dist/src/positions/extract.js +53 -1
- package/dist/src/positions/extract.js.map +1 -1
- package/dist/src/positions/index.d.ts +1 -1
- package/dist/src/positions/index.d.ts.map +1 -1
- package/dist/src/positions/types.d.ts +59 -0
- package/dist/src/positions/types.d.ts.map +1 -1
- package/dist/src/sources/builtins.d.ts +1 -1
- package/dist/src/sources/builtins.d.ts.map +1 -1
- package/dist/src/sources/builtins.js +8 -2
- package/dist/src/sources/builtins.js.map +1 -1
- package/dist/src/sources/context.d.ts.map +1 -1
- package/dist/src/sources/context.js +1 -0
- package/dist/src/sources/context.js.map +1 -1
- package/dist/src/sources/credentials.d.ts +50 -1
- package/dist/src/sources/credentials.d.ts.map +1 -1
- package/dist/src/sources/credentials.js +69 -0
- package/dist/src/sources/credentials.js.map +1 -1
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
- package/dist/src/sources/cypher/descriptor.js +5 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -1
- package/dist/src/sources/cypher/index.d.ts.map +1 -1
- package/dist/src/sources/cypher/index.js +125 -18
- package/dist/src/sources/cypher/index.js.map +1 -1
- package/dist/src/sources/cypher/params.d.ts +1 -1
- package/dist/src/sources/cypher/params.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.d.ts +17 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.js +31 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -1
- package/dist/src/sources/ids.d.ts +5 -0
- package/dist/src/sources/ids.d.ts.map +1 -1
- package/dist/src/sources/ids.js +5 -0
- package/dist/src/sources/ids.js.map +1 -1
- package/dist/src/sources/params.d.ts +3 -0
- package/dist/src/sources/params.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.js +9 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -1
- package/dist/src/sources/rest/openalex.d.ts +4 -2
- package/dist/src/sources/rest/openalex.d.ts.map +1 -1
- package/dist/src/sources/rest/openalex.js +4 -2
- package/dist/src/sources/rest/openalex.js.map +1 -1
- package/dist/src/sources/rest/source.d.ts.map +1 -1
- package/dist/src/sources/rest/source.js +38 -0
- package/dist/src/sources/rest/source.js.map +1 -1
- package/dist/src/sources/run.d.ts +2 -0
- package/dist/src/sources/run.d.ts.map +1 -1
- package/dist/src/sources/run.js +30 -3
- package/dist/src/sources/run.js.map +1 -1
- package/dist/src/sources/sigv4.d.ts +5 -3
- package/dist/src/sources/sigv4.d.ts.map +1 -1
- package/dist/src/sources/sigv4.js +6 -4
- package/dist/src/sources/sigv4.js.map +1 -1
- package/dist/src/sources/sparql/descriptor.d.ts +10 -0
- package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
- package/dist/src/sources/sparql/descriptor.js +64 -0
- package/dist/src/sources/sparql/descriptor.js.map +1 -0
- package/dist/src/sources/sparql/index.d.ts +28 -0
- package/dist/src/sources/sparql/index.d.ts.map +1 -0
- package/dist/src/sources/sparql/index.js +327 -0
- package/dist/src/sources/sparql/index.js.map +1 -0
- package/dist/src/sources/sparql/ntriples.d.ts +69 -0
- package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
- package/dist/src/sources/sparql/ntriples.js +180 -0
- package/dist/src/sources/sparql/ntriples.js.map +1 -0
- package/dist/src/sources/sparql/params.d.ts +27 -0
- package/dist/src/sources/sparql/params.d.ts.map +1 -0
- package/dist/src/sources/sparql/params.js +5 -0
- package/dist/src/sources/sparql/params.js.map +1 -0
- package/dist/src/sources/sparql/query.d.ts +73 -0
- package/dist/src/sources/sparql/query.d.ts.map +1 -0
- package/dist/src/sources/sparql/query.js +164 -0
- package/dist/src/sources/sparql/query.js.map +1 -0
- package/dist/src/sources/types.d.ts +60 -0
- package/dist/src/sources/types.d.ts.map +1 -1
- package/dist/src/styles/annotations.d.ts +61 -5
- package/dist/src/styles/annotations.d.ts.map +1 -1
- package/dist/src/styles/annotations.js +130 -22
- package/dist/src/styles/annotations.js.map +1 -1
- package/dist/src/styles/canon/bends.d.ts +46 -0
- package/dist/src/styles/canon/bends.d.ts.map +1 -1
- package/dist/src/styles/canon/bends.js +123 -0
- package/dist/src/styles/canon/bends.js.map +1 -1
- package/dist/src/styles/canon/color-tables.d.ts +6 -1
- package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
- package/dist/src/styles/canon/color-tables.js +10 -4
- package/dist/src/styles/canon/color-tables.js.map +1 -1
- package/dist/src/styles/canon/color.d.ts +3 -1
- package/dist/src/styles/canon/color.d.ts.map +1 -1
- package/dist/src/styles/canon/color.js +103 -3
- package/dist/src/styles/canon/color.js.map +1 -1
- package/dist/src/styles/canon/enums.d.ts +2 -2
- package/dist/src/styles/canon/enums.d.ts.map +1 -1
- package/dist/src/styles/canon/enums.js +89 -7
- package/dist/src/styles/canon/enums.js.map +1 -1
- package/dist/src/styles/canon/graphviz.d.ts +12 -3
- package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
- package/dist/src/styles/canon/graphviz.js +57 -9
- package/dist/src/styles/canon/graphviz.js.map +1 -1
- package/dist/src/styles/canon/number.d.ts +8 -0
- package/dist/src/styles/canon/number.d.ts.map +1 -1
- package/dist/src/styles/canon/number.js +18 -0
- package/dist/src/styles/canon/number.js.map +1 -1
- package/dist/src/styles/canon/text.d.ts +29 -2
- package/dist/src/styles/canon/text.d.ts.map +1 -1
- package/dist/src/styles/canon/text.js +156 -16
- package/dist/src/styles/canon/text.js.map +1 -1
- package/dist/src/styles/codes.d.ts +2 -0
- package/dist/src/styles/codes.d.ts.map +1 -1
- package/dist/src/styles/codes.js +2 -0
- package/dist/src/styles/codes.js.map +1 -1
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
- package/dist/src/styles/cyjs/cascade.js +1139 -79
- package/dist/src/styles/cyjs/cascade.js.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.js +4 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
- package/dist/src/styles/cyjs/emit.js +232 -10
- package/dist/src/styles/cyjs/emit.js.map +1 -1
- package/dist/src/styles/cyjs/face.d.ts +20 -0
- package/dist/src/styles/cyjs/face.d.ts.map +1 -0
- package/dist/src/styles/cyjs/face.js +332 -0
- package/dist/src/styles/cyjs/face.js.map +1 -0
- package/dist/src/styles/cyjs/mappers.d.ts +44 -1
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +475 -26
- package/dist/src/styles/cyjs/mappers.js.map +1 -1
- package/dist/src/styles/cyjs/routes.d.ts +53 -0
- package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
- package/dist/src/styles/cyjs/routes.js +360 -0
- package/dist/src/styles/cyjs/routes.js.map +1 -0
- package/dist/src/styles/cytoscape/charts.d.ts +23 -0
- package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/charts.js +560 -0
- package/dist/src/styles/cytoscape/charts.js.map +1 -0
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/emit.js +156 -48
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +387 -77
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
- package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
- package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/mappings.js +92 -0
- package/dist/src/styles/cytoscape/mappings.js.map +1 -1
- package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +623 -17
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +46 -26
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +308 -71
- package/dist/src/styles/defaults.js.map +1 -1
- package/dist/src/styles/index.d.ts +4 -3
- package/dist/src/styles/index.d.ts.map +1 -1
- package/dist/src/styles/index.js +3 -2
- package/dist/src/styles/index.js.map +1 -1
- package/dist/src/styles/internal.d.ts +1 -0
- package/dist/src/styles/internal.d.ts.map +1 -1
- package/dist/src/styles/internal.js +1 -0
- package/dist/src/styles/internal.js.map +1 -1
- package/dist/src/styles/io/generic.d.ts.map +1 -1
- package/dist/src/styles/io/generic.js +56 -16
- package/dist/src/styles/io/generic.js.map +1 -1
- package/dist/src/styles/io/round-trip.d.ts +56 -0
- package/dist/src/styles/io/round-trip.d.ts.map +1 -0
- package/dist/src/styles/io/round-trip.js +138 -0
- package/dist/src/styles/io/round-trip.js.map +1 -0
- package/dist/src/styles/io/writer.d.ts.map +1 -1
- package/dist/src/styles/io/writer.js +6 -1
- package/dist/src/styles/io/writer.js.map +1 -1
- package/dist/src/styles/notes.d.ts.map +1 -1
- package/dist/src/styles/notes.js +1 -0
- package/dist/src/styles/notes.js.map +1 -1
- package/dist/src/styles/plan/features.d.ts +1 -1
- package/dist/src/styles/plan/features.d.ts.map +1 -1
- package/dist/src/styles/plan/features.js +22 -2
- package/dist/src/styles/plan/features.js.map +1 -1
- package/dist/src/styles/plan/index.d.ts +1 -1
- package/dist/src/styles/plan/index.d.ts.map +1 -1
- package/dist/src/styles/plan/index.js +1 -1
- package/dist/src/styles/plan/index.js.map +1 -1
- package/dist/src/styles/plan/plan.d.ts.map +1 -1
- package/dist/src/styles/plan/plan.js +61 -4
- package/dist/src/styles/plan/plan.js.map +1 -1
- package/dist/src/styles/plan/resolve.d.ts +11 -0
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +40 -4
- package/dist/src/styles/plan/resolve.js.map +1 -1
- package/dist/src/styles/slots.d.ts +14 -0
- package/dist/src/styles/slots.d.ts.map +1 -0
- package/dist/src/styles/slots.js +20 -0
- package/dist/src/styles/slots.js.map +1 -0
- package/dist/src/styles/types.d.ts +687 -6
- package/dist/src/styles/types.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.d.ts +3 -2
- package/dist/src/styles/vocabulary.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.js +224 -0
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/styles.js +30 -239
- package/dist/styles.js.map +1 -1
- package/dist/xgmml.js +3 -3
- package/package.json +27 -7
- package/src/formats/cx/importer.ts +6 -1
- package/src/formats/cx/styles.ts +143 -9
- package/src/formats/cx2/importer.ts +1 -0
- package/src/formats/cx2/styles.ts +3 -1
- package/src/formats/cys/importer.ts +1 -0
- package/src/formats/cys/styles.ts +27 -5
- package/src/formats/dot/drawing.ts +799 -0
- package/src/formats/dot/exporter.ts +37 -1
- package/src/formats/dot/importer.ts +192 -36
- package/src/formats/dot/index.ts +3 -1
- package/src/formats/dot/label-places.ts +241 -0
- package/src/formats/dot/names.ts +15 -0
- package/src/formats/dot/record.ts +336 -0
- package/src/formats/dot/styles.ts +1702 -149
- package/src/formats/gexf/dialog-metrics.ts +61 -0
- package/src/formats/gexf/importer.ts +50 -5
- package/src/formats/gexf/preview.ts +217 -0
- package/src/formats/gexf/schema.ts +2 -1
- package/src/formats/gexf/styles.ts +1099 -245
- package/src/formats/gml/importer.ts +291 -76
- package/src/formats/gml/index.ts +1 -1
- package/src/formats/gml/positions.ts +29 -7
- package/src/formats/gml/styles.ts +852 -110
- package/src/formats/graphml/styles-plain.ts +6 -15
- package/src/formats/graphml/styles-yed.ts +765 -176
- package/src/formats/graphml/styles-yfiles3.ts +487 -63
- package/src/formats/graphml/yfiles.ts +19 -6
- package/src/formats/json/dialect.ts +41 -5
- package/src/formats/json/importer.ts +59 -7
- package/src/formats/json/index.ts +1 -0
- package/src/formats/json/positions.ts +22 -5
- package/src/formats/json/styles.ts +2123 -171
- package/src/formats/pajek/draw.ts +469 -0
- package/src/formats/pajek/exporter.ts +81 -49
- package/src/formats/pajek/importer.ts +278 -103
- package/src/formats/pajek/index.ts +1 -0
- package/src/formats/pajek/styles.ts +1506 -133
- package/src/formats/pajek/syntax.ts +27 -2
- package/src/formats/xgmml/emit.ts +73 -5
- package/src/formats/xgmml/styles.ts +330 -71
- package/src/index.ts +12 -1
- package/src/positions/convert.ts +12 -1
- package/src/positions/extract.ts +55 -1
- package/src/positions/index.ts +1 -0
- package/src/positions/types.ts +60 -0
- package/src/sources/builtins.ts +8 -1
- package/src/sources/context.ts +1 -0
- package/src/sources/credentials.ts +90 -1
- package/src/sources/cypher/descriptor.ts +7 -1
- package/src/sources/cypher/index.ts +149 -18
- package/src/sources/cypher/params.ts +1 -1
- package/src/sources/cypher/query-builder.ts +33 -0
- package/src/sources/ids.ts +6 -0
- package/src/sources/params.ts +3 -0
- package/src/sources/rest/descriptor.ts +9 -0
- package/src/sources/rest/openalex.ts +4 -2
- package/src/sources/rest/source.ts +41 -0
- package/src/sources/run.ts +35 -3
- package/src/sources/sigv4.ts +6 -4
- package/src/sources/sparql/descriptor.ts +67 -0
- package/src/sources/sparql/index.ts +371 -0
- package/src/sources/sparql/ntriples.ts +219 -0
- package/src/sources/sparql/params.ts +28 -0
- package/src/sources/sparql/query.ts +216 -0
- package/src/sources/types.ts +68 -0
- package/src/styles/annotations.ts +201 -27
- package/src/styles/canon/bends.ts +137 -0
- package/src/styles/canon/color-tables.ts +10 -4
- package/src/styles/canon/color.ts +105 -3
- package/src/styles/canon/enums.ts +107 -8
- package/src/styles/canon/graphviz.ts +71 -10
- package/src/styles/canon/number.ts +19 -0
- package/src/styles/canon/text.ts +187 -16
- package/src/styles/codes.ts +2 -0
- package/src/styles/cyjs/cascade.ts +1303 -84
- package/src/styles/cyjs/defaults-table.ts +4 -0
- package/src/styles/cyjs/emit.ts +268 -14
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +506 -27
- package/src/styles/cyjs/routes.ts +432 -0
- package/src/styles/cytoscape/charts.ts +684 -0
- package/src/styles/cytoscape/emit.ts +170 -48
- package/src/styles/cytoscape/lexicon.ts +431 -78
- package/src/styles/cytoscape/mappings.ts +108 -0
- package/src/styles/cytoscape/resolve.ts +741 -17
- package/src/styles/defaults.ts +417 -108
- package/src/styles/index.ts +5 -0
- package/src/styles/internal.ts +1 -0
- package/src/styles/io/generic.ts +79 -23
- package/src/styles/io/round-trip.ts +202 -0
- package/src/styles/io/writer.ts +6 -1
- package/src/styles/notes.ts +1 -0
- package/src/styles/plan/features.ts +23 -2
- package/src/styles/plan/index.ts +1 -1
- package/src/styles/plan/plan.ts +69 -5
- package/src/styles/plan/resolve.ts +47 -4
- package/src/styles/slots.ts +25 -0
- package/src/styles/types.ts +698 -5
- package/src/styles/vocabulary.ts +232 -2
- package/dist/chunks/block-Cu22ewuS.js.map +0 -1
- package/dist/chunks/choose-Cdx6Enl2.js +0 -57
- package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
- package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
- package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
- package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
- package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
- package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
- package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
- package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
- package/dist/chunks/format-BMS-1Nxb.js +0 -64
- package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
- package/dist/chunks/generic-CP6YD34u.js.map +0 -1
- package/dist/chunks/importer-B87_fmVx.js.map +0 -1
- package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
- package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
- package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
- package/dist/chunks/importer-DPZDN40-.js.map +0 -1
- package/dist/chunks/importer-e3huMZbm.js.map +0 -1
- package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
- package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
- package/dist/chunks/styles-CaABMoO1.js.map +0 -1
- package/dist/chunks/styles-P_gmFAOi.js +0 -770
- package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
- package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
- package/dist/chunks/writer-DvHTl36J.js +0 -449
- package/dist/chunks/writer-DvHTl36J.js.map +0 -1
|
@@ -4,15 +4,93 @@
|
|
|
4
4
|
* `arrowColorMatchesEdge` makes the edge's paint drive the line and both arrows). Every pass is linear in the number
|
|
5
5
|
* of elements plus the size of the style, and spends from the extraction's one budget.
|
|
6
6
|
*/
|
|
7
|
+
import { num6 } from "../canon/number.js";
|
|
8
|
+
import { noteAt } from "../canon/site.js";
|
|
7
9
|
import { STYLE_ISSUE } from "../codes.js";
|
|
8
10
|
import { toolDefaults } from "../defaults.js";
|
|
9
11
|
import { StyleNotes } from "../notes.js";
|
|
10
12
|
import { discreteLookup, evalContinuous, numberOf } from "../plan/resolve.js";
|
|
11
13
|
import { isStyleValue } from "../vocabulary.js";
|
|
12
|
-
import {
|
|
14
|
+
import { readCytoscapeCharts } from "./charts.js";
|
|
15
|
+
import { arrowGap, arrowProportion, arrowSizeParser, colorParser, CYTOSCAPE_LEXICON, cytoscapeLabelBase, cytoscapeLabelMove, cytoscapeLabelPlace, halfBack, isUncarriedVp, NODE_SIZE_VP, opacityParser, sizeParser, vpStep, } from "./lexicon.js";
|
|
13
16
|
import { emptyCytoscapeStyle, } from "./mappings.js";
|
|
17
|
+
/** How closely desktop stacks the edges it fans, 0..1: its anchors are twice this times the node size apart. */
|
|
18
|
+
const EDGE_STACKING_DENSITY_VP = "EDGE_STACKING_DENSITY";
|
|
19
|
+
/** How desktop draws parallel edges: AUTO_BEND (the default) fans them, HAYSTACK draws them straight. */
|
|
20
|
+
const EDGE_STACKING_VP = "EDGE_STACKING";
|
|
21
|
+
/** Whether an edge's label is turned along its line. */
|
|
22
|
+
const AUTOROTATE_VP = "EDGE_LABEL_AUTOROTATE";
|
|
23
|
+
/**
|
|
24
|
+
* A map without one key.
|
|
25
|
+
* @param m - the map
|
|
26
|
+
* @param key - the key left out
|
|
27
|
+
* @returns a copy without it
|
|
28
|
+
*/
|
|
29
|
+
function withoutKey(m, key) {
|
|
30
|
+
return new Map([...m].filter(([k]) => k !== key));
|
|
31
|
+
}
|
|
32
|
+
/** Desktop's `EDGE_STACKING_DENSITY` default. */
|
|
33
|
+
const EDGE_STACKING_DENSITY_DEFAULT = 0.5;
|
|
34
|
+
/**
|
|
35
|
+
* A graph's edge ends for `CytoscapeElements.ends`, with each node's larger side from the nodes' resolved `width`
|
|
36
|
+
* and `height`: what desktop spaces the edges it fans between two nodes by.
|
|
37
|
+
* @param snapshot - the graph
|
|
38
|
+
* @param nodes - the nodes' values per property
|
|
39
|
+
* @returns the ends
|
|
40
|
+
*/
|
|
41
|
+
export function edgeEnds(snapshot, nodes) {
|
|
42
|
+
const nodeSize = Array.from({ length: snapshot.nodeCount }, (_, i) => {
|
|
43
|
+
const sides = [nodes.width?.[i], nodes.height?.[i]].filter((v) => typeof v === "number");
|
|
44
|
+
return sides.length === 0 ? null : Math.max(...sides);
|
|
45
|
+
});
|
|
46
|
+
const nodeBox = Array.from({ length: snapshot.nodeCount }, (_, i) => {
|
|
47
|
+
const [w, h, b] = [nodes.width?.[i], nodes.height?.[i], nodes.borderWidth?.[i]];
|
|
48
|
+
return typeof w === "number" && typeof h === "number" ? [w, h, typeof b === "number" ? b : 0] : null;
|
|
49
|
+
});
|
|
50
|
+
const position = snapshot.nodes.byRole("position");
|
|
51
|
+
// stored y up unless the column says otherwise; the label places are worked out y down, as Cytoscape draws
|
|
52
|
+
const down = position?.meta.extra?.yAxis === "down";
|
|
53
|
+
const nodeAt = Array.from({ length: snapshot.nodeCount }, (_, i) => {
|
|
54
|
+
const v = position?.isSet(i) === true ? position.value(i) : null;
|
|
55
|
+
return v === null ? null : [v[0], down ? v[1] : -v[1]];
|
|
56
|
+
});
|
|
57
|
+
const { src, dst } = snapshot.edgeList();
|
|
58
|
+
return { source: src, target: dst, nodeSize, nodeBox, nodeAt };
|
|
59
|
+
}
|
|
14
60
|
/** Locked node sizes with no `NODE_SIZE` anywhere draw at Cytoscape's lexicon default. */
|
|
15
61
|
const NODE_SIZE_FALLBACK = 50;
|
|
62
|
+
/**
|
|
63
|
+
* The visual property whose bypass each one takes when an element does not bypass it itself: Cytoscape desktop locks
|
|
64
|
+
* a bypassed parent's children too, so a session's `NODE_PAINT` bypass paints the fill and the border, a `NODE_SIZE`
|
|
65
|
+
* bypass sizes the node whatever `nodeSizeLocked` says, and an `EDGE_PAINT` or `EDGE_UNSELECTED_PAINT` bypass paints
|
|
66
|
+
* the line and its arrows (Cytoscape 3.10.5's SVG of the session specimen sheets `node-fills-borders`,
|
|
67
|
+
* `node-sizes-opacity` and `edges-lines`).
|
|
68
|
+
*/
|
|
69
|
+
const LOCK_PARENT = new Map([
|
|
70
|
+
["NODE_FILL_COLOR", "NODE_PAINT"],
|
|
71
|
+
["NODE_BORDER_PAINT", "NODE_PAINT"],
|
|
72
|
+
["NODE_WIDTH", "NODE_SIZE"],
|
|
73
|
+
["NODE_HEIGHT", "NODE_SIZE"],
|
|
74
|
+
["EDGE_UNSELECTED_PAINT", "EDGE_PAINT"],
|
|
75
|
+
["EDGE_STROKE_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
|
|
76
|
+
["EDGE_SOURCE_ARROW_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
|
|
77
|
+
["EDGE_TARGET_ARROW_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
|
|
78
|
+
]);
|
|
79
|
+
/**
|
|
80
|
+
* An element's bypass of a visual property: its own, else the nearest bypassed parent's (`LOCK_PARENT`).
|
|
81
|
+
* @param b - the element's bypasses
|
|
82
|
+
* @param vp - the visual property
|
|
83
|
+
* @returns the bypass value, or undefined
|
|
84
|
+
*/
|
|
85
|
+
function lockedValue(b, vp) {
|
|
86
|
+
for (let p = vp; p !== undefined; p = LOCK_PARENT.get(p)) {
|
|
87
|
+
const v = b.get(p);
|
|
88
|
+
if (v !== undefined && v !== null) {
|
|
89
|
+
return v;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
16
94
|
/**
|
|
17
95
|
* Which visual properties a style or its bypasses mention.
|
|
18
96
|
* @param style - the target's style
|
|
@@ -33,6 +111,12 @@ export function vpUsage(style, bypasses) {
|
|
|
33
111
|
bypassed.add(to);
|
|
34
112
|
}
|
|
35
113
|
}
|
|
114
|
+
// a bypassed parent bypasses its children (LOCK_PARENT lists a parent's own entry before its children's)
|
|
115
|
+
for (const [child, parent] of LOCK_PARENT) {
|
|
116
|
+
if (bypassed.has(parent)) {
|
|
117
|
+
bypassed.add(child);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
36
120
|
const used = new Set([...style.defaults.keys(), ...style.mappings.keys(), ...bypassed]);
|
|
37
121
|
return { used, bypassed };
|
|
38
122
|
}
|
|
@@ -57,7 +141,8 @@ export function chooseVps(target, style, used) {
|
|
|
57
141
|
chosen.delete("height");
|
|
58
142
|
}
|
|
59
143
|
if (target === "edge" && style.dependencies.get("arrowColorMatchesEdge") === true) {
|
|
60
|
-
|
|
144
|
+
// the line is EDGE_UNSELECTED_PAINT's, not the stroke's, even where the style sets only the stroke
|
|
145
|
+
if (used.has("EDGE_UNSELECTED_PAINT") || used.has("EDGE_STROKE_UNSELECTED_PAINT")) {
|
|
61
146
|
chosen.set("color", ["EDGE_UNSELECTED_PAINT", colorParser]);
|
|
62
147
|
}
|
|
63
148
|
chosen.delete("sourceArrowColor");
|
|
@@ -175,7 +260,7 @@ function resolver(target, style, elements, notes, budget) {
|
|
|
175
260
|
return b.get(from);
|
|
176
261
|
}
|
|
177
262
|
}
|
|
178
|
-
return
|
|
263
|
+
return lockedValue(b, vp);
|
|
179
264
|
};
|
|
180
265
|
// a mapping parsed once per visual property and neutral property
|
|
181
266
|
const mappingOf = (vp, parse, property) => {
|
|
@@ -212,7 +297,7 @@ function resolver(target, style, elements, notes, budget) {
|
|
|
212
297
|
/**
|
|
213
298
|
* Every element's value per neutral property under a Cytoscape style, the way Cytoscape draws it: per visual
|
|
214
299
|
* property a bypass, else the mapping's value, else the default; `nodeSizeLocked` and `arrowColorMatchesEdge`
|
|
215
|
-
* applied. `EDGE_CURVED` only rounds an edge's bends, so an edge without bends is `curved: false
|
|
300
|
+
* applied (under `nodeSizeLocked` a node's own `NODE_WIDTH` or `NODE_HEIGHT` bypass still sets that dimension). `EDGE_CURVED` only rounds an edge's bends, so an edge without bends is `curved: false` unless desktop fans it out of a bundle of parallel edges (given `elements.ends`). Visual properties
|
|
216
301
|
* no neutral property carries are noted as `W_STYLE_NOT_CARRIED`.
|
|
217
302
|
* @param target - nodes or edges
|
|
218
303
|
* @param style - the style
|
|
@@ -227,7 +312,7 @@ export function resolveCytoscape(target, style, elements, options = {}) {
|
|
|
227
312
|
const n = elements.count;
|
|
228
313
|
const { used, bypassed } = vpUsage(s, elements.bypasses ?? []);
|
|
229
314
|
const chosen = chooseVps(target, s, used);
|
|
230
|
-
const { one } = resolver(target, s, elements, notes, options.budget);
|
|
315
|
+
const { one, bypass } = resolver(target, s, elements, notes, options.budget);
|
|
231
316
|
const out = {};
|
|
232
317
|
const column = (vp, parse, property) => {
|
|
233
318
|
options.budget?.spend(target, n);
|
|
@@ -241,30 +326,509 @@ export function resolveCytoscape(target, style, elements, options = {}) {
|
|
|
241
326
|
out[prop] = column(vp, parse, prop);
|
|
242
327
|
}
|
|
243
328
|
if (target === "node" && s.dependencies.get("nodeSizeLocked") === true) {
|
|
329
|
+
// a node's own width or height still wins over the locked size: Cytoscape draws it
|
|
244
330
|
const size = column(NODE_SIZE_VP, sizeParser, "width").map((v) => v ?? NODE_SIZE_FALLBACK);
|
|
245
|
-
|
|
246
|
-
|
|
331
|
+
const own = (vp, property) => size.map((v, i) => {
|
|
332
|
+
const b = bypass(i, vp);
|
|
333
|
+
const parsed = b === undefined || b === null ? null : sizeParser(b, { notes, target, property, element: i });
|
|
334
|
+
return parsed ?? v;
|
|
335
|
+
});
|
|
336
|
+
out.width = own("NODE_WIDTH", "width");
|
|
337
|
+
out.height = own("NODE_HEIGHT", "height");
|
|
338
|
+
}
|
|
339
|
+
labelDress(target, out, one, n, elements.ends);
|
|
340
|
+
if (target === "node") {
|
|
341
|
+
squashHexagons(out);
|
|
342
|
+
// the value as written: a chart is text, or an object in CX2; a size a number or its text
|
|
343
|
+
const raw = (v) => {
|
|
344
|
+
if (typeof v === "string" || typeof v === "number") {
|
|
345
|
+
return String(v);
|
|
346
|
+
}
|
|
347
|
+
return typeof v === "object" && v !== null ? JSON.stringify(v) : null;
|
|
348
|
+
};
|
|
349
|
+
readCytoscapeCharts(out, n, (slot, i) => {
|
|
350
|
+
const v = one(slot, raw, "pieColors", i);
|
|
351
|
+
return typeof v === "string" && v.startsWith("{") ? JSON.parse(v) : v;
|
|
352
|
+
}, (column, i) => elements.value(column, i), s.dependencies.get("nodeCustomGraphicsSizeSync") !== false);
|
|
353
|
+
}
|
|
354
|
+
if (target === "edge" &&
|
|
355
|
+
s.dependencies.get("arrowColorMatchesEdge") === true &&
|
|
356
|
+
!used.has("EDGE_UNSELECTED_PAINT") &&
|
|
357
|
+
used.has("EDGE_STROKE_UNSELECTED_PAINT")) {
|
|
358
|
+
// the dependency draws the line and the arrows in EDGE_UNSELECTED_PAINT, Cytoscape's own when the style has
|
|
359
|
+
// none: the stroke's default and its mapping are not drawn, only an element's own bypass of the stroke (below;
|
|
360
|
+
// Cytoscape 3.10.5 on specimen-mappings-bypass draws a passthrough of the stroke #404040, as its XGMML says)
|
|
361
|
+
const paint = (toolDefaults("cytoscape-fallbacks")?.edge.color?.value ?? null);
|
|
362
|
+
out.color = Array.from({ length: n }, (_, i) => one("EDGE_UNSELECTED_PAINT", colorParser, "color", i) ?? paint);
|
|
247
363
|
}
|
|
248
364
|
if (target === "edge" && s.dependencies.get("arrowColorMatchesEdge") === true && out.color !== undefined) {
|
|
249
|
-
|
|
250
|
-
out
|
|
365
|
+
// CX2's EDGE_LINE_COLOR bypass is the stroke's alone (its writer spells a desktop EDGE_UNSELECTED_PAINT
|
|
366
|
+
// bypass out as the line and both arrow colors): the arrows keep the style's line color (Cytoscape 3.10.5's
|
|
367
|
+
// SVG of the CX2 specimen-mappings-bypass, bypass-over-edge-passthrough, draws its arrow #505050)
|
|
368
|
+
const lineVp = chosen.get("color")?.[0];
|
|
369
|
+
const unbypassed = resolver(target, s, { ...elements, bypasses: [] }, notes, options.budget).one;
|
|
370
|
+
const arrows = lineVp === "EDGE_LINE_COLOR"
|
|
371
|
+
? Array.from({ length: n }, (_, i) => unbypassed(lineVp, colorParser, "color", i))
|
|
372
|
+
: out.color;
|
|
373
|
+
out.sourceArrowColor = arrows.slice();
|
|
374
|
+
out.targetArrowColor = arrows.slice();
|
|
375
|
+
// the dependency sets the line and the arrows from EDGE_UNSELECTED_PAINT; an element's own bypass of one of
|
|
376
|
+
// them still wins for that one (Cytoscape draws a bypassed EDGE_STROKE_UNSELECTED_PAINT line in its color)
|
|
377
|
+
const own = [
|
|
378
|
+
["color", "EDGE_STROKE_UNSELECTED_PAINT"],
|
|
379
|
+
["sourceArrowColor", "EDGE_SOURCE_ARROW_UNSELECTED_PAINT"],
|
|
380
|
+
["targetArrowColor", "EDGE_TARGET_ARROW_UNSELECTED_PAINT"],
|
|
381
|
+
["sourceArrowColor", "EDGE_SOURCE_ARROW_COLOR"],
|
|
382
|
+
["targetArrowColor", "EDGE_TARGET_ARROW_COLOR"],
|
|
383
|
+
];
|
|
384
|
+
for (const [prop, vp] of own) {
|
|
385
|
+
out[prop] = (out[prop] ?? []).map((v, i) => {
|
|
386
|
+
const b = bypass(i, vp);
|
|
387
|
+
const site = { notes, target, property: prop, element: i };
|
|
388
|
+
return (b === undefined || b === null ? null : colorParser(b, site)) ?? v;
|
|
389
|
+
});
|
|
390
|
+
}
|
|
251
391
|
}
|
|
252
392
|
noteUncarried(target, s, used, bypassed, notes);
|
|
253
|
-
fillToolDefaults(target, out, n, options.defaults ?? null);
|
|
254
393
|
if (target === "edge") {
|
|
255
|
-
|
|
394
|
+
const bends = column(EDGE_BEND_VP, bendsParser, "bends");
|
|
395
|
+
if (bends.some((v) => v !== null)) {
|
|
396
|
+
out.bends = bends;
|
|
397
|
+
}
|
|
398
|
+
// before the tool's defaults: an edge the style leaves unset is curved as Cytoscape's EDGE_CURVED default is
|
|
399
|
+
const curvedAsSet = out.curved?.slice();
|
|
400
|
+
straightenBendless(out, one, n, elements.ends);
|
|
401
|
+
loopHandles(out, one, curvedAsSet, elements.ends);
|
|
402
|
+
arrowProportions(out, column);
|
|
256
403
|
}
|
|
404
|
+
fillToolDefaults(target, out, n, options.defaults ?? null);
|
|
257
405
|
return out;
|
|
258
406
|
}
|
|
259
407
|
/**
|
|
260
|
-
*
|
|
408
|
+
* A visual property's value as written, a CX2 object as its JSON.
|
|
409
|
+
* @param v - the value
|
|
410
|
+
* @returns its text, or null
|
|
411
|
+
*/
|
|
412
|
+
const rawText = (v) => {
|
|
413
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
414
|
+
return String(v);
|
|
415
|
+
}
|
|
416
|
+
return typeof v === "object" && v !== null ? JSON.stringify(v) : null;
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* Reads what Cytoscape draws of each element's label beyond its words, font and color: the box behind it (drawn only
|
|
420
|
+
* with a `*_LABEL_BACKGROUND_SHAPE` other than NONE, the default, in its color and transparency), where it is placed
|
|
421
|
+
* (`*_LABEL_POSITION` read whole: which point of the label's box is pinned to which point of the node, or of the
|
|
422
|
+
* edge's line, and the offset) and how its lines are justified. Each column is kept only where some element needs it;
|
|
423
|
+
* an edge's place is kept whenever it has one, since Cytoscape centers an edge's label on its line.
|
|
424
|
+
* @param target - nodes or edges
|
|
261
425
|
* @param out - the values per property, changed in place
|
|
262
426
|
* @param one - reads one visual property of one element
|
|
427
|
+
* @param n - the element count
|
|
428
|
+
* @param ends - the edges' ends and their nodes' centers, when known
|
|
429
|
+
*/
|
|
430
|
+
function labelDress(target, out, one, n, ends) {
|
|
431
|
+
const vp = (name) => `${target === "node" ? "NODE" : "EDGE"}_LABEL_${name}`;
|
|
432
|
+
const columns = {};
|
|
433
|
+
const put = (property, i, v) => {
|
|
434
|
+
let column = columns[property];
|
|
435
|
+
if (column === undefined) {
|
|
436
|
+
column = new Array(n).fill(null);
|
|
437
|
+
columns[property] = column;
|
|
438
|
+
}
|
|
439
|
+
column[i] = v;
|
|
440
|
+
};
|
|
441
|
+
for (let i = 0; i < n; i++) {
|
|
442
|
+
labelBox(vp, one, i, put);
|
|
443
|
+
// read whole, quietly (the lexicon's reading of the same value notes a bad one), under a name of its own: a
|
|
444
|
+
// mapping is parsed once per visual property and neutral property
|
|
445
|
+
const placed = one(vp("POSITION"), rawText, "labelPlace", i);
|
|
446
|
+
const raw = typeof placed === "string" && placed.startsWith("{") ? JSON.parse(placed) : placed;
|
|
447
|
+
const place = cytoscapeLabelPlace(raw, { notes: new StyleNotes(), target, property: "labelPosition" });
|
|
448
|
+
if (place !== null) {
|
|
449
|
+
placeLabel(target, place, i, out, put, ends);
|
|
450
|
+
}
|
|
451
|
+
if (target === "edge") {
|
|
452
|
+
autorotate(one, i, out, n, ends);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const kept = (property, v) => v !== null && v !== 0 && (v !== "center" || (property === "labelPosition" && target === "edge"));
|
|
456
|
+
for (const [property, values] of Object.entries(columns)) {
|
|
457
|
+
if (values.some((v) => kept(property, v))) {
|
|
458
|
+
out[property] = values;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* The box Cytoscape draws behind one label, when its shape is not NONE: its color (`#B6B6B6` unset, the lexicon's
|
|
464
|
+
* default), its opacity, and for ROUND_RECTANGLE its corners, rounded an eighth of the box's height: 1.455 on the
|
|
465
|
+
* 11.64-tall box of a 10 px label (xgmml-specimen-labels.svg, label-background-shape-round-rectangle), so 0.1455 of the
|
|
466
|
+
* label's size. ponytail: one line's height; a box of several lines is rounded as one line's.
|
|
467
|
+
* @param vp - names a label visual property of the target
|
|
468
|
+
* @param one - reads one visual property of one element
|
|
469
|
+
* @param i - the element
|
|
470
|
+
* @param put - sets one element's value of a property
|
|
471
|
+
*/
|
|
472
|
+
function labelBox(vp, one, i, put) {
|
|
473
|
+
const shape = one(vp("BACKGROUND_SHAPE"), rawText, "labelBackgroundShape", i);
|
|
474
|
+
if (typeof shape !== "string" || shape.trim().toUpperCase() === "NONE") {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
put("labelBackground", i, one(vp("BACKGROUND_COLOR"), colorParser, "labelBackground", i) ?? "#b6b6b6");
|
|
478
|
+
const [t, o] = [vp("BACKGROUND_TRANSPARENCY"), vp("BACKGROUND_OPACITY")];
|
|
479
|
+
const opacity = one(t, opacityParser(t), "labelBackgroundOpacity", i) ?? one(o, opacityParser(o), "labelBackgroundOpacity", i);
|
|
480
|
+
put("labelBackgroundOpacity", i, opacity ?? 1);
|
|
481
|
+
// CX2 spells it round-rectangle
|
|
482
|
+
if (shape.trim().toUpperCase().replace("-", "_") === "ROUND_RECTANGLE") {
|
|
483
|
+
const size = one(vp("FONT_SIZE"), sizeParser, "labelSize", i);
|
|
484
|
+
// desktop's default label sizes: 12 on a node, 10 on an edge
|
|
485
|
+
const defaultSize = vp("FONT_SIZE").startsWith("EDGE") ? 10 : 12;
|
|
486
|
+
put("labelCornerRadius", i, num6(LABEL_CORNER_PER_SIZE * (typeof size === "number" ? size : defaultSize)));
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/** How far Cytoscape rounds a ROUND_RECTANGLE label box's corners, as a fraction of the label's font size. */
|
|
490
|
+
const LABEL_CORNER_PER_SIZE = 0.1455;
|
|
491
|
+
/**
|
|
492
|
+
* Where one label is placed, from its Cytoscape label position: its neutral `labelPosition`, offsets, shifts and
|
|
493
|
+
* line justification. A node's label is pinned against the node's box. An edge's is pinned to a point of its drawn
|
|
494
|
+
* line, the middle unless the anchor's horizontal letter names an end (W the source's, E the target's; its vertical
|
|
495
|
+
* letter changes nothing, measured on Cytoscape 3.10.5's SVG), from the line's middle, where it is centered.
|
|
496
|
+
* @param target - nodes or edges
|
|
497
|
+
* @param place - the label position
|
|
498
|
+
* @param i - the element
|
|
499
|
+
* @param out - the values per property (the node sizes are read)
|
|
500
|
+
* @param put - sets one element's value of a property
|
|
501
|
+
* @param ends - the edges' ends and their nodes' centers, when known
|
|
502
|
+
*/
|
|
503
|
+
function placeLabel(target, place, i, out, put, ends) {
|
|
504
|
+
let move;
|
|
505
|
+
if (target === "node") {
|
|
506
|
+
const [w, h] = [out.width?.[i], out.height?.[i]];
|
|
507
|
+
move = cytoscapeLabelMove(place, typeof w === "number" ? w : 0, typeof h === "number" ? h : 0);
|
|
508
|
+
put("labelPosition", i, cytoscapeLabelBase(place));
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
const [ax, ay] = lineEnd(ends, i, place.node[0]);
|
|
512
|
+
move = {
|
|
513
|
+
offset: [ax + place.offset[0], ay + place.offset[1]],
|
|
514
|
+
shift: [halfBack(place.label[0]), halfBack(place.label[1])],
|
|
515
|
+
};
|
|
516
|
+
put("labelPosition", i, "center");
|
|
517
|
+
}
|
|
518
|
+
put("labelOffsetX", i, num6(move.offset[0]));
|
|
519
|
+
put("labelOffsetY", i, num6(move.offset[1]));
|
|
520
|
+
put("labelShiftX", i, move.shift[0]);
|
|
521
|
+
put("labelShiftY", i, move.shift[1]);
|
|
522
|
+
put("labelTextAlign", i, place.justify);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Turns an edge's label along its line under `EDGE_LABEL_AUTOROTATE`, as Cytoscape draws it: the line's angle from
|
|
526
|
+
* its source's center to its target's (kept between -90 and 90 so the words read left to right), plus its
|
|
527
|
+
* `EDGE_LABEL_ROTATION`.
|
|
528
|
+
* ponytail: the angle is the file's node places at import; a layout that moves the nodes leaves it as it was, until
|
|
529
|
+
* the neutral styles can say "along the line"
|
|
530
|
+
* @param one - reads one visual property of one element
|
|
531
|
+
* @param e - the edge
|
|
532
|
+
* @param out - the values per property, changed in place
|
|
533
|
+
* @param n - the edge count
|
|
534
|
+
* @param ends - the edges' ends and their nodes' centers
|
|
263
535
|
*/
|
|
264
|
-
function
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
536
|
+
function autorotate(one, e, out, n, ends) {
|
|
537
|
+
const on = one(AUTOROTATE_VP, rawText, "labelRotation", e);
|
|
538
|
+
const [si, ti] = [ends?.source[e], ends?.target[e]];
|
|
539
|
+
const [s, t] = [si === undefined ? null : ends?.nodeAt?.[si], ti === undefined ? null : ends?.nodeAt?.[ti]];
|
|
540
|
+
if (String(on).toLowerCase() !== "true" || !s || !t || (s[0] === t[0] && s[1] === t[1])) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const a = (Math.atan2(t[1] - s[1], t[0] - s[0]) * 180) / Math.PI;
|
|
544
|
+
let upright = a;
|
|
545
|
+
if (a > 90) {
|
|
546
|
+
upright = a - 180;
|
|
547
|
+
}
|
|
548
|
+
else if (a <= -90) {
|
|
549
|
+
upright = a + 180;
|
|
550
|
+
}
|
|
551
|
+
out.labelRotation ?? (out.labelRotation = new Array(n).fill(null));
|
|
552
|
+
const column = out.labelRotation;
|
|
553
|
+
const own = column[e];
|
|
554
|
+
column[e] = num6((((upright + (typeof own === "number" ? own : 0)) % 360) + 360) % 360);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* How far from the middle of an edge's drawn line one of its ends is, on screen (y down): the line between its two
|
|
558
|
+
* nodes' centers, cut where it meets each node's ellipse; 0 for the middle, or where the centers are not known.
|
|
559
|
+
* @param ends - the edges' ends, their nodes' centers and boxes
|
|
560
|
+
* @param e - the edge
|
|
561
|
+
* @param side - -1 for the source's end, 1 for the target's, 0 for the middle
|
|
562
|
+
* @returns the offset from the line's middle
|
|
563
|
+
*/
|
|
564
|
+
function lineEnd(ends, e, side) {
|
|
565
|
+
const [si, ti] = [ends?.source[e], ends?.target[e]];
|
|
566
|
+
const [s, t] = [si === undefined ? null : ends?.nodeAt?.[si], ti === undefined ? null : ends?.nodeAt?.[ti]];
|
|
567
|
+
if (side === 0 || s === null || s === undefined || t === null || t === undefined) {
|
|
568
|
+
return [0, 0];
|
|
569
|
+
}
|
|
570
|
+
const length = Math.hypot(t[0] - s[0], t[1] - s[1]);
|
|
571
|
+
if (length === 0) {
|
|
572
|
+
return [0, 0];
|
|
573
|
+
}
|
|
574
|
+
const [ux, uy] = [(t[0] - s[0]) / length, (t[1] - s[1]) / length];
|
|
575
|
+
// where the line leaves a node's ellipse, along it from the center
|
|
576
|
+
const reach = (node) => {
|
|
577
|
+
const box = node === undefined ? null : ends?.nodeBox?.[node];
|
|
578
|
+
if (box === null || box === undefined) {
|
|
579
|
+
return 0;
|
|
580
|
+
}
|
|
581
|
+
const [a, b] = [box[0] / 2, box[1] / 2];
|
|
582
|
+
return a === 0 || b === 0 ? 0 : (a * b) / Math.hypot(b * ux, a * uy);
|
|
583
|
+
};
|
|
584
|
+
const from = reach(si);
|
|
585
|
+
const to = length - reach(ti);
|
|
586
|
+
// the drawn line's middle and the end asked for, both measured along the line from the source's center
|
|
587
|
+
const along = (side < 0 ? from : to) - (from + to) / 2;
|
|
588
|
+
return [ux * along, uy * along];
|
|
589
|
+
}
|
|
590
|
+
/** How tall a regular hexagon is for its width. */
|
|
591
|
+
const HEXAGON_ASPECT = Math.sqrt(3) / 2;
|
|
592
|
+
/**
|
|
593
|
+
* Gives every hexagon node the height Cytoscape desktop draws it at. Its HEXAGON is a regular hexagon squashed to
|
|
594
|
+
* the node's box rather than one filling it: the corners reach the box's sides, the flat top and bottom only
|
|
595
|
+
* `sqrt(3) / 2` of the way up and down, so a 40 x 40 node with a border of 1 is a 39 x 33.8 path (its border is
|
|
596
|
+
* inside its size, `borderPosition` inside). The neutral hexagon fills its box, so the node is that much shorter.
|
|
597
|
+
* @param out - the node values per property, changed in place
|
|
598
|
+
*/
|
|
599
|
+
function squashHexagons(out) {
|
|
600
|
+
const { shape, height } = out;
|
|
601
|
+
if (shape === undefined || height === undefined || !shape.includes("hexagon")) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const border = out.borderWidth;
|
|
605
|
+
out.height = height.map((h, i) => {
|
|
606
|
+
if (shape[i] !== "hexagon" || typeof h !== "number") {
|
|
607
|
+
return h;
|
|
608
|
+
}
|
|
609
|
+
const b = border?.[i];
|
|
610
|
+
const w = typeof b === "number" ? Math.min(b, h) : 0;
|
|
611
|
+
return (h - w) * HEXAGON_ASPECT + w;
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* What Cytoscape draws of each end's arrow beyond its shape and the one neutral `arrowSize`: the source end's own
|
|
616
|
+
* size where it differs from the target's (an unset size is Cytoscape's 6), and the length and width of the short and
|
|
617
|
+
* crossed arrows against their neutral shape's, and how far off its node each arrow stands. Each is kept only where
|
|
618
|
+
* some edge needs it.
|
|
619
|
+
* @param out - the values per property, changed in place
|
|
620
|
+
* @param column - reads one visual property of every element
|
|
621
|
+
*/
|
|
622
|
+
function arrowProportions(out, column) {
|
|
623
|
+
const size = out.arrowSize;
|
|
624
|
+
const own = column("EDGE_SOURCE_ARROW_SIZE", arrowSizeParser, "sourceArrowSize").map((v) => v ?? 1);
|
|
625
|
+
if (own.some((v, i) => v !== (size?.[i] ?? 1))) {
|
|
626
|
+
out.sourceArrowSize = own;
|
|
627
|
+
}
|
|
628
|
+
for (const [prop, vp, side] of [
|
|
629
|
+
["sourceArrowLength", "EDGE_SOURCE_ARROW_SHAPE", "length"],
|
|
630
|
+
["targetArrowLength", "EDGE_TARGET_ARROW_SHAPE", "length"],
|
|
631
|
+
["sourceArrowWidth", "EDGE_SOURCE_ARROW_SHAPE", "width"],
|
|
632
|
+
["targetArrowWidth", "EDGE_TARGET_ARROW_SHAPE", "width"],
|
|
633
|
+
]) {
|
|
634
|
+
const values = column(vp, arrowProportion(side), prop).map((v) => (v === 1 ? null : v));
|
|
635
|
+
if (values.some((v) => v !== null)) {
|
|
636
|
+
out[prop] = values;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
// the arrows desktop draws standing off their node (T, the half circles, HALF_TOP, the squares)
|
|
640
|
+
for (const [prop, vp] of [
|
|
641
|
+
["sourceArrowGap", "EDGE_SOURCE_ARROW_SHAPE"],
|
|
642
|
+
["targetArrowGap", "EDGE_TARGET_ARROW_SHAPE"],
|
|
643
|
+
]) {
|
|
644
|
+
const values = column(vp, arrowGap, prop).map((v) => (v === 0 ? null : v));
|
|
645
|
+
if (values.some((v) => v !== null)) {
|
|
646
|
+
out[prop] = values;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Marks straight every curved edge without bends, except where Cytoscape desktop fans it: `EDGE_CURVED` only
|
|
652
|
+
* rounds the bends an edge has, and the bends Cytoscape adds itself. Among the edges joining the same two nodes
|
|
653
|
+
* (either way round, not loops), it draws the last it created straight and bends each earlier one without bends
|
|
654
|
+
* of its own round an anchor beside the line (`DEdgeDetails.getAnchors`, `EDGE_STACKING` `AUTO_BEND`, the default;
|
|
655
|
+
* it walks the pair's edges newest first, measured on Cytoscape 3.10.5's SVG of edges joining two nodes both ways)
|
|
656
|
+
* -- unless the last has bends, when every anchor falls on the line. Its anchors are the larger side of the two
|
|
657
|
+
* nodes times twice `EDGE_STACKING_DENSITY` apart, so the curves' middles half that: each fanned edge's
|
|
658
|
+
* `fanSpacing`, when the node sizes are known. A fanned edge is drawn curved even under `EDGE_CURVED` false, and an
|
|
659
|
+
* edge whose `EDGE_STACKING` is HAYSTACK is neither fanned nor counted: desktop draws it straight (both measured on
|
|
660
|
+
* Cytoscape 3.10.5's SVG of the edges-lines specimen sheet).
|
|
661
|
+
* @param out - the values per property, changed in place
|
|
662
|
+
* @param one - reads one visual property of one element
|
|
663
|
+
* @param n - the edge count
|
|
664
|
+
* @param ends - each edge's source and target node index, in creation order, when known
|
|
665
|
+
*/
|
|
666
|
+
function straightenBendless(out, one, n, ends) {
|
|
667
|
+
// an edge the style leaves unset takes EDGE_CURVED's default, true
|
|
668
|
+
const curved = out.curved ?? new Array(n).fill(null);
|
|
669
|
+
const bent = (i) => one(EDGE_BEND_VP, bendParser, "curved", i) === true;
|
|
670
|
+
const haystack = (i) => String(one(EDGE_STACKING_VP, rawText, "fanned", i) ?? "").toUpperCase() === "HAYSTACK";
|
|
671
|
+
// each fanned edge's place in its pair's walk (1 for the first fanned)
|
|
672
|
+
const place = ends === undefined ? new Map() : fanPlaces(ends, curved.length, bent, haystack);
|
|
673
|
+
const fanned = new Set(place.keys());
|
|
674
|
+
const rounds = (i) => fanned.has(i) || bent(i);
|
|
675
|
+
const rounded = curved.map((c, i) => {
|
|
676
|
+
if (c === null) {
|
|
677
|
+
return rounds(i) ? true : null;
|
|
678
|
+
}
|
|
679
|
+
return c === true || fanned.has(i) ? rounds(i) : c;
|
|
680
|
+
});
|
|
681
|
+
if (out.curved !== undefined || rounded.includes(true)) {
|
|
682
|
+
out.curved = rounded;
|
|
683
|
+
}
|
|
684
|
+
if (ends?.nodeSize === undefined || fanned.size === 0) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const { source, target, nodeSize } = ends;
|
|
688
|
+
out.fanSpacing = curved.map((_, i) => {
|
|
689
|
+
const size = Math.max(nodeSize[source[i]] ?? Number.NaN, nodeSize[target[i]] ?? Number.NaN);
|
|
690
|
+
if (out.curved?.[i] !== true || !fanned.has(i) || bent(i) || !Number.isFinite(size)) {
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
const read = one(EDGE_STACKING_DENSITY_VP, sizeParser, "fanSpacing", i);
|
|
694
|
+
const density = Math.min(1, typeof read === "number" ? read : EDGE_STACKING_DENSITY_DEFAULT);
|
|
695
|
+
return size * density;
|
|
696
|
+
});
|
|
697
|
+
fanAnchors(out, ends, place);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* The edges desktop fans, each with its place in its node pair's walk (1 for the first fanned). Desktop walks a node
|
|
701
|
+
* pair's edges newest first (its adjacency lists take each new edge at the head); the first it meets is drawn
|
|
702
|
+
* straight, and each later one fanned unless that first one has bends. Loops and haystack edges are left out.
|
|
703
|
+
* @param ends - each edge's source and target node index, and the order they were created in
|
|
704
|
+
* @param count - the edge count
|
|
705
|
+
* @param bent - whether an edge has bends of its own
|
|
706
|
+
* @param haystack - whether an edge is a haystack edge
|
|
707
|
+
* @returns each fanned edge's place, in walk order
|
|
708
|
+
*/
|
|
709
|
+
function fanPlaces(ends, count, bent, haystack) {
|
|
710
|
+
const place = new Map();
|
|
711
|
+
const first = new Map();
|
|
712
|
+
for (const i of newestFirst(count, ends.created?.edge)) {
|
|
713
|
+
const [s, t] = [ends.source[i], ends.target[i]];
|
|
714
|
+
if (s === t || haystack(i)) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const key = `${Math.min(s, t)},${Math.max(s, t)}`;
|
|
718
|
+
const f = first.get(key);
|
|
719
|
+
if (f === undefined) {
|
|
720
|
+
first.set(key, { f: i, k: 0 });
|
|
721
|
+
}
|
|
722
|
+
else if (!bent(f.f)) {
|
|
723
|
+
f.k++;
|
|
724
|
+
place.set(i, f.k);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return place;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* The edges newest first: by the order they were created in when it is known, else last index first.
|
|
731
|
+
* @param count - the edge count
|
|
732
|
+
* @param created - each edge's place in the creation order, when known
|
|
733
|
+
* @returns the edge indices in that order
|
|
734
|
+
*/
|
|
735
|
+
function newestFirst(count, created) {
|
|
736
|
+
const walk = Array.from({ length: count }, (_, i) => i);
|
|
737
|
+
walk.sort(created === undefined ? (a, b) => b - a : (a, b) => created[b] - created[a]);
|
|
738
|
+
return walk;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Gives each fanned edge its place in desktop's fan as a bend, when the order desktop created the nodes in is known:
|
|
742
|
+
* the fan's side is then desktop's, not graphty's. Desktop measures each pair's fan from the node whose view it made
|
|
743
|
+
* first, and it makes views newest node first (`DEdgeDetails.getAnchors`: the pair's lower view SUID is its source;
|
|
744
|
+
* `SimpleNetwork.getNodeList` lists the newest node first); the `k`-th fanned edge bows `ceil(k / 2)` fan spacings
|
|
745
|
+
* off the middle of the line, to the right of the fan's direction (y down) for odd `k`, to the left for even. The
|
|
746
|
+
* bend is the control point of a quadratic Bezier whose middle lies there, twice as far off.
|
|
747
|
+
* @param out - the values per property, with `fanSpacing` set; changed in place
|
|
748
|
+
* @param ends - the edges' ends, their nodes' centers and creation order
|
|
749
|
+
* @param place - each fanned edge's place in its pair's walk, from 1
|
|
750
|
+
*/
|
|
751
|
+
function fanAnchors(out, ends, place) {
|
|
752
|
+
const { created, nodeAt, source, target } = ends;
|
|
753
|
+
const spacing = out.fanSpacing?.slice();
|
|
754
|
+
if (created === undefined || nodeAt === undefined || spacing === undefined) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
const bends = out.bends?.slice() ?? new Array(source.length).fill(null);
|
|
758
|
+
const bendCurve = out.bendCurve?.slice() ?? new Array(source.length).fill(null);
|
|
759
|
+
let changed = false;
|
|
760
|
+
for (const [i, k] of place) {
|
|
761
|
+
const [s, t] = [source[i], target[i]];
|
|
762
|
+
const [ps, pt, f] = [nodeAt[s], nodeAt[t], spacing[i]];
|
|
763
|
+
if (ps === null || ps === undefined || pt === null || pt === undefined || typeof f !== "number") {
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
const len = Math.hypot(pt[0] - ps[0], pt[1] - ps[1]);
|
|
767
|
+
if (len === 0) {
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
// the fan's direction: from the node desktop made a view of first, the one created last
|
|
771
|
+
const sign = created.node[s] > created.node[t] ? 1 : -1;
|
|
772
|
+
const [nx, ny] = [(sign * (pt[0] - ps[0])) / len, (sign * (pt[1] - ps[1])) / len];
|
|
773
|
+
const offset = Math.ceil(k / 2) * (k % 2 === 0 ? 1 : -1) * 2 * f;
|
|
774
|
+
const [vx, vy] = [offset * ny, -offset * nx];
|
|
775
|
+
// to the left of source -> target, y up, as a fraction of the length
|
|
776
|
+
const across = (vx * (pt[1] - ps[1]) - vy * (pt[0] - ps[0])) / (len * len);
|
|
777
|
+
bends[i] = `0.5,${String(Math.round(across * 1e6) / 1e6 || 0)}`;
|
|
778
|
+
bendCurve[i] = "bezier";
|
|
779
|
+
spacing[i] = null;
|
|
780
|
+
changed = true;
|
|
781
|
+
}
|
|
782
|
+
if (changed) {
|
|
783
|
+
out.bends = bends;
|
|
784
|
+
out.bendCurve = bendCurve;
|
|
785
|
+
out.fanSpacing = spacing;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Gives each self-loop without bends of its own the two handles Cytoscape desktop draws it round
|
|
790
|
+
* (`DEdgeDetails.getAnchors`): one left of the node's center and one above it, each `(i + 3) / 2` of the node's
|
|
791
|
+
* size times twice `EDGE_STACKING_DENSITY` away, where the size is the larger side of the node with its border
|
|
792
|
+
* (its extents in desktop's spatial index) and `i` counts the node's earlier loops without bends, newest first as
|
|
793
|
+
* desktop walks them. A loop is curved through them unless `EDGE_CURVED` says false. Measured on Cytoscape
|
|
794
|
+
* 3.10.5's SVG of the edges-lines specimen sheet (within 0.3 px of its loops).
|
|
795
|
+
* @param out - the values per property, changed in place
|
|
796
|
+
* @param one - reads one visual property of one element
|
|
797
|
+
* @param curvedAsSet - each edge's `curved` as the style set it, before bendless edges were straightened
|
|
798
|
+
* @param ends - each edge's source and target node index, in creation order, and each node's box, when known
|
|
799
|
+
*/
|
|
800
|
+
function loopHandles(out, one, curvedAsSet, ends) {
|
|
801
|
+
const box = ends?.nodeBox;
|
|
802
|
+
if (ends === undefined || box === undefined) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const bends = out.bends?.slice() ?? new Array(ends.source.length).fill(null);
|
|
806
|
+
const curved = out.curved?.slice() ?? new Array(ends.source.length).fill(null);
|
|
807
|
+
const earlier = new Map();
|
|
808
|
+
const fraction = (v) => String(Math.round(v * 1e4) / 1e4 || 0);
|
|
809
|
+
let changed = false;
|
|
810
|
+
for (let i = ends.source.length - 1; i >= 0; i--) {
|
|
811
|
+
const node = ends.source[i];
|
|
812
|
+
const b = box[node];
|
|
813
|
+
if (node !== ends.target[i] || bends[i] !== null) {
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
const rank = earlier.get(node) ?? 0;
|
|
817
|
+
earlier.set(node, rank + 1);
|
|
818
|
+
if (b === null || b === undefined || b[0] <= 0 || b[1] <= 0) {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
const read = one(EDGE_STACKING_DENSITY_VP, sizeParser, "fanSpacing", i);
|
|
822
|
+
const density = Math.min(1, typeof read === "number" ? read : EDGE_STACKING_DENSITY_DEFAULT);
|
|
823
|
+
const reach = (((rank + 3) * (Math.max(b[0], b[1]) + b[2])) / 2) * 2 * density;
|
|
824
|
+
// as `x,y` fractions of the node's half width and half height, y up: left of the center, then above it
|
|
825
|
+
bends[i] = `${fraction(-reach / (b[0] / 2))},0 0,${fraction(reach / (b[1] / 2))}`;
|
|
826
|
+
curved[i] = curvedAsSet?.[i] !== false;
|
|
827
|
+
changed = true;
|
|
828
|
+
}
|
|
829
|
+
if (changed) {
|
|
830
|
+
out.bends = bends;
|
|
831
|
+
out.curved = curved;
|
|
268
832
|
}
|
|
269
833
|
}
|
|
270
834
|
/** An edge's bend handles. */
|
|
@@ -281,6 +845,40 @@ export const bendParser = (raw) => {
|
|
|
281
845
|
}
|
|
282
846
|
return Array.isArray(raw) ? raw.length > 0 : raw !== null && raw !== undefined && typeof raw === "object";
|
|
283
847
|
};
|
|
848
|
+
/**
|
|
849
|
+
* An `EDGE_BEND` value as the neutral `bends`: Cytoscape keeps each handle as `cos,sin,ratio`, the handle at the
|
|
850
|
+
* source center plus `ratio` times the source-to-target vector turned by the angle (y down), handles separated by
|
|
851
|
+
* `|`. Relative to the same line, y up, that is `ratio * cos` along it and `-ratio * sin` across it.
|
|
852
|
+
* @param input - the value: an `EDGE_BEND` text, or CX2's `EDGE_CONTROL_POINTS` objects
|
|
853
|
+
* @param site - where it was read
|
|
854
|
+
* @returns the bends, or null for an edge without handles or a value that is not handles
|
|
855
|
+
*/
|
|
856
|
+
const bendsParser = (input, site) => {
|
|
857
|
+
// CX2's EDGE_CONTROL_POINTS: one object per handle, whose `sin` Cytoscape fills with EDGE_BEND's first number and
|
|
858
|
+
// `cos` with its second (it reads them back the same way: specimen-edges-lines bend-one-handle bends)
|
|
859
|
+
const raw = Array.isArray(input)
|
|
860
|
+
? input
|
|
861
|
+
.map((h) => {
|
|
862
|
+
const o = (h ?? {});
|
|
863
|
+
return `${Number(o.sin)},${Number(o.cos)},${Number(o.ratio)}`;
|
|
864
|
+
})
|
|
865
|
+
.join("|")
|
|
866
|
+
: input;
|
|
867
|
+
if (typeof raw !== "string" || !bendParser(raw, site)) {
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
const points = [];
|
|
871
|
+
for (const handle of raw.trim().split("|")) {
|
|
872
|
+
const [c, sin, ratio] = handle.split(",").map((t) => Number(t.trim()));
|
|
873
|
+
if (![c, sin, ratio].every((v) => Number.isFinite(v))) {
|
|
874
|
+
noteAt(site, STYLE_ISSUE.BAD_VALUE, raw.slice(0, 64));
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
const fraction = (v) => String(Math.round(v * 1e4) / 1e4 || 0);
|
|
878
|
+
points.push(`${fraction(ratio * c)},${fraction(-ratio * sin)}`);
|
|
879
|
+
}
|
|
880
|
+
return points.join(" ");
|
|
881
|
+
};
|
|
284
882
|
/** Default values that mean "nothing drawn": a VP left at one of these is not worth a note. */
|
|
285
883
|
const INERT_DEFAULT = /NullCustomGraphics|^255$|^0(?:\.0+)?$|^$|^C,C,c,0\.00,0\.00$|^false$/;
|
|
286
884
|
/**
|
|
@@ -357,7 +955,15 @@ export function cytoscapeBackground(style, notes) {
|
|
|
357
955
|
export function resolveCytoscapeBypasses(target, maps, options = {}) {
|
|
358
956
|
const notes = options.notes ?? new StyleNotes();
|
|
359
957
|
const style = emptyCytoscapeStyle();
|
|
360
|
-
const elements = {
|
|
958
|
+
const elements = {
|
|
959
|
+
count: maps.length,
|
|
960
|
+
value: options.value ?? (() => null),
|
|
961
|
+
// Cytoscape 3.10.5 draws an XGMML edge's EDGE_LABEL_AUTOROTATE true level, where it turns the same edge read
|
|
962
|
+
// from CX, CX2 or a session along its line (the label-autorotate-true edge of the edge-labels and
|
|
963
|
+
// mappings-bypass-p13 sheets in its SVG): its XGMML reader does not apply it, so neither does graph-io
|
|
964
|
+
bypasses: maps.map((m) => (m?.has(AUTOROTATE_VP) === true ? withoutKey(m, AUTOROTATE_VP) : m)),
|
|
965
|
+
ends: options.ends,
|
|
966
|
+
};
|
|
361
967
|
const out = resolveCytoscape(target, style, elements, { notes, budget: options.budget });
|
|
362
968
|
if (target === "node" && out.width === undefined) {
|
|
363
969
|
const size = maps.map((m) => {
|