@graphty/graph-io 0.3.48 → 0.3.49
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-Bzn3L-je.js} +2 -2
- package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-Bzn3L-je.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-iptrlMBb.js} +906 -164
- package/dist/chunks/block-iptrlMBb.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-C3p0RQxR.js} +5 -4
- package/dist/chunks/{context-cgmmOxZ2.js.map → context-C3p0RQxR.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-DXHx7nwR.js} +16 -14
- package/dist/chunks/credentials-DXHx7nwR.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-DLA5kINx.js} +7 -2
- package/dist/chunks/descriptor-DLA5kINx.js.map +1 -0
- package/dist/chunks/{emit-CD8xnY8s.js → emit-BwHQkZle.js} +1660 -133
- package/dist/chunks/emit-BwHQkZle.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-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
- package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
- package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-D2CETOMK.js} +1222 -156
- package/dist/chunks/exporter-D2CETOMK.js.map +1 -0
- package/dist/chunks/{exporter-BIdaoIgh.js → exporter-D9yMtocA.js} +7 -7
- package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-D9yMtocA.js.map} +1 -1
- package/dist/chunks/{exporter-DtVU80Fa.js → exporter-_jrBTnos.js} +9 -8
- package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-_jrBTnos.js.map} +1 -1
- package/dist/chunks/{exporter-ChjL5fmP.js → exporter-nDfxIK5D.js} +9 -8
- package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-nDfxIK5D.js.map} +1 -1
- 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-ymWCETAJ.js} +387 -31
- package/dist/chunks/generic-ymWCETAJ.js.map +1 -0
- package/dist/chunks/{importer-e3huMZbm.js → importer-B92x1xY5.js} +14 -10
- package/dist/chunks/importer-B92x1xY5.js.map +1 -0
- package/dist/chunks/{importer-B87_fmVx.js → importer-CT9mJ1nn.js} +326 -84
- package/dist/chunks/importer-CT9mJ1nn.js.map +1 -0
- package/dist/chunks/{importer-CB_zV5_L.js → importer-DaLTjbds.js} +116 -1102
- package/dist/chunks/importer-DaLTjbds.js.map +1 -0
- package/dist/chunks/{importer-DPZDN40-.js → importer-GREKMdIf.js} +25 -17
- package/dist/chunks/importer-GREKMdIf.js.map +1 -0
- package/dist/chunks/{importer-Bji2MeWr.js → importer-PqaaKKnY.js} +13 -10
- package/dist/chunks/{importer-Bji2MeWr.js.map → importer-PqaaKKnY.js.map} +1 -1
- package/dist/chunks/{importer-Cyy6UseH.js → importer-Vn5QvmmJ.js} +66 -13
- package/dist/chunks/importer-Vn5QvmmJ.js.map +1 -0
- package/dist/chunks/{importer-CVT-JyDE.js → importer-vRq4h3j5.js} +1469 -356
- package/dist/chunks/importer-vRq4h3j5.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-Clf4QIyl.js} +282 -74
- package/dist/chunks/lexicon-Clf4QIyl.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-Zm3_ivgq.js +79 -0
- package/dist/chunks/round-trip-Zm3_ivgq.js.map +1 -0
- package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-EokFic1V.js} +5 -5
- package/dist/chunks/sigv4-EokFic1V.js.map +1 -0
- package/dist/chunks/{styles-CaABMoO1.js → styles-CCs214_3.js} +1237 -138
- package/dist/chunks/styles-CCs214_3.js.map +1 -0
- package/dist/chunks/styles-Cm62yyQX.js +2812 -0
- package/dist/chunks/styles-Cm62yyQX.js.map +1 -0
- package/dist/chunks/styles-DPQQIig4.js +1928 -0
- package/dist/chunks/styles-DPQQIig4.js.map +1 -0
- package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-UMFdNqze.js} +503 -172
- package/dist/chunks/styles-yed-UMFdNqze.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 +5 -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 +847 -193
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +232 -220
- 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 +138 -23
- package/dist/sources-cypher.js.map +1 -1
- package/dist/sources-ndex.js +2 -2
- package/dist/sources-rest.js +16 -6
- package/dist/sources-rest.js.map +1 -1
- package/dist/sources-sparql.d.ts +1 -0
- package/dist/sources-sparql.js +405 -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/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +108 -31
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/label-places.d.ts +34 -0
- package/dist/src/formats/dot/label-places.d.ts.map +1 -0
- package/dist/src/formats/dot/label-places.js +179 -0
- package/dist/src/formats/dot/label-places.js.map +1 -0
- 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 +62 -2
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +1454 -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 +753 -101
- 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 +692 -161
- 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 +429 -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 +1755 -136
- package/dist/src/formats/json/styles.js.map +1 -1
- package/dist/src/formats/pajek/draw.d.ts +96 -0
- package/dist/src/formats/pajek/draw.d.ts.map +1 -0
- package/dist/src/formats/pajek/draw.js +372 -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 +1278 -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 +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -3
- 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/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 +124 -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 +5 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -1
- package/dist/src/sources/rest/source.d.ts.map +1 -1
- package/dist/src/sources/rest/source.js +15 -0
- package/dist/src/sources/rest/source.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 +314 -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 +72 -0
- package/dist/src/sources/sparql/query.d.ts.map +1 -0
- package/dist/src/sources/sparql/query.js +113 -0
- package/dist/src/sources/sparql/query.js.map +1 -0
- package/dist/src/sources/types.d.ts +31 -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 +81 -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 +1015 -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 +3 -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 +202 -9
- 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 +461 -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 +622 -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 +203 -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/importer.ts +120 -35
- package/src/formats/dot/label-places.ts +228 -0
- package/src/formats/dot/record.ts +336 -0
- package/src/formats/dot/styles.ts +1654 -153
- 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 +851 -109
- package/src/formats/graphml/styles-plain.ts +6 -15
- package/src/formats/graphml/styles-yed.ts +762 -173
- package/src/formats/graphml/styles-yfiles3.ts +485 -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 +2041 -185
- package/src/formats/pajek/draw.ts +458 -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 +1381 -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 +5 -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/cypher/descriptor.ts +7 -1
- package/src/sources/cypher/index.ts +148 -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 +5 -0
- package/src/sources/rest/source.ts +16 -0
- package/src/sources/sigv4.ts +6 -4
- package/src/sources/sparql/descriptor.ts +67 -0
- package/src/sources/sparql/index.ts +356 -0
- package/src/sources/sparql/ntriples.ts +219 -0
- package/src/sources/sparql/params.ts +28 -0
- package/src/sources/sparql/query.ts +162 -0
- package/src/sources/types.ts +35 -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 +98 -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 +1160 -84
- package/src/styles/cyjs/defaults-table.ts +3 -0
- package/src/styles/cyjs/emit.ts +233 -13
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +492 -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 +633 -5
- package/src/styles/vocabulary.ts +211 -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
|
@@ -42,18 +42,26 @@ import type {
|
|
|
42
42
|
StyleWorkBudget,
|
|
43
43
|
} from "../types.js";
|
|
44
44
|
import { CYJS_DEFAULT_STYLESHEET, CYJS_PROPERTY_DEFAULTS } from "./defaults-table.js";
|
|
45
|
+
import { combineFace } from "./face.js";
|
|
45
46
|
import {
|
|
46
47
|
applyCyjsMapper,
|
|
48
|
+
CYJS_CURVE_STYLES,
|
|
47
49
|
CYJS_THROWS,
|
|
50
|
+
cyjsAliasOf,
|
|
51
|
+
cyjsDashLook,
|
|
48
52
|
type CyjsFlat,
|
|
49
53
|
cyjsNeutral,
|
|
50
54
|
type CyjsParsed,
|
|
55
|
+
cyjsPolygonShapes,
|
|
51
56
|
cyjsProperties,
|
|
52
57
|
cyjsPropertyName,
|
|
53
58
|
type CyjsPropertySpec,
|
|
54
59
|
cyjsRendered,
|
|
60
|
+
gradientStopColors,
|
|
61
|
+
gradientStops,
|
|
55
62
|
parseCyjsValue,
|
|
56
63
|
} from "./mappers.js";
|
|
64
|
+
import { cyjsRoute, type CyjsRouteEdge, type CyjsRouteNode } from "./routes.js";
|
|
57
65
|
import { type CyjsCheck, type CyjsQuery, type CyjsSelector, parseCyjsSelector } from "./selector.js";
|
|
58
66
|
import { type CyjsSheetEntry, parseCyjsStylesheetText } from "./stylesheet-text.js";
|
|
59
67
|
|
|
@@ -1136,6 +1144,18 @@ const POSITIONS: ReadonlyMap<string, string> = new Map([
|
|
|
1136
1144
|
["bottom,right", "bottom-right"],
|
|
1137
1145
|
]);
|
|
1138
1146
|
|
|
1147
|
+
/** The positions inside the node, by the sides the `-inside` alignments name (`center` for neither). */
|
|
1148
|
+
const INSIDE_POSITIONS: ReadonlyMap<string, string> = new Map([
|
|
1149
|
+
["top,left", "inside-top-left"],
|
|
1150
|
+
["top,center", "inside-top"],
|
|
1151
|
+
["top,right", "inside-top-right"],
|
|
1152
|
+
["center,left", "inside-left"],
|
|
1153
|
+
["center,right", "inside-right"],
|
|
1154
|
+
["bottom,left", "inside-bottom-left"],
|
|
1155
|
+
["bottom,center", "inside-bottom"],
|
|
1156
|
+
["bottom,right", "inside-bottom-right"],
|
|
1157
|
+
]);
|
|
1158
|
+
|
|
1139
1159
|
/**
|
|
1140
1160
|
* Applies a Cytoscape.js stylesheet to its elements as Cytoscape.js 3.34 does.
|
|
1141
1161
|
* @param input - the elements, the stylesheet, the graph and the options
|
|
@@ -1186,8 +1206,8 @@ export function evaluateCytoscapeJs(input: CyjsStyleInput): CyjsStyles {
|
|
|
1186
1206
|
notes.add(STYLE_ISSUE.SELECTOR, null, "selector", { count: deep, sample: "nested too deep" });
|
|
1187
1207
|
}
|
|
1188
1208
|
const matcher = new Matcher(graph, notes);
|
|
1189
|
-
const node = evaluateTarget("node", graph, sheet, matcher, input, notes, budget);
|
|
1190
|
-
const edge = evaluateTarget("edge", graph, sheet, matcher, input, notes, budget);
|
|
1209
|
+
const node = evaluateTarget("node", graph, sheet, matcher, input, { notes, budget, nodes: null });
|
|
1210
|
+
const edge = evaluateTarget("edge", graph, sheet, matcher, input, { notes, budget, nodes: node });
|
|
1191
1211
|
return { node, edge, graph };
|
|
1192
1212
|
}
|
|
1193
1213
|
|
|
@@ -1289,8 +1309,10 @@ function cellsOf(cells: Cells, name: string, n: number): (Cell | undefined)[] {
|
|
|
1289
1309
|
* @param sheet - the entries
|
|
1290
1310
|
* @param matcher - the selector evaluator
|
|
1291
1311
|
* @param input - the input
|
|
1292
|
-
* @param
|
|
1293
|
-
* @param
|
|
1312
|
+
* @param env - where problems are noted, the counted budget, and for edges the nodes' values
|
|
1313
|
+
* @param env.notes - where problems are noted
|
|
1314
|
+
* @param env.budget - the counted budget
|
|
1315
|
+
* @param env.nodes - the nodes' values, which edge routes are measured against (null for nodes)
|
|
1294
1316
|
* @returns the target's values and rules
|
|
1295
1317
|
*/
|
|
1296
1318
|
function evaluateTarget(
|
|
@@ -1299,9 +1321,9 @@ function evaluateTarget(
|
|
|
1299
1321
|
sheet: readonly Entry[],
|
|
1300
1322
|
matcher: Matcher,
|
|
1301
1323
|
input: CyjsStyleInput,
|
|
1302
|
-
notes: StyleNotes,
|
|
1303
|
-
budget: StyleWorkBudget,
|
|
1324
|
+
env: { readonly notes: StyleNotes; readonly budget: StyleWorkBudget; readonly nodes: CyjsTargetStyles | null },
|
|
1304
1325
|
): CyjsTargetStyles {
|
|
1326
|
+
const { notes, budget } = env;
|
|
1305
1327
|
const els = kind === "node" ? graph.nodes : graph.edges;
|
|
1306
1328
|
const spend = (ops: number): void => {
|
|
1307
1329
|
budget.spend(kind, ops);
|
|
@@ -1319,6 +1341,21 @@ function evaluateTarget(
|
|
|
1319
1341
|
forceLoopCurves(graph, cells.get("curve-style"));
|
|
1320
1342
|
}
|
|
1321
1343
|
const drawn = drawnValues(kind, els, cells, order, input.rendered, notes, spend);
|
|
1344
|
+
// a file read with Cytoscape.js's own defaults draws an edge no rule curves as a haystack (a file graphty wrote
|
|
1345
|
+
// is read with graphty's)
|
|
1346
|
+
if (kind === "edge" && input.toolDefaults !== false) {
|
|
1347
|
+
const read: DrawnRead = { kind, els, cells, order, rendered: input.rendered, notes };
|
|
1348
|
+
const curves = drawnColumn(read, "curve-style", CURVE_PART);
|
|
1349
|
+
noArrowsOnHaystacks(curves, drawn);
|
|
1350
|
+
if (env.nodes !== null) {
|
|
1351
|
+
edgeRoutes(graph, read, curves, env.nodes, drawn);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
if (kind === "node") {
|
|
1355
|
+
const read: DrawnRead = { kind, els, cells, order, rendered: input.rendered, notes };
|
|
1356
|
+
nodeSizes(graph, read, drawn);
|
|
1357
|
+
mixedLabelPlaces(graph, read, drawn);
|
|
1358
|
+
}
|
|
1322
1359
|
if (kind === "edge") {
|
|
1323
1360
|
straightenUnpairedBeziers(graph, curveStyles(graph, cells, input.rendered), coreToOut, drawn.curved);
|
|
1324
1361
|
}
|
|
@@ -1501,7 +1538,7 @@ function drawnValues(
|
|
|
1501
1538
|
if (spec.property.startsWith("_")) {
|
|
1502
1539
|
words.set(
|
|
1503
1540
|
spec.property,
|
|
1504
|
-
col.map((v) => (typeof v === "string" ? v : null)),
|
|
1541
|
+
col.map((v) => (typeof v === "string" || typeof v === "number" ? String(v) : null)),
|
|
1505
1542
|
);
|
|
1506
1543
|
continue;
|
|
1507
1544
|
}
|
|
@@ -1514,6 +1551,9 @@ function drawnValues(
|
|
|
1514
1551
|
});
|
|
1515
1552
|
}
|
|
1516
1553
|
combineParts(kind, out, words, values, notes);
|
|
1554
|
+
if (kind === "node") {
|
|
1555
|
+
cyjsPolygonShapes(values);
|
|
1556
|
+
}
|
|
1517
1557
|
const drawn: Record<string, (StyleValue | null)[]> = {};
|
|
1518
1558
|
for (const [p, col] of Object.entries(values)) {
|
|
1519
1559
|
if (col.some((v) => v !== null)) {
|
|
@@ -1695,7 +1735,7 @@ function entryProperties(
|
|
|
1695
1735
|
): EntryProperty[] {
|
|
1696
1736
|
const out: EntryProperty[] = [];
|
|
1697
1737
|
for (const [name0, value] of entry.properties) {
|
|
1698
|
-
const name = entry.dashOnly ?
|
|
1738
|
+
const name = entry.dashOnly ? cyjsAliasOf(name0) : cyjsPropertyName(name0);
|
|
1699
1739
|
const spec = specs.get(name);
|
|
1700
1740
|
if (spec === undefined) {
|
|
1701
1741
|
if (kind === "node" && !CYJS_EDGE_ONLY.has(name) && !entry.tool) {
|
|
@@ -1716,29 +1756,37 @@ function entryProperties(
|
|
|
1716
1756
|
return out;
|
|
1717
1757
|
}
|
|
1718
1758
|
|
|
1719
|
-
/**
|
|
1720
|
-
* A property name of an entry Cytoscape.js reads in dash form only: `content` is `label`, any other name as it is.
|
|
1721
|
-
* @param name - the name as written
|
|
1722
|
-
* @returns the name
|
|
1723
|
-
*/
|
|
1724
|
-
function dashOnlyName(name: string): string {
|
|
1725
|
-
return name === "content" ? "label" : name;
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
1759
|
/** Edge properties a node never carries: not noted as dropped on nodes. */
|
|
1729
1760
|
const CYJS_EDGE_ONLY: ReadonlySet<string> = new Set([
|
|
1730
1761
|
"line-color",
|
|
1731
1762
|
"line-style",
|
|
1763
|
+
"line-outline-width",
|
|
1764
|
+
"line-outline-color",
|
|
1765
|
+
"line-fill",
|
|
1766
|
+
"line-gradient-stop-colors",
|
|
1767
|
+
"line-gradient-stop-positions",
|
|
1732
1768
|
"target-arrow-shape",
|
|
1733
1769
|
"source-arrow-shape",
|
|
1734
1770
|
"target-arrow-color",
|
|
1735
1771
|
"source-arrow-color",
|
|
1772
|
+
"mid-target-arrow-shape",
|
|
1773
|
+
"mid-source-arrow-shape",
|
|
1774
|
+
"mid-target-arrow-color",
|
|
1775
|
+
"mid-source-arrow-color",
|
|
1736
1776
|
"target-arrow-fill",
|
|
1737
1777
|
"source-arrow-fill",
|
|
1738
1778
|
"curve-style",
|
|
1739
1779
|
"arrow-scale",
|
|
1740
1780
|
"source-label",
|
|
1741
1781
|
"target-label",
|
|
1782
|
+
"source-text-offset",
|
|
1783
|
+
"target-text-offset",
|
|
1784
|
+
"source-text-margin-x",
|
|
1785
|
+
"source-text-margin-y",
|
|
1786
|
+
"target-text-margin-x",
|
|
1787
|
+
"target-text-margin-y",
|
|
1788
|
+
"source-text-rotation",
|
|
1789
|
+
"target-text-rotation",
|
|
1742
1790
|
]);
|
|
1743
1791
|
|
|
1744
1792
|
/**
|
|
@@ -1862,7 +1910,8 @@ function neutralOfCell(spec: CyjsPropertySpec, name: string, c: Cell, site: Cano
|
|
|
1862
1910
|
}
|
|
1863
1911
|
|
|
1864
1912
|
/**
|
|
1865
|
-
* Combines the label alignments into `labelPosition`
|
|
1913
|
+
* Combines the label alignments into `labelPosition`, `text-wrap` with `text-max-width` and `text-overflow-wrap` into
|
|
1914
|
+
* `labelWrapWidth`, `labelWrapEllipsis` and `labelWrapAnywhere`, and `visibility` with `display` into `visible`.
|
|
1866
1915
|
* @param kind - the target
|
|
1867
1916
|
* @param n - the element count
|
|
1868
1917
|
* @param words - the parts by internal name
|
|
@@ -1876,116 +1925,1139 @@ function combineParts(
|
|
|
1876
1925
|
values: Record<string, (StyleValue | null)[]>,
|
|
1877
1926
|
notes: StyleNotes,
|
|
1878
1927
|
): void {
|
|
1928
|
+
// the element's own opacity, before an edge's line opacity is multiplied in: its label is drawn at it
|
|
1929
|
+
const whole = [...(values.opacity ?? new Array<StyleValue | null>(n).fill(null))];
|
|
1930
|
+
combineLabelOpacity(n, words, values);
|
|
1931
|
+
if (kind === "node") {
|
|
1932
|
+
combineNodeOpacity(n, words, values);
|
|
1933
|
+
}
|
|
1879
1934
|
const va = words.get("_valign");
|
|
1880
1935
|
const ha = words.get("_halign");
|
|
1881
1936
|
if (kind === "node" && (va !== undefined || ha !== undefined)) {
|
|
1882
|
-
values.labelPosition = Array.from({ length: n }, (_, i) =>
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1937
|
+
values.labelPosition = Array.from({ length: n }, (_, i) => labelPosition(va?.[i] ?? null, ha?.[i] ?? null));
|
|
1938
|
+
}
|
|
1939
|
+
// `text-max-width` wraps a label only under `text-wrap: wrap`; unset there, it is 9999 (cytoscape.js 3.34.3
|
|
1940
|
+
// dist/cytoscape.cjs.js line 18484), which wraps nothing but the label's own line breaks.
|
|
1941
|
+
// `text-wrap: ellipsis` cuts the label at the same width instead (3.34.3 line 25254), and
|
|
1942
|
+
// `text-overflow-wrap: anywhere` breaks a wrapped one between any two letters (line 25204).
|
|
1943
|
+
const wrap = words.get("_wrap");
|
|
1944
|
+
const maxWidth = words.get("_maxWidth");
|
|
1945
|
+
const overflow = words.get("_overflowWrap");
|
|
1946
|
+
if (wrap !== undefined) {
|
|
1947
|
+
const cut = (i: number): boolean => wrap[i] === "wrap" || wrap[i] === "ellipsis";
|
|
1948
|
+
values.labelWrapWidth = Array.from({ length: n }, (_, i) =>
|
|
1949
|
+
cut(i) && typeof maxWidth?.[i] === "string" ? Number(maxWidth[i]) : null,
|
|
1886
1950
|
);
|
|
1951
|
+
if (wrap.includes("ellipsis")) {
|
|
1952
|
+
values.labelWrapEllipsis = wrap.map((w) => (w === "ellipsis" ? true : null));
|
|
1953
|
+
}
|
|
1954
|
+
if (overflow?.includes("anywhere") === true) {
|
|
1955
|
+
values.labelWrapAnywhere = wrap.map((w, i) => (w === "wrap" && overflow[i] === "anywhere" ? true : null));
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
if (kind === "node") {
|
|
1959
|
+
combineFace(n, words, values);
|
|
1960
|
+
combineBackgroundGradient(n, words, values, notes);
|
|
1961
|
+
} else {
|
|
1962
|
+
combineArrowFills(n, words, values, notes);
|
|
1963
|
+
combineLineOpacity(n, words.get("_lineOpacity"), values);
|
|
1964
|
+
}
|
|
1965
|
+
combineDashes(kind, n, words, values);
|
|
1966
|
+
combineLabelText(kind, n, words, values);
|
|
1967
|
+
combineLabelDress(kind, n, words, values, notes, whole);
|
|
1968
|
+
combineVisibility(kind, n, words, values);
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* A label's opacity as Cytoscape.js draws it: its `text-opacity` times the element's `opacity` (cytoscape.js 3.34.3
|
|
1973
|
+
* `drawText`: `effectiveOpacity() * text-opacity`), which the label's box and its line round it are drawn at too.
|
|
1974
|
+
* ponytail: a compound parent's opacity, which Cytoscape.js multiplies in as well, is left out
|
|
1975
|
+
* @param n - the element count
|
|
1976
|
+
* @param words - the parts by internal name
|
|
1977
|
+
* @param values - the values, `opacity` still the element's own; changed in place
|
|
1978
|
+
*/
|
|
1979
|
+
function combineLabelOpacity(
|
|
1980
|
+
n: number,
|
|
1981
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
1982
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
1983
|
+
): void {
|
|
1984
|
+
const text = words.get("_textOpacity");
|
|
1985
|
+
const whole = values.opacity;
|
|
1986
|
+
if (text === undefined && whole === undefined) {
|
|
1987
|
+
return;
|
|
1988
|
+
}
|
|
1989
|
+
const col = new Array<StyleValue | null>(n).fill(null);
|
|
1990
|
+
for (let i = 0; i < n; i++) {
|
|
1991
|
+
const t = text?.[i] ?? null;
|
|
1992
|
+
const o = whole?.[i];
|
|
1993
|
+
const v = Math.round((t === null ? 1 : Number(t)) * (typeof o === "number" ? o : 1) * 1e6) / 1e6;
|
|
1994
|
+
// a label at full strength is left unset, as one no rule fades
|
|
1995
|
+
col[i] = v === 1 || !Number.isFinite(v) ? null : v;
|
|
1887
1996
|
}
|
|
1997
|
+
values.labelOpacity = col;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
/**
|
|
2001
|
+
* A node's border and outline as Cytoscape.js draws them: at their own `border-opacity` / `outline-opacity` times the
|
|
2002
|
+
* node's `opacity` (cytoscape.js 3.34.3 `drawNode`: `parentOpacity * borderOpacity`). A ring at full strength is left
|
|
2003
|
+
* unset.
|
|
2004
|
+
* @param n - the element count
|
|
2005
|
+
* @param words - the parts by internal name
|
|
2006
|
+
* @param values - the values, `opacity` still the node's own; changed in place
|
|
2007
|
+
*/
|
|
2008
|
+
function combineNodeOpacity(
|
|
2009
|
+
n: number,
|
|
2010
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2011
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2012
|
+
): void {
|
|
2013
|
+
const whole = values.opacity;
|
|
2014
|
+
for (const [part, p] of [
|
|
2015
|
+
["_ringOpacity", "borderOpacity"],
|
|
2016
|
+
["_outlineRingOpacity", "outerBorderOpacity"],
|
|
2017
|
+
] as const) {
|
|
2018
|
+
const own = words.get(part);
|
|
2019
|
+
if (own === undefined && whole === undefined) {
|
|
2020
|
+
continue;
|
|
2021
|
+
}
|
|
2022
|
+
values[p] = Array.from({ length: n }, (_, i) => {
|
|
2023
|
+
const a = own?.[i] ?? null;
|
|
2024
|
+
const o = whole?.[i];
|
|
2025
|
+
const v = Math.round((a === null ? 1 : Number(a)) * (typeof o === "number" ? o : 1) * 1e6) / 1e6;
|
|
2026
|
+
return v === 1 || !Number.isFinite(v) ? null : v;
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
/**
|
|
2032
|
+
* A dashed line or border as the line it looks like. Cytoscape.js draws `dashed` with `line-dash-pattern` (6 3) or
|
|
2033
|
+
* `border-dash-pattern` (4 2) in pixels whatever the width, and `dotted` as 1 1 (cytoscape.js 3.34.3 `drawEdgePath`,
|
|
2034
|
+
* `drawNode`), so a wide dashed line shows dots and a pattern of long and short dashes a dash-dot. The class is read
|
|
2035
|
+
* from the dashes and gaps against the width, a round or square cap lengthening each dash by the width.
|
|
2036
|
+
* ponytail: the neutral line styles name a class, not a pattern; a dash pattern slot would carry the lengths exactly
|
|
2037
|
+
* @param kind - the target
|
|
2038
|
+
* @param n - the element count
|
|
2039
|
+
* @param words - the parts by internal name
|
|
2040
|
+
* @param values - the values; changed in place
|
|
2041
|
+
*/
|
|
2042
|
+
function combineDashes(
|
|
2043
|
+
kind: StyleTarget,
|
|
2044
|
+
n: number,
|
|
2045
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2046
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2047
|
+
): void {
|
|
2048
|
+
// the line or border, and a node's outline, which is always dashed 4 2 with butt ends (`drawOutline`)
|
|
2049
|
+
const lines: [string, string, number, string, boolean][] =
|
|
2050
|
+
kind === "edge"
|
|
2051
|
+
? [["lineStyle", "width", 3, "6 3", true]]
|
|
2052
|
+
: [
|
|
2053
|
+
["borderStyle", "borderWidth", 0, "4 2", true],
|
|
2054
|
+
["outerBorderStyle", "outerBorderWidth", 0, "4 2", false],
|
|
2055
|
+
];
|
|
2056
|
+
for (const [style, width, fallback, pattern, own] of lines) {
|
|
2057
|
+
const col = values[style];
|
|
2058
|
+
if (col !== undefined) {
|
|
2059
|
+
dashColumn(col, n, values[width], { fallback, pattern }, own ? words : null);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
/**
|
|
2065
|
+
* One line style's dashed lines as the lines they look like.
|
|
2066
|
+
* @param col - the line styles; changed in place
|
|
2067
|
+
* @param n - the element count
|
|
2068
|
+
* @param widths - the lines' widths, when set
|
|
2069
|
+
* @param drawn - what Cytoscape.js draws when they are not set: the width and the dash pattern
|
|
2070
|
+
* @param drawn.fallback - the width
|
|
2071
|
+
* @param drawn.pattern - the dash pattern
|
|
2072
|
+
* @param words - the parts by internal name, or null for an outline, which has no pattern or cap of its own
|
|
2073
|
+
*/
|
|
2074
|
+
function dashColumn(
|
|
2075
|
+
col: (StyleValue | null)[],
|
|
2076
|
+
n: number,
|
|
2077
|
+
widths: readonly (StyleValue | null)[] | undefined,
|
|
2078
|
+
drawn: { fallback: number; pattern: string },
|
|
2079
|
+
words: ReadonlyMap<string, (string | null)[]> | null,
|
|
2080
|
+
): void {
|
|
2081
|
+
for (let i = 0; i < n; i++) {
|
|
2082
|
+
if (col[i] !== "dashed") {
|
|
2083
|
+
continue;
|
|
2084
|
+
}
|
|
2085
|
+
const w = widths?.[i];
|
|
2086
|
+
const look = dashedLook(words, i, drawn.pattern, typeof w === "number" ? w : drawn.fallback);
|
|
2087
|
+
if (look !== null) {
|
|
2088
|
+
col[i] = look;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
/**
|
|
2094
|
+
* One dashed line's look, from its dash pattern (its own `line-dash-pattern` when it has one) and cap.
|
|
2095
|
+
* @param words - the parts by internal name, or null for an outline, which has no pattern or cap of its own
|
|
2096
|
+
* @param i - the element
|
|
2097
|
+
* @param pattern - the pattern Cytoscape.js draws when none is given
|
|
2098
|
+
* @param width - the line's width
|
|
2099
|
+
* @returns the line style, or null when the pattern is not a list of numbers
|
|
2100
|
+
*/
|
|
2101
|
+
function dashedLook(
|
|
2102
|
+
words: ReadonlyMap<string, (string | null)[]> | null,
|
|
2103
|
+
i: number,
|
|
2104
|
+
pattern: string,
|
|
2105
|
+
width: number,
|
|
2106
|
+
): string | null {
|
|
2107
|
+
const dashes = (words?.get("_dashPattern")?.[i] ?? pattern)
|
|
2108
|
+
.split(/[\s,[\]]+/)
|
|
2109
|
+
.filter((t) => t !== "")
|
|
2110
|
+
.map((t) => Number.parseFloat(t));
|
|
2111
|
+
if (dashes.length === 0 || !dashes.every((d) => Number.isFinite(d))) {
|
|
2112
|
+
return null;
|
|
2113
|
+
}
|
|
2114
|
+
return cyjsDashLook(dashes, width, words?.get("_dashCap")?.[i] ?? "butt");
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* A property's values, created (all null) when it has none yet.
|
|
2119
|
+
* @param values - the values by property; changed in place
|
|
2120
|
+
* @param property - the property
|
|
2121
|
+
* @param n - the element count
|
|
2122
|
+
* @returns its values
|
|
2123
|
+
*/
|
|
2124
|
+
function columnOf(values: Record<string, (StyleValue | null)[]>, property: string, n: number): (StyleValue | null)[] {
|
|
2125
|
+
let column = values[property];
|
|
2126
|
+
if (column === undefined) {
|
|
2127
|
+
column = new Array<StyleValue | null>(n).fill(null);
|
|
2128
|
+
values[property] = column;
|
|
2129
|
+
}
|
|
2130
|
+
return column;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
/**
|
|
2134
|
+
* `visibility` with `display` into `visible`. Cytoscape.js leaves the edges of a node hidden with `visibility:
|
|
2135
|
+
* hidden` drawn (only `display: none` takes them away), so such a node is kept and drawn at opacity 0 (its border and
|
|
2136
|
+
* outline too), with no label.
|
|
2137
|
+
* @param kind - the target
|
|
2138
|
+
* @param n - the element count
|
|
2139
|
+
* @param words - the parts by internal name
|
|
2140
|
+
* @param values - the values; changed in place
|
|
2141
|
+
*/
|
|
2142
|
+
function combineVisibility(
|
|
2143
|
+
kind: StyleTarget,
|
|
2144
|
+
n: number,
|
|
2145
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2146
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2147
|
+
): void {
|
|
1888
2148
|
const vis = words.get("_visibility");
|
|
1889
2149
|
const disp = words.get("_display");
|
|
1890
|
-
if (vis
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
2150
|
+
if (vis === undefined && disp === undefined) {
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
const col = new Array<StyleValue | null>(n).fill(null);
|
|
2154
|
+
for (let i = 0; i < n; i++) {
|
|
2155
|
+
const a = vis?.[i] ?? null;
|
|
2156
|
+
const b = disp?.[i] ?? null;
|
|
2157
|
+
if (a === null && b === null) {
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
const keptInvisible = kind === "node" && a === "hidden" && b !== "none";
|
|
2161
|
+
col[i] = keptInvisible || (a !== "hidden" && b !== "none");
|
|
2162
|
+
if (keptInvisible) {
|
|
2163
|
+
// nothing of it is drawn: its body, its border, its outline or its label
|
|
2164
|
+
for (const p of ["opacity", "borderOpacity", "outerBorderOpacity", "labelOpacity"]) {
|
|
2165
|
+
columnOf(values, p, n)[i] = 0;
|
|
1897
2166
|
}
|
|
1898
|
-
|
|
2167
|
+
columnOf(values, "label", n)[i] = "";
|
|
1899
2168
|
}
|
|
1900
|
-
values.visible = col;
|
|
1901
|
-
}
|
|
1902
|
-
if (kind === "edge") {
|
|
1903
|
-
hollowArrows("target", words.get("_targetArrowFill"), values, notes);
|
|
1904
|
-
hollowArrows("source", words.get("_sourceArrowFill"), values, notes);
|
|
1905
2169
|
}
|
|
2170
|
+
values.visible = col;
|
|
1906
2171
|
}
|
|
1907
2172
|
|
|
1908
2173
|
/**
|
|
1909
|
-
*
|
|
1910
|
-
*
|
|
1911
|
-
*
|
|
1912
|
-
* @param
|
|
2174
|
+
* The label's words as Cytoscape.js draws them: `text-transform`, `text-justification`, and `text-rotation` (an
|
|
2175
|
+
* edge's end labels' `source-` / `target-text-rotation` too) as `labelRotation`, `sourceLabelRotation` and
|
|
2176
|
+
* `targetLabelRotation`.
|
|
2177
|
+
* @param kind - the target
|
|
2178
|
+
* @param n - the element count
|
|
2179
|
+
* @param words - the parts by internal name
|
|
2180
|
+
* @param values - the values; changed in place
|
|
1913
2181
|
*/
|
|
1914
|
-
function
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2182
|
+
function combineLabelText(
|
|
2183
|
+
kind: StyleTarget,
|
|
2184
|
+
n: number,
|
|
2185
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2186
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2187
|
+
): void {
|
|
2188
|
+
transformLabels(n, words.get("_transform"), values.label);
|
|
2189
|
+
// cytoscape.js 3.34.3 `labelJustification`: auto lines the lines up against the node, a label beside it on the
|
|
2190
|
+
// left to its right edge
|
|
2191
|
+
const justification = words.get("_justification");
|
|
2192
|
+
if (justification !== undefined && kind === "edge") {
|
|
2193
|
+
combineEdgeJustification(n, justification, words.get("_wrap"), values);
|
|
2194
|
+
} else if (justification !== undefined) {
|
|
2195
|
+
const halign = words.get("_halign");
|
|
2196
|
+
const AUTO: Readonly<Record<string, string>> = {
|
|
2197
|
+
left: "right",
|
|
2198
|
+
right: "left",
|
|
2199
|
+
"left-inside": "left",
|
|
2200
|
+
"right-inside": "right",
|
|
2201
|
+
};
|
|
2202
|
+
values.labelTextAlign = justification.map((j, i) => {
|
|
2203
|
+
if (j === null) {
|
|
2204
|
+
return null;
|
|
1921
2205
|
}
|
|
2206
|
+
return j === "auto" ? (AUTO[halign?.[i] ?? "center"] ?? "center") : j;
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
// an edge's `autorotate` follows its line, which the routes work out (`autorotateLabels`)
|
|
2210
|
+
const rotations: readonly (readonly [string, string])[] = [
|
|
2211
|
+
["_rotation", "labelRotation"],
|
|
2212
|
+
["_sourceRotation", "sourceLabelRotation"],
|
|
2213
|
+
["_targetRotation", "targetLabelRotation"],
|
|
2214
|
+
];
|
|
2215
|
+
for (const [part, property] of rotations) {
|
|
2216
|
+
const rotation = words.get(part);
|
|
2217
|
+
if (rotation !== undefined) {
|
|
2218
|
+
values[property] = rotation.map((r) => (r === null ? null : cyjsAngleDegrees(r)));
|
|
1922
2219
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
/**
|
|
2224
|
+
* A label's `text-transform`: `uppercase` and `lowercase` change its words; anything else leaves them.
|
|
2225
|
+
* @param n - the element count
|
|
2226
|
+
* @param transform - each element's transform
|
|
2227
|
+
* @param label - each element's label; changed in place
|
|
2228
|
+
*/
|
|
2229
|
+
function transformLabels(
|
|
2230
|
+
n: number,
|
|
2231
|
+
transform: readonly (string | null)[] | undefined,
|
|
2232
|
+
label: (StyleValue | null)[] | undefined,
|
|
2233
|
+
): void {
|
|
2234
|
+
if (transform === undefined || label === undefined) {
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
for (let i = 0; i < n; i++) {
|
|
2238
|
+
const text = label[i];
|
|
2239
|
+
if (typeof text === "string" && transform[i] === "uppercase") {
|
|
2240
|
+
label[i] = text.toUpperCase();
|
|
2241
|
+
} else if (typeof text === "string" && transform[i] === "lowercase") {
|
|
2242
|
+
label[i] = text.toLowerCase();
|
|
1927
2243
|
}
|
|
1928
2244
|
}
|
|
1929
2245
|
}
|
|
1930
2246
|
|
|
1931
|
-
/**
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
2247
|
+
/**
|
|
2248
|
+
* An edge label's `text-justification` as Cytoscape.js draws it: every line centered (an edge's text is always
|
|
2249
|
+
* centered, cytoscape.js 3.34.3 `setupTextStyle`), the block moved half its width left for `left` and right for
|
|
2250
|
+
* `right`, and only for a wrapped label (`drawText`), as `labelShiftX`.
|
|
2251
|
+
* @param n - the element count
|
|
2252
|
+
* @param justification - each edge's justification
|
|
2253
|
+
* @param wrap - each edge's `text-wrap`
|
|
2254
|
+
* @param values - the values; changed in place
|
|
2255
|
+
*/
|
|
2256
|
+
function combineEdgeJustification(
|
|
2257
|
+
n: number,
|
|
2258
|
+
justification: readonly (string | null)[],
|
|
2259
|
+
wrap: readonly (string | null)[] | undefined,
|
|
2260
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2261
|
+
): void {
|
|
2262
|
+
const SHIFT: Readonly<Record<string, number>> = { left: -0.5, right: 0.5 };
|
|
2263
|
+
for (let i = 0; i < n; i++) {
|
|
2264
|
+
const shift = wrap?.[i] === "wrap" ? SHIFT[justification[i] ?? ""] : undefined;
|
|
2265
|
+
if (shift !== undefined) {
|
|
2266
|
+
columnOf(values, "labelShiftX", n)[i] = shift;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* A label's outline and background box as Cytoscape.js draws them: the outline only with a `text-outline-width` and
|
|
2273
|
+
* a `text-outline-opacity` above 0, a stroke of twice that width centered on the letters' edges (cytoscape.js
|
|
2274
|
+
* 3.34.3 `drawText`: `lineWidth = 2 * text-outline-width`); the box only with a `text-background-opacity` above 0
|
|
2275
|
+
* (its default is 0), and the line round the box (`labelBorder`); the box and the line reach `text-background-padding`
|
|
2276
|
+
* past the words.
|
|
2277
|
+
* @param kind - the target
|
|
2278
|
+
* @param n - the element count
|
|
2279
|
+
* @param words - the parts by internal name
|
|
2280
|
+
* @param values - the values; changed in place
|
|
2281
|
+
* @param notes - where problems are noted
|
|
2282
|
+
* @param whole - each element's own opacity, which the box is drawn at too
|
|
2283
|
+
*/
|
|
2284
|
+
function combineLabelDress(
|
|
2285
|
+
kind: StyleTarget,
|
|
2286
|
+
n: number,
|
|
2287
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2288
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2289
|
+
notes: StyleNotes,
|
|
2290
|
+
whole: readonly (StyleValue | null)[],
|
|
2291
|
+
): void {
|
|
2292
|
+
const num = (part: string, i: number, fallback: number): number => {
|
|
2293
|
+
const v = words.get(part)?.[i];
|
|
2294
|
+
return v === null || v === undefined ? fallback : Number(v);
|
|
2295
|
+
};
|
|
2296
|
+
const col = (p: string): (StyleValue | null)[] => (values[p] ??= new Array<StyleValue | null>(n).fill(null));
|
|
2297
|
+
const outlined = words.has("_outlineWidth");
|
|
2298
|
+
const boxed = words.has("_backgroundOpacity");
|
|
2299
|
+
const bordered = words.has("_textBorderWidth") && words.has("_textBorderOpacity");
|
|
2300
|
+
// each part is drawn at its own opacity times the element's; the outline at the words' opacity too (drawText)
|
|
2301
|
+
const at = (v: StyleValue | null | undefined): number => (typeof v === "number" ? v : 1);
|
|
2302
|
+
const faded = (v: number): number | null => {
|
|
2303
|
+
const r = Math.round(v * 1e6) / 1e6;
|
|
2304
|
+
return r < 1 ? r : null;
|
|
2305
|
+
};
|
|
2306
|
+
for (let i = 0; i < n && (outlined || boxed || bordered); i++) {
|
|
2307
|
+
const width = num("_outlineWidth", i, 0);
|
|
2308
|
+
const outlineOpacity = num("_outlineOpacity", i, 1);
|
|
2309
|
+
if (outlined && width > 0 && outlineOpacity > 0) {
|
|
2310
|
+
col("labelOutlineColor")[i] = words.get("_outlineColor")?.[i] ?? "#000000";
|
|
2311
|
+
col("labelOutlineWidth")[i] = 2 * width;
|
|
2312
|
+
col("labelOutlineOpacity")[i] = faded(outlineOpacity * at(values.labelOpacity?.[i]));
|
|
2313
|
+
}
|
|
2314
|
+
const boxOpacity = num("_backgroundOpacity", i, 0);
|
|
2315
|
+
const box = boxed && boxOpacity > 0;
|
|
2316
|
+
if (box) {
|
|
2317
|
+
col("labelBackground")[i] = words.get("_backgroundColor")?.[i] ?? "#000000";
|
|
2318
|
+
col("labelBackgroundOpacity")[i] = faded(boxOpacity * at(whole[i]));
|
|
2319
|
+
}
|
|
2320
|
+
const border = bordered && labelBorder(kind, i, words, col, notes, at(whole[i]));
|
|
2321
|
+
if (box || border) {
|
|
2322
|
+
labelBoxShape(kind, i, words, col, notes);
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
/**
|
|
2328
|
+
* A label's box or line round it, sized and shaped: it reaches `text-background-padding` past the words on every
|
|
2329
|
+
* side (0 unset), one font size tall a line (cytoscape.js 3.34.3 `calculateLabelDimensions`), its corners rounded
|
|
2330
|
+
* 2px for round-rectangle (`drawText`); a circle is noted.
|
|
2331
|
+
* @param kind - the target
|
|
2332
|
+
* @param i - the element
|
|
2333
|
+
* @param words - the parts by internal name
|
|
2334
|
+
* @param col - a property's values, created when absent
|
|
2335
|
+
* @param notes - where problems are noted
|
|
2336
|
+
*/
|
|
2337
|
+
function labelBoxShape(
|
|
2338
|
+
kind: StyleTarget,
|
|
2339
|
+
i: number,
|
|
2340
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2341
|
+
col: (p: string) => (StyleValue | null)[],
|
|
2342
|
+
notes: StyleNotes,
|
|
2343
|
+
): void {
|
|
2344
|
+
const padding = words.get("_backgroundPadding")?.[i];
|
|
2345
|
+
col("labelPadding")[i] = padding === null || padding === undefined ? 0 : Number(padding);
|
|
2346
|
+
col("labelLineHeight")[i] = 1;
|
|
2347
|
+
const shape = words.get("_backgroundShape")?.[i];
|
|
2348
|
+
if (shape === "round-rectangle" || shape === "roundrectangle") {
|
|
2349
|
+
col("labelCornerRadius")[i] = 2;
|
|
2350
|
+
} else if (shape === "circle") {
|
|
2351
|
+
// a disc as tall as the box, centered on it: no neutral box has that shape
|
|
2352
|
+
notes.add(STYLE_ISSUE.APPROXIMATED, kind, "labelBackground", { sample: "circle", element: i });
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
/**
|
|
2357
|
+
* The line Cytoscape.js draws round a label's box: only with a `text-border-width` and a `text-border-opacity` above
|
|
2358
|
+
* 0 (both default to 0), in `text-border-color` (black unset), at its opacity times the element's. A double one is
|
|
2359
|
+
* one line a quarter of the width, where `drawText` strokes two such lines half the width apart (cytoscape.js 3.34.3),
|
|
2360
|
+
* noted; dotted and dashed are drawn solid, noted.
|
|
2361
|
+
* @param kind - the target
|
|
2362
|
+
* @param i - the element
|
|
2363
|
+
* @param words - the parts by internal name
|
|
2364
|
+
* @param col - a property's values, created when absent
|
|
2365
|
+
* @param notes - where problems are noted
|
|
2366
|
+
* @param whole - the element's opacity
|
|
2367
|
+
* @returns whether a line is drawn
|
|
2368
|
+
*/
|
|
2369
|
+
function labelBorder(
|
|
2370
|
+
kind: StyleTarget,
|
|
2371
|
+
i: number,
|
|
2372
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
2373
|
+
col: (p: string) => (StyleValue | null)[],
|
|
2374
|
+
notes: StyleNotes,
|
|
2375
|
+
whole: number,
|
|
2376
|
+
): boolean {
|
|
2377
|
+
const num = (part: string): number => Number(words.get(part)?.[i] ?? 0);
|
|
2378
|
+
const [width, opacity] = [num("_textBorderWidth"), num("_textBorderOpacity")];
|
|
2379
|
+
if (!(width > 0 && opacity > 0)) {
|
|
2380
|
+
return false;
|
|
2381
|
+
}
|
|
2382
|
+
const style = words.get("_textBorderStyle")?.[i] ?? "solid";
|
|
2383
|
+
col("labelBorderColor")[i] = words.get("_textBorderColor")?.[i] ?? "#000000";
|
|
2384
|
+
col("labelBorderWidth")[i] = style === "double" ? width / 4 : width;
|
|
2385
|
+
const drawn = Math.round(opacity * whole * 1e6) / 1e6;
|
|
2386
|
+
col("labelBorderOpacity")[i] = drawn < 1 ? drawn : null;
|
|
2387
|
+
if (style === "dotted" || style === "dashed" || style === "double") {
|
|
2388
|
+
notes.add(STYLE_ISSUE.APPROXIMATED, kind, "labelBorderColor", { sample: style, element: i });
|
|
2389
|
+
}
|
|
2390
|
+
return true;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
/**
|
|
2394
|
+
* An autorotated label's turn: along the line between two centers, kept upright (cytoscape.js 3.34.3
|
|
2395
|
+
* `lineAngleFromDelta`: atan(dy / dx), a vertical line turned to +90 whichever way it runs), from 0 up to 360.
|
|
2396
|
+
* @param a - the source's center
|
|
2397
|
+
* @param b - the target's center
|
|
2398
|
+
* @returns the degrees
|
|
2399
|
+
*/
|
|
2400
|
+
function lineDegrees(a: readonly [number, number], b: readonly [number, number]): number {
|
|
2401
|
+
const dx = b[0] - a[0];
|
|
2402
|
+
const angle = Math.atan((b[1] - a[1]) / dx);
|
|
2403
|
+
const turn = ((dx === 0 ? Math.abs(angle) : angle) * 180) / Math.PI;
|
|
2404
|
+
return Number.isFinite(turn) ? Math.round((((turn % 360) + 360) % 360) * 1e6) / 1e6 + 0 : 0;
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
/**
|
|
2408
|
+
* A Cytoscape.js angle (`30deg`, `0.5rad`, a number of radians) in degrees; `none` and `autorotate` (which turns
|
|
2409
|
+
* only an edge's label) are 0.
|
|
2410
|
+
* @param text - the value
|
|
2411
|
+
* @returns the degrees, or null when it is not an angle
|
|
2412
|
+
*/
|
|
2413
|
+
function cyjsAngleDegrees(text: string): number | null {
|
|
2414
|
+
const t = text.trim();
|
|
2415
|
+
if (t === "none" || t === "autorotate") {
|
|
2416
|
+
return 0;
|
|
2417
|
+
}
|
|
2418
|
+
const m = /^(-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)(deg|rad)?$/i.exec(t);
|
|
2419
|
+
if (m === null) {
|
|
2420
|
+
return null;
|
|
2421
|
+
}
|
|
2422
|
+
const x = Number(m[1]);
|
|
2423
|
+
const deg = m[2]?.toLowerCase() === "deg" ? x : (x * 180) / Math.PI;
|
|
2424
|
+
// the neutral rotation runs from 0 up to 360
|
|
2425
|
+
return Math.round((((deg % 360) + 360) % 360) * 1e6) / 1e6 + 0;
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
/**
|
|
2429
|
+
* An edge's `line-opacity` times its `opacity`, which the line is drawn at (cytoscape.js 3.34.3 `drawEdge`:
|
|
2430
|
+
* `effectiveLineOpacity`).
|
|
2431
|
+
* @param n - the element count
|
|
2432
|
+
* @param line - the line opacities, as text
|
|
2433
|
+
* @param values - the values; changed in place
|
|
2434
|
+
*/
|
|
2435
|
+
function combineLineOpacity(
|
|
2436
|
+
n: number,
|
|
2437
|
+
line: readonly (string | null)[] | undefined,
|
|
2438
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2439
|
+
): void {
|
|
2440
|
+
if (line === undefined) {
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
const whole = values.opacity;
|
|
2444
|
+
values.opacity = Array.from({ length: n }, (_, i) => {
|
|
2445
|
+
const a = line[i] === null ? null : Number(line[i]);
|
|
2446
|
+
const b = whole?.[i];
|
|
2447
|
+
if (a === null || !Number.isFinite(a)) {
|
|
2448
|
+
return b ?? null;
|
|
2449
|
+
}
|
|
2450
|
+
return Math.round(a * (typeof b === "number" ? b : 1) * 1e6) / 1e6;
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
/** Where each `background-gradient-direction` runs, in the neutral `fillGradientAngle` degrees. */
|
|
2455
|
+
const GRADIENT_ANGLES: ReadonlyMap<string, number> = new Map([
|
|
2456
|
+
["to-bottom", 90],
|
|
2457
|
+
["to-top", 270],
|
|
2458
|
+
["to-left", 180],
|
|
2459
|
+
["to-right", 0],
|
|
2460
|
+
["to-bottom-right", 45],
|
|
2461
|
+
["to-right-bottom", 45],
|
|
2462
|
+
["to-bottom-left", 135],
|
|
2463
|
+
["to-left-bottom", 135],
|
|
2464
|
+
["to-top-right", 315],
|
|
2465
|
+
["to-right-top", 315],
|
|
2466
|
+
["to-top-left", 225],
|
|
2467
|
+
["to-left-top", 225],
|
|
1936
2468
|
]);
|
|
1937
2469
|
|
|
1938
2470
|
/**
|
|
1939
|
-
*
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1942
|
-
*
|
|
2471
|
+
* A node's `background-fill: linear-gradient` or `radial-gradient` as `fill` (its first stop), `fillGradient` (its
|
|
2472
|
+
* last), `fillGradientAngle` (a linear one's direction), `fillGradientKind`, `fillGradientColors` (every stop, when
|
|
2473
|
+
* there are more than two) and `fillGradientStops` (`background-gradient-stop-positions`, when there is one per
|
|
2474
|
+
* color, as Cytoscape.js uses them).
|
|
2475
|
+
* @param n - the element count
|
|
2476
|
+
* @param words - the parts by internal name
|
|
1943
2477
|
* @param values - the values; changed in place
|
|
1944
2478
|
* @param notes - where problems are noted
|
|
1945
2479
|
*/
|
|
1946
|
-
function
|
|
1947
|
-
|
|
1948
|
-
|
|
2480
|
+
function combineBackgroundGradient(
|
|
2481
|
+
n: number,
|
|
2482
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
1949
2483
|
values: Record<string, (StyleValue | null)[]>,
|
|
1950
2484
|
notes: StyleNotes,
|
|
1951
2485
|
): void {
|
|
1952
|
-
const
|
|
1953
|
-
if (fill === undefined
|
|
2486
|
+
const fill = words.get("_backgroundFill");
|
|
2487
|
+
if (fill === undefined) {
|
|
1954
2488
|
return;
|
|
1955
2489
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
2490
|
+
const stops = words.get("_backgroundStops");
|
|
2491
|
+
const positions = words.get("_backgroundPositions");
|
|
2492
|
+
const direction = words.get("_backgroundDirection");
|
|
2493
|
+
const col = (name: string): (StyleValue | null)[] => (values[name] ??= new Array<StyleValue | null>(n).fill(null));
|
|
2494
|
+
for (let i = 0; i < n; i++) {
|
|
2495
|
+
const radial = fill[i] === "radial-gradient";
|
|
2496
|
+
if (fill[i] !== "linear-gradient" && !radial) {
|
|
1959
2497
|
continue;
|
|
1960
2498
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
notes
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
2499
|
+
// Cytoscape.js's default stop colors are one gray, which draws flat
|
|
2500
|
+
const colors = gradientStopColors(stops?.[i] ?? "#999", {
|
|
2501
|
+
notes,
|
|
2502
|
+
target: "node",
|
|
2503
|
+
property: "fill",
|
|
2504
|
+
element: i,
|
|
2505
|
+
});
|
|
2506
|
+
if (colors.length < 2) {
|
|
2507
|
+
continue;
|
|
2508
|
+
}
|
|
2509
|
+
col("fill")[i] = colors[0];
|
|
2510
|
+
col("fillGradient")[i] = colors.at(-1) ?? null;
|
|
2511
|
+
if (colors.length > 2) {
|
|
2512
|
+
col("fillGradientColors")[i] = colors.join(" ");
|
|
2513
|
+
}
|
|
2514
|
+
const placed = gradientStops(positions?.[i] ?? "");
|
|
2515
|
+
if (placed?.split(" ").length === colors.length) {
|
|
2516
|
+
col("fillGradientStops")[i] = placed;
|
|
2517
|
+
}
|
|
2518
|
+
if (radial) {
|
|
2519
|
+
col("fillGradientKind")[i] = "radial";
|
|
1967
2520
|
} else {
|
|
1968
|
-
|
|
2521
|
+
col("fillGradientAngle")[i] = GRADIENT_ANGLES.get(direction?.[i] ?? "to-bottom") ?? 90;
|
|
1969
2522
|
}
|
|
1970
2523
|
}
|
|
1971
2524
|
}
|
|
1972
2525
|
|
|
2526
|
+
/** An edge's routing settings, each read as Cytoscape.js spells it. */
|
|
2527
|
+
const ROUTE_PARTS: readonly (readonly [keyof CyjsRouteEdge, string, CyjsPropertySpec])[] = [
|
|
2528
|
+
["segmentDistances", "segment-distances", { property: "_segmentDistances", type: "text" }],
|
|
2529
|
+
["segmentWeights", "segment-weights", { property: "_segmentWeights", type: "text" }],
|
|
2530
|
+
["controlPointDistances", "control-point-distances", { property: "_controlPointDistances", type: "text" }],
|
|
2531
|
+
["controlPointWeights", "control-point-weights", { property: "_controlPointWeights", type: "text" }],
|
|
2532
|
+
["controlPointStepSize", "control-point-step-size", { property: "_controlPointStepSize", type: "size" }],
|
|
2533
|
+
["taxiDirection", "taxi-direction", { property: "_taxiDirection", type: "text" }],
|
|
2534
|
+
["taxiTurn", "taxi-turn", { property: "_taxiTurn", type: "text" }],
|
|
2535
|
+
["taxiTurnMinDistance", "taxi-turn-min-distance", { property: "_taxiTurnMinDistance", type: "size" }],
|
|
2536
|
+
["edgeDistances", "edge-distances", { property: "_edgeDistances", type: "text" }],
|
|
2537
|
+
["loopDirection", "loop-direction", { property: "_loopDirection", type: "text" }],
|
|
2538
|
+
["loopSweep", "loop-sweep", { property: "_loopSweep", type: "text" }],
|
|
2539
|
+
["segmentRadii", "segment-radii", { property: "_segmentRadii", type: "text" }],
|
|
2540
|
+
["taxiRadius", "taxi-radius", { property: "_taxiRadius", type: "text" }],
|
|
2541
|
+
["radiusType", "radius-type", { property: "_radiusType", type: "text" }],
|
|
2542
|
+
];
|
|
2543
|
+
|
|
1973
2544
|
/**
|
|
1974
|
-
*
|
|
1975
|
-
*
|
|
2545
|
+
* The routes of the edges Cytoscape.js does not draw straight (`segments`, `taxi`, an `unbundled-bezier` with
|
|
2546
|
+
* control points, a loop) as `bends`, drawn straight through them (`curved` false).
|
|
2547
|
+
* @param graph - the core's elements
|
|
2548
|
+
* @param read - the edges' cells
|
|
2549
|
+
* @param curves - each edge's curve style, in output order
|
|
2550
|
+
* @param nodes - the nodes' values
|
|
2551
|
+
* @param values - the edges' values; changed in place
|
|
2552
|
+
*/
|
|
2553
|
+
function edgeRoutes(
|
|
2554
|
+
graph: CyjsGraph,
|
|
2555
|
+
read: DrawnRead,
|
|
2556
|
+
curves: readonly (StyleValue | null | undefined)[],
|
|
2557
|
+
nodes: CyjsTargetStyles,
|
|
2558
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2559
|
+
): void {
|
|
2560
|
+
const words = new Map(ROUTE_PARTS.map(([key, name, spec]) => [key, drawnColumn(read, name, spec)] as const));
|
|
2561
|
+
const nodeAt = new Map<CyjsElement, number>();
|
|
2562
|
+
nodes.elements.forEach((el, k) => {
|
|
2563
|
+
if (el !== null) {
|
|
2564
|
+
nodeAt.set(el, k);
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
const geometry = (core: number): CyjsRouteNode | null => routeNode(graph.nodes[core], nodeAt, nodes);
|
|
2568
|
+
// an end label's autorotate turns it as the main label's does (cytoscape.js 3.34.3 `calculateLabelAngle`)
|
|
2569
|
+
const turned: readonly (readonly [string, (StyleValue | null | undefined)[]])[] = [
|
|
2570
|
+
["labelRotation", drawnColumn(read, "text-rotation", TEXT_PART)],
|
|
2571
|
+
["sourceLabelRotation", drawnColumn(read, "source-text-rotation", TEXT_PART)],
|
|
2572
|
+
["targetLabelRotation", drawnColumn(read, "target-text-rotation", TEXT_PART)],
|
|
2573
|
+
];
|
|
2574
|
+
const ends = [drawnColumn(read, "source-endpoint", TEXT_PART), drawnColumn(read, "target-endpoint", TEXT_PART)];
|
|
2575
|
+
const loops = new Map<string, number>();
|
|
2576
|
+
const n = read.order.length;
|
|
2577
|
+
let routed: (StyleValue | null)[] | null = null;
|
|
2578
|
+
for (let k = 0; k < n; k++) {
|
|
2579
|
+
const e = read.order[k];
|
|
2580
|
+
const between = edgeNodes(graph, e, geometry);
|
|
2581
|
+
if (between === null) {
|
|
2582
|
+
continue;
|
|
2583
|
+
}
|
|
2584
|
+
const { src, tgt, loop } = between;
|
|
2585
|
+
if (!loop) {
|
|
2586
|
+
autorotateLabels(values, turned, k, n, lineDegrees(src.center, tgt.center));
|
|
2587
|
+
}
|
|
2588
|
+
const edge = routeSettings(words, k, curves[k]);
|
|
2589
|
+
const bends = cyjsRoute(edge, src, tgt, loop ? nextLoopIndex(loops, graph.source[e], edge) : 0);
|
|
2590
|
+
if (bends !== null) {
|
|
2591
|
+
routed ??= values.bends ?? new Array<StyleValue | null>(n).fill(null);
|
|
2592
|
+
routed[k] = bends;
|
|
2593
|
+
columnOf(values, "curved", n)[k] = false;
|
|
2594
|
+
}
|
|
2595
|
+
if (!loop) {
|
|
2596
|
+
edgePorts(edge.curveStyle, [ends[0][k], ends[1][k]], [src, tgt], (p, port) => {
|
|
2597
|
+
columnOf(values, p, n)[k] = port;
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
if (routed !== null) {
|
|
2602
|
+
values.bends = routed;
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
/**
|
|
2607
|
+
* A node's geometry as the routes measure it: its center, its outer size (its border taken in), its box and whether
|
|
2608
|
+
* it is an ellipse.
|
|
2609
|
+
* @param el - the node
|
|
2610
|
+
* @param nodeAt - each node's output index
|
|
2611
|
+
* @param nodes - the nodes' values
|
|
2612
|
+
* @returns the geometry, or null when the node has no position
|
|
2613
|
+
*/
|
|
2614
|
+
function routeNode(
|
|
2615
|
+
el: CyjsElement,
|
|
2616
|
+
nodeAt: ReadonlyMap<CyjsElement, number>,
|
|
2617
|
+
nodes: CyjsTargetStyles,
|
|
2618
|
+
): CyjsRouteNode | null {
|
|
2619
|
+
const k = nodeAt.get(el);
|
|
2620
|
+
const pos = el.json.position;
|
|
2621
|
+
if (k === undefined || !isObject(pos) || typeof pos.x !== "number" || typeof pos.y !== "number") {
|
|
2622
|
+
return null;
|
|
2623
|
+
}
|
|
2624
|
+
const num = (p: string, fallback: number): number => {
|
|
2625
|
+
const v = nodes.values[p]?.[k];
|
|
2626
|
+
return typeof v === "number" ? v : fallback;
|
|
2627
|
+
};
|
|
2628
|
+
const [w, h, bw] = [num("width", 30), num("height", 30), num("borderWidth", 0)];
|
|
2629
|
+
return {
|
|
2630
|
+
center: [pos.x, pos.y],
|
|
2631
|
+
size: [w + bw, h + bw],
|
|
2632
|
+
box: [w, h],
|
|
2633
|
+
ellipse: (nodes.values.shape?.[k] ?? "ellipse") === "ellipse",
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* An edge's two nodes' geometry, and whether it is a loop.
|
|
2639
|
+
* @param graph - the core's elements
|
|
2640
|
+
* @param e - the edge's core index, below 0 for none
|
|
2641
|
+
* @param geometry - a node's geometry
|
|
2642
|
+
* @returns the source's and the target's geometry, or null when either is not known
|
|
2643
|
+
*/
|
|
2644
|
+
function edgeNodes(
|
|
2645
|
+
graph: CyjsGraph,
|
|
2646
|
+
e: number,
|
|
2647
|
+
geometry: (core: number) => CyjsRouteNode | null,
|
|
2648
|
+
): { src: CyjsRouteNode; tgt: CyjsRouteNode; loop: boolean } | null {
|
|
2649
|
+
if (e < 0) {
|
|
2650
|
+
return null;
|
|
2651
|
+
}
|
|
2652
|
+
const loop = graph.source[e] === graph.target[e];
|
|
2653
|
+
const src = geometry(graph.source[e]);
|
|
2654
|
+
const tgt = loop ? src : geometry(graph.target[e]);
|
|
2655
|
+
return src === null || tgt === null ? null : { src, tgt, loop };
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
/**
|
|
2659
|
+
* Turns each of an edge's labels set to `autorotate` along its line.
|
|
2660
|
+
* @param values - the edges' values; changed in place
|
|
2661
|
+
* @param turned - each label's rotation property and its `text-rotation` words
|
|
2662
|
+
* @param k - the edge's output index
|
|
2663
|
+
* @param n - the edge count
|
|
2664
|
+
* @param degrees - the line's turn
|
|
2665
|
+
*/
|
|
2666
|
+
function autorotateLabels(
|
|
2667
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2668
|
+
turned: readonly (readonly [string, (StyleValue | null | undefined)[]])[],
|
|
2669
|
+
k: number,
|
|
2670
|
+
n: number,
|
|
2671
|
+
degrees: number,
|
|
2672
|
+
): void {
|
|
2673
|
+
for (const [property, column] of turned) {
|
|
2674
|
+
if (column[k] === "autorotate") {
|
|
2675
|
+
columnOf(values, property, n)[k] = degrees;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
/**
|
|
2681
|
+
* A loop's place among the loops drawn before it on the same node in the same direction and sweep, which fans them.
|
|
2682
|
+
* @param loops - how many loops each node, direction and sweep has so far; changed in place
|
|
2683
|
+
* @param source - the loop's node
|
|
2684
|
+
* @param edge - the loop's settings
|
|
2685
|
+
* @returns its place, from 0
|
|
2686
|
+
*/
|
|
2687
|
+
function nextLoopIndex(loops: Map<string, number>, source: number, edge: CyjsRouteEdge): number {
|
|
2688
|
+
const key = `${String(source)} ${String(edge.loopDirection)} ${String(edge.loopSweep)}`;
|
|
2689
|
+
const index = loops.get(key) ?? 0;
|
|
2690
|
+
loops.set(key, index + 1);
|
|
2691
|
+
return index;
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
/**
|
|
2695
|
+
* Where an edge's ends meet its nodes, when not where the line from the centers crosses the outlines (cytoscape.js
|
|
2696
|
+
* 3.34.3 `findEndpoints`, `manualEndptToPx`): `inside-to-node` at the center, `x y` offsets from the center (pixels,
|
|
2697
|
+
* or percentages of the node's outer size), an angle clockwise from 12 o'clock on the outline. A `haystack` edge
|
|
2698
|
+
* runs between points `haystack-radius` of the way from the centers to the outlines in a random direction
|
|
2699
|
+
* (`findHaystackPoints`), drawn from the centers, where a radius of 0 (the default) puts them; a taxi edge ignores its
|
|
2700
|
+
* endpoints.
|
|
2701
|
+
* ponytail: an angle meets a polygon's outline where it meets its box; per-shape outlines if a file angles one
|
|
2702
|
+
* @param curve - the curve style
|
|
2703
|
+
* @param words - the source endpoint and the target endpoint, as Cytoscape.js spells them
|
|
2704
|
+
* @param nodes - the source's and the target's geometry
|
|
2705
|
+
* @param put - sets `sourcePort` or `targetPort`
|
|
2706
|
+
*/
|
|
2707
|
+
function edgePorts(
|
|
2708
|
+
curve: string,
|
|
2709
|
+
words: readonly (StyleValue | null | undefined)[],
|
|
2710
|
+
nodes: readonly [CyjsRouteNode, CyjsRouteNode],
|
|
2711
|
+
put: (property: string, port: string) => void,
|
|
2712
|
+
): void {
|
|
2713
|
+
if (curve === "taxi" || curve === "round-taxi") {
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
(["sourcePort", "targetPort"] as const).forEach((p, a) => {
|
|
2717
|
+
const port = curve === "haystack" ? "0,0" : endpointPort(String(words[a] ?? ""), nodes[a]);
|
|
2718
|
+
if (port !== null) {
|
|
2719
|
+
put(p, port);
|
|
2720
|
+
}
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
/**
|
|
2725
|
+
* One `source-endpoint` / `target-endpoint` as a neutral port.
|
|
2726
|
+
* @param text - the value
|
|
2727
|
+
* @param node - the node's geometry
|
|
2728
|
+
* @returns the port, or null where the line meets the outline as it does by default
|
|
2729
|
+
*/
|
|
2730
|
+
function endpointPort(text: string, node: CyjsRouteNode): string | null {
|
|
2731
|
+
const t = text.trim();
|
|
2732
|
+
if (t === "inside-to-node") {
|
|
2733
|
+
return "0,0";
|
|
2734
|
+
}
|
|
2735
|
+
const parts = t.split(/\s+/);
|
|
2736
|
+
const [w, h] = node.size;
|
|
2737
|
+
const r6 = (v: number): string => String(Math.round(v * 1e6) / 1e6 + 0);
|
|
2738
|
+
const fraction = (part: string, size: number): number | null => {
|
|
2739
|
+
const m = /^(-?(?:\d+(?:\.\d*)?|\.\d+))(%|px)?$/.exec(part);
|
|
2740
|
+
if (m === null || Number.isNaN(size) || size <= 0) {
|
|
2741
|
+
return null;
|
|
2742
|
+
}
|
|
2743
|
+
const px = m[2] === "%" ? (Number(m[1]) / 100) * size : Number(m[1]);
|
|
2744
|
+
return px / (size / 2);
|
|
2745
|
+
};
|
|
2746
|
+
if (parts.length === 2) {
|
|
2747
|
+
const [x, y] = [fraction(parts[0], w), fraction(parts[1], h)];
|
|
2748
|
+
return x === null || y === null ? null : `${r6(x)},${r6(-y)}`;
|
|
2749
|
+
}
|
|
2750
|
+
const m = /^(-?(?:\d+(?:\.\d*)?|\.\d+))(deg|rad)$/.exec(t);
|
|
2751
|
+
if (m === null) {
|
|
2752
|
+
return null;
|
|
2753
|
+
}
|
|
2754
|
+
const turn = m[2] === "deg" ? (Number(m[1]) * Math.PI) / 180 : Number(m[1]);
|
|
2755
|
+
// the direction in half sizes, y up, from 12 o'clock clockwise; scaled until it meets the outline
|
|
2756
|
+
const [dx, dy] = [Math.sin(turn) / (w / 2), Math.cos(turn) / (h / 2)];
|
|
2757
|
+
const reach = node.ellipse ? Math.hypot(dx, dy) : Math.max(Math.abs(dx), Math.abs(dy));
|
|
2758
|
+
return reach > 0 ? `${r6(dx / reach)},${r6(dy / reach)}` : null;
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
/**
|
|
2762
|
+
* One edge's routing settings.
|
|
2763
|
+
* @param words - each setting's values, in output order
|
|
2764
|
+
* @param k - the edge's output index
|
|
2765
|
+
* @param curve - its curve style
|
|
2766
|
+
* @returns the settings
|
|
2767
|
+
*/
|
|
2768
|
+
function routeSettings(
|
|
2769
|
+
words: ReadonlyMap<keyof CyjsRouteEdge, readonly (StyleValue | null | undefined)[]>,
|
|
2770
|
+
k: number,
|
|
2771
|
+
curve: StyleValue | null | undefined,
|
|
2772
|
+
): CyjsRouteEdge {
|
|
2773
|
+
const text = (key: keyof CyjsRouteEdge): string | null => {
|
|
2774
|
+
const v = words.get(key)?.[k];
|
|
2775
|
+
return v === null || v === undefined ? null : String(v);
|
|
2776
|
+
};
|
|
2777
|
+
const num = (key: keyof CyjsRouteEdge): number | null => {
|
|
2778
|
+
const v = text(key);
|
|
2779
|
+
return v === null ? null : Number(v);
|
|
2780
|
+
};
|
|
2781
|
+
return {
|
|
2782
|
+
curveStyle: String(curve ?? "haystack"),
|
|
2783
|
+
segmentDistances: text("segmentDistances"),
|
|
2784
|
+
segmentWeights: text("segmentWeights"),
|
|
2785
|
+
controlPointDistances: text("controlPointDistances"),
|
|
2786
|
+
controlPointWeights: text("controlPointWeights"),
|
|
2787
|
+
controlPointStepSize: num("controlPointStepSize"),
|
|
2788
|
+
taxiDirection: text("taxiDirection"),
|
|
2789
|
+
taxiTurn: text("taxiTurn"),
|
|
2790
|
+
taxiTurnMinDistance: num("taxiTurnMinDistance"),
|
|
2791
|
+
edgeDistances: text("edgeDistances"),
|
|
2792
|
+
loopDirection: text("loopDirection"),
|
|
2793
|
+
loopSweep: text("loopSweep"),
|
|
2794
|
+
segmentRadii: text("segmentRadii"),
|
|
2795
|
+
taxiRadius: text("taxiRadius"),
|
|
2796
|
+
radiusType: text("radiusType"),
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
/** A padding read as Cytoscape.js spells it. */
|
|
2801
|
+
const TEXT_PART: CyjsPropertySpec = { property: "_text", type: "text" };
|
|
2802
|
+
|
|
2803
|
+
/**
|
|
2804
|
+
* A node's size as Cytoscape.js draws it: a node that is no compound parent is drawn `padding` larger on every side
|
|
2805
|
+
* (cytoscape.js 3.34.3 draws its shape `width() + 2 * padding()` across).
|
|
2806
|
+
* @param graph - the core's elements
|
|
2807
|
+
* @param read - the nodes' cells
|
|
2808
|
+
* @param values - the nodes' values; changed in place
|
|
2809
|
+
*/
|
|
2810
|
+
function nodeSizes(graph: CyjsGraph, read: DrawnRead, values: Record<string, (StyleValue | null)[]>): void {
|
|
2811
|
+
const padding = drawnColumn(read, "padding", TEXT_PART);
|
|
2812
|
+
const toLabel = (["width", "height"] as const).map((p) => drawnColumn(read, p, SIZE_PART));
|
|
2813
|
+
const n = read.order.length;
|
|
2814
|
+
const col = (p: string): (StyleValue | null)[] => (values[p] ??= new Array<StyleValue | null>(n).fill(null));
|
|
2815
|
+
for (let k = 0; k < n; k++) {
|
|
2816
|
+
const core = read.order[k];
|
|
2817
|
+
const pad = core < 0 || graph.children[core].length > 0 ? 0 : paddingOf(padding[k]);
|
|
2818
|
+
const fitted = toLabel.map((c) => c[k] === "label");
|
|
2819
|
+
if (fitted[0] || fitted[1]) {
|
|
2820
|
+
// `width: label` sizes the node to its label's box (cytoscape.js 3.34.3 `width()` reads the label's
|
|
2821
|
+
// width), padding on each side: the label's side is a minimum of 0, the other keeps its own size
|
|
2822
|
+
col("labelFit")[k] = "bounds";
|
|
2823
|
+
col("labelPaddingX")[k] = pad;
|
|
2824
|
+
col("labelPaddingY")[k] = pad;
|
|
2825
|
+
["width", "height"].forEach((p, a) => {
|
|
2826
|
+
const v = values[p]?.[k];
|
|
2827
|
+
const side = typeof v === "number" ? v : 30;
|
|
2828
|
+
col(p)[k] = fitted[a] ? 0 : side + 2 * pad;
|
|
2829
|
+
});
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
if (pad <= 0) {
|
|
2833
|
+
continue;
|
|
2834
|
+
}
|
|
2835
|
+
for (const p of ["width", "height"]) {
|
|
2836
|
+
const v = values[p]?.[k];
|
|
2837
|
+
col(p)[k] = (typeof v === "number" ? v : 30) + 2 * pad;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
/** The label alignments read as Cytoscape.js's words. */
|
|
2843
|
+
const VALIGN_PART: CyjsPropertySpec = {
|
|
2844
|
+
property: "_valign",
|
|
2845
|
+
type: "enum",
|
|
2846
|
+
enums: ["top", "top-inside", "center", "bottom", "bottom-inside"],
|
|
2847
|
+
};
|
|
2848
|
+
const HALIGN_PART: CyjsPropertySpec = {
|
|
2849
|
+
property: "_halign",
|
|
2850
|
+
type: "enum",
|
|
2851
|
+
enums: ["left", "left-inside", "center", "right", "right-inside"],
|
|
2852
|
+
};
|
|
2853
|
+
|
|
2854
|
+
/**
|
|
2855
|
+
* Where Cytoscape.js pins a label on one axis (cytoscape.js 3.34.3 `recalculateNodeLabelProjection` and
|
|
2856
|
+
* `labelHalign` / `labelValign`): outside, `padding` past the node's side with the label's far edge there; inside,
|
|
2857
|
+
* `padding` short of it with the label's near edge there; centered, at the node's middle.
|
|
2858
|
+
* @param align - the alignment (`left`, `left-inside`, `top`, ...)
|
|
2859
|
+
* @param half - half the node's drawn size on that axis, `padding` included
|
|
2860
|
+
* @param pad - the node's padding
|
|
2861
|
+
* @returns the offset from the node's center and the shift by the label's own size
|
|
2862
|
+
*/
|
|
2863
|
+
function pinnedAxis(align: string, half: number, pad: number): { offset: number; shift: number } {
|
|
2864
|
+
const near = /^(left|top)/.test(align);
|
|
2865
|
+
if (!near && !/^(right|bottom)/.test(align)) {
|
|
2866
|
+
return { offset: 0, shift: 0 };
|
|
2867
|
+
}
|
|
2868
|
+
const side = near ? -1 : 1;
|
|
2869
|
+
return align.endsWith("-inside")
|
|
2870
|
+
? { offset: side * (half - 2 * pad), shift: -side / 2 }
|
|
2871
|
+
: { offset: side * half, shift: side / 2 };
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
/**
|
|
2875
|
+
* A node label with one alignment inside the node and the other outside it (`text-valign: bottom-inside` with
|
|
2876
|
+
* `text-halign: left`): no neutral position says that, so the label is centered, moved to the point Cytoscape.js
|
|
2877
|
+
* puts it at by `labelOffsetX` / `labelOffsetY` (its `text-margin` added) and pinned there by `labelShiftX` /
|
|
2878
|
+
* `labelShiftY`. A node sized to its label keeps the outside side's position, noted.
|
|
2879
|
+
* @param graph - the core's elements
|
|
2880
|
+
* @param read - the nodes' cells
|
|
2881
|
+
* @param values - the nodes' values, sizes already drawn (`nodeSizes`); changed in place
|
|
2882
|
+
*/
|
|
2883
|
+
function mixedLabelPlaces(graph: CyjsGraph, read: DrawnRead, values: Record<string, (StyleValue | null)[]>): void {
|
|
2884
|
+
const va = drawnColumn(read, "text-valign", VALIGN_PART);
|
|
2885
|
+
const ha = drawnColumn(read, "text-halign", HALIGN_PART);
|
|
2886
|
+
const padding = drawnColumn(read, "padding", TEXT_PART);
|
|
2887
|
+
const n = read.order.length;
|
|
2888
|
+
const col = (p: string): (StyleValue | null)[] => (values[p] ??= new Array<StyleValue | null>(n).fill(null));
|
|
2889
|
+
for (let k = 0; k < n; k++) {
|
|
2890
|
+
const v = typeof va[k] === "string" ? String(va[k]) : "top";
|
|
2891
|
+
const h = typeof ha[k] === "string" ? String(ha[k]) : "center";
|
|
2892
|
+
const inside = v.endsWith("-inside") || h.endsWith("-inside");
|
|
2893
|
+
const outside = v === "top" || v === "bottom" || h === "left" || h === "right";
|
|
2894
|
+
if (!inside || !outside) {
|
|
2895
|
+
continue;
|
|
2896
|
+
}
|
|
2897
|
+
if (values.labelFit?.[k] !== undefined && values.labelFit[k] !== null) {
|
|
2898
|
+
read.notes.add(STYLE_ISSUE.APPROXIMATED, "node", "labelPosition", { sample: `${v} ${h}`, element: k });
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2901
|
+
const core = read.order[k];
|
|
2902
|
+
const pad = core < 0 || graph.children[core].length > 0 ? 0 : paddingOf(padding[k]);
|
|
2903
|
+
const size = (p: string): number => {
|
|
2904
|
+
const s = values[p]?.[k];
|
|
2905
|
+
return typeof s === "number" ? s : 30 + 2 * pad;
|
|
2906
|
+
};
|
|
2907
|
+
const x = pinnedAxis(h, size("width") / 2, pad);
|
|
2908
|
+
const y = pinnedAxis(v, size("height") / 2, pad);
|
|
2909
|
+
const add = (p: string, d: number): void => {
|
|
2910
|
+
const was = values[p]?.[k];
|
|
2911
|
+
col(p)[k] = (typeof was === "number" ? was : 0) + d;
|
|
2912
|
+
};
|
|
2913
|
+
col("labelPosition")[k] = "center";
|
|
2914
|
+
add("labelOffsetX", x.offset);
|
|
2915
|
+
add("labelOffsetY", y.offset);
|
|
2916
|
+
col("labelShiftX")[k] = x.shift;
|
|
2917
|
+
col("labelShiftY")[k] = y.shift;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
/** A node size read as Cytoscape.js's word, so `label` is seen. */
|
|
2922
|
+
const SIZE_PART: CyjsPropertySpec = { property: "_size", type: "nodeSize" };
|
|
2923
|
+
|
|
2924
|
+
/**
|
|
2925
|
+
* A node's padding in pixels. A percentage is relative only on a compound parent; on any other node Cytoscape.js
|
|
2926
|
+
* draws its fraction as pixels (`padding()` returns the property's `pfValue`, 0.2 for `20%`).
|
|
2927
|
+
* @param text - the padding as Cytoscape.js spells it, or null
|
|
2928
|
+
* @returns the pixels, 0 for none
|
|
2929
|
+
*/
|
|
2930
|
+
function paddingOf(text: StyleValue | null | undefined): number {
|
|
2931
|
+
if (typeof text !== "string") {
|
|
2932
|
+
return 0;
|
|
2933
|
+
}
|
|
2934
|
+
const x = Number.parseFloat(text);
|
|
2935
|
+
if (!Number.isFinite(x) || x <= 0) {
|
|
2936
|
+
return 0;
|
|
2937
|
+
}
|
|
2938
|
+
return text.trim().endsWith("%") ? x / 100 : x;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
/** The curve style read as Cytoscape.js's word. */
|
|
2942
|
+
const CURVE_PART: CyjsPropertySpec = { property: "_curve", type: "enum", enums: CYJS_CURVE_STYLES };
|
|
2943
|
+
|
|
2944
|
+
/**
|
|
2945
|
+
* Cytoscape.js draws no source or target arrow on a `haystack` edge, its default curve style (cytoscape.js 3.34.3
|
|
2946
|
+
* `drawArrowheads` skips them on haystacks, but still draws the mid arrows): each end arrow of one is `none`.
|
|
2947
|
+
* @param curves - each edge's curve style, null where no rule sets it
|
|
2948
|
+
* @param values - the values; changed in place
|
|
2949
|
+
*/
|
|
2950
|
+
function noArrowsOnHaystacks(
|
|
2951
|
+
curves: readonly (StyleValue | null | undefined)[],
|
|
2952
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
2953
|
+
): void {
|
|
2954
|
+
const n = curves.length;
|
|
2955
|
+
for (const p of ["targetArrow", "sourceArrow"]) {
|
|
2956
|
+
const col = values[p];
|
|
2957
|
+
if (col === undefined) {
|
|
2958
|
+
continue;
|
|
2959
|
+
}
|
|
2960
|
+
for (let i = 0; i < n; i++) {
|
|
2961
|
+
if ((curves[i] ?? "haystack") === "haystack" && col[i] !== null) {
|
|
2962
|
+
col[i] = "none";
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
/**
|
|
2969
|
+
* The outline arrow a hollow `*-arrow-fill` draws for each filled shape that has one (cytoscape.js 3.34.3 strokes the
|
|
2970
|
+
* arrow's path instead of filling it). A hollow square has no outline cap of its own in the neutral vocabulary;
|
|
2971
|
+
* `other:open-square` is drawn as the nearest one.
|
|
2972
|
+
*/
|
|
2973
|
+
const HOLLOW_ARROWS: ReadonlyMap<StyleValue, string> = new Map([
|
|
2974
|
+
["triangle", "triangle-open"],
|
|
2975
|
+
["diamond", "diamond-open"],
|
|
2976
|
+
["circle", "circle-open"],
|
|
2977
|
+
["square", "other:open-square"],
|
|
2978
|
+
]);
|
|
2979
|
+
|
|
2980
|
+
/**
|
|
2981
|
+
* A rule that sets an arrow shape and makes it hollow sets the outline shape (`combineArrowFills` does the same per
|
|
2982
|
+
* element, for a fill and a shape set by different rules).
|
|
2983
|
+
* @param set - the rule's values; changed in place
|
|
2984
|
+
* @param all - every property of the rule
|
|
2985
|
+
*/
|
|
2986
|
+
function hollowArrowsOfRule(set: Record<string, StyleValue>, all: readonly EntryProperty[]): void {
|
|
2987
|
+
for (const p of all) {
|
|
2988
|
+
const shapeProp = /^_(\w+Arrow)Fill$/.exec(p.spec.property)?.[1];
|
|
2989
|
+
const shape = shapeProp === undefined ? undefined : set[shapeProp];
|
|
2990
|
+
if (shapeProp === undefined || shape === undefined || p.parsed.kind !== "word") {
|
|
2991
|
+
continue;
|
|
2992
|
+
}
|
|
2993
|
+
const open = HOLLOW_ARROWS.get(shape);
|
|
2994
|
+
if (open !== undefined && p.parsed.value === "hollow") {
|
|
2995
|
+
set[shapeProp] = open;
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
/**
|
|
3001
|
+
* Turns each arrow whose `*-arrow-fill` is `hollow` into its outline shape. A hollow arrow the vocabulary has no
|
|
3002
|
+
* outline shape for keeps its filled shape and is noted.
|
|
3003
|
+
* @param n - the element count
|
|
3004
|
+
* @param words - the parts by internal name
|
|
3005
|
+
* @param values - the values; changed in place
|
|
3006
|
+
* @param notes - where a hollow arrow drawn filled is noted
|
|
3007
|
+
*/
|
|
3008
|
+
function combineArrowFills(
|
|
3009
|
+
n: number,
|
|
3010
|
+
words: ReadonlyMap<string, (string | null)[]>,
|
|
3011
|
+
values: Record<string, (StyleValue | null)[]>,
|
|
3012
|
+
notes: StyleNotes,
|
|
3013
|
+
): void {
|
|
3014
|
+
for (const p of ["targetArrow", "sourceArrow", "midTargetArrow", "midSourceArrow"]) {
|
|
3015
|
+
const fill = words.get(`_${p}Fill`);
|
|
3016
|
+
const shapes = values[p];
|
|
3017
|
+
if (fill === undefined || shapes === undefined) {
|
|
3018
|
+
continue;
|
|
3019
|
+
}
|
|
3020
|
+
for (let i = 0; i < n; i++) {
|
|
3021
|
+
const shape = shapes[i];
|
|
3022
|
+
if (fill[i] !== "hollow" || shape === null || shape === "none") {
|
|
3023
|
+
continue;
|
|
3024
|
+
}
|
|
3025
|
+
const open = HOLLOW_ARROWS.get(shape);
|
|
3026
|
+
if (open !== undefined) {
|
|
3027
|
+
shapes[i] = open;
|
|
3028
|
+
} else if (!String(shape).includes("open")) {
|
|
3029
|
+
const property = p.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace("-arrow", "-arrow-fill");
|
|
3030
|
+
notes.add(STYLE_ISSUE.NOT_CARRIED, "edge", property, { sample: `hollow ${String(shape)}`, element: i });
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
/**
|
|
3037
|
+
* A node label's position from its vertical and horizontal alignments. Cytoscape.js 3.34 places an `-inside`
|
|
3038
|
+
* alignment against that side of the node, inside it (`recalculateNodeLabelProjection`): `top-inside` with
|
|
3039
|
+
* `center` is `inside-top`, `top-inside` with `left-inside` is `inside-top-left`. One inside and one outside
|
|
3040
|
+
* alignment have no neutral position of their own: the outside side here, its inside part read as centered, which
|
|
3041
|
+
* `mixedLabelPlaces()` replaces with the pinned place once the node's size is known.
|
|
1976
3042
|
* @param v - the vertical alignment, or null
|
|
1977
3043
|
* @param h - the horizontal alignment, or null
|
|
1978
|
-
* @param note - notes an alignment read as another
|
|
1979
3044
|
* @returns the position, or null
|
|
1980
3045
|
*/
|
|
1981
|
-
function labelPosition(v: string | null, h: string | null
|
|
3046
|
+
function labelPosition(v: string | null, h: string | null): StyleValue | null {
|
|
1982
3047
|
if (v === null && h === null) {
|
|
1983
3048
|
return null;
|
|
1984
3049
|
}
|
|
3050
|
+
const vIn = (v ?? "").endsWith("-inside");
|
|
3051
|
+
const hIn = (h ?? "").endsWith("-inside");
|
|
1985
3052
|
const vv = (v ?? "top").replace("-inside", "");
|
|
1986
3053
|
const hh = (h ?? "center").replace("-inside", "");
|
|
1987
|
-
if (
|
|
1988
|
-
|
|
3054
|
+
if (vIn || hIn) {
|
|
3055
|
+
const vOut = vv !== "center" && !vIn;
|
|
3056
|
+
const hOut = hh !== "center" && !hIn;
|
|
3057
|
+
if (!vOut && !hOut) {
|
|
3058
|
+
return INSIDE_POSITIONS.get(`${vv},${hh}`) ?? null;
|
|
3059
|
+
}
|
|
3060
|
+
return POSITIONS.get(`${vIn ? "center" : vv},${hIn ? "center" : hh}`) ?? null;
|
|
1989
3061
|
}
|
|
1990
3062
|
return POSITIONS.get(`${vv},${hh}`) ?? null;
|
|
1991
3063
|
}
|
|
@@ -2091,7 +3163,7 @@ interface Draft {
|
|
|
2091
3163
|
* @param entry - the entry
|
|
2092
3164
|
* @param list - the matched core elements
|
|
2093
3165
|
* @param props - the carried properties
|
|
2094
|
-
* @param
|
|
3166
|
+
* @param all - every property of the entry, the parts combined afterward too
|
|
2095
3167
|
* @returns the draft
|
|
2096
3168
|
*/
|
|
2097
3169
|
function draftOf(
|
|
@@ -2099,7 +3171,7 @@ function draftOf(
|
|
|
2099
3171
|
entry: Entry,
|
|
2100
3172
|
list: readonly number[],
|
|
2101
3173
|
props: readonly EntryProperty[],
|
|
2102
|
-
|
|
3174
|
+
all: readonly EntryProperty[],
|
|
2103
3175
|
): Draft {
|
|
2104
3176
|
const setting = new Map<string, StyleValue>();
|
|
2105
3177
|
const mapping = new Map<string, Mapping>();
|
|
@@ -2131,8 +3203,12 @@ function draftOf(
|
|
|
2131
3203
|
mapping.set(p.spec.property, mapperMapping(ctx, entry, list, p));
|
|
2132
3204
|
}
|
|
2133
3205
|
}
|
|
2134
|
-
|
|
2135
|
-
|
|
3206
|
+
const set: Record<string, StyleValue> = Object.fromEntries(setting);
|
|
3207
|
+
if (ctx.kind === "node") {
|
|
3208
|
+
cyjsPolygonShapes(set);
|
|
3209
|
+
} else {
|
|
3210
|
+
hollowArrowsOfRule(set, all);
|
|
3211
|
+
}
|
|
2136
3212
|
const map = Object.fromEntries(mapping);
|
|
2137
3213
|
const hasMap = mapping.size > 0;
|
|
2138
3214
|
// the predicate is built only for a rule that is not collapsed into a run: a run's rules need no column each
|