@graphty/graph-io 0.3.47 → 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-wWjCRzKj.js → approximations-Bzn3L-je.js} +2 -2
- package/dist/chunks/{approximations-wWjCRzKj.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-DiGq58c3.js → block-iptrlMBb.js} +947 -134
- 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-BE2xir2k.js +157 -0
- package/dist/chunks/codes-BE2xir2k.js.map +1 -0
- package/dist/chunks/{constants-BKwqelYD.js → constants-CKkYLPtt.js} +2 -2
- package/dist/chunks/{constants-BKwqelYD.js.map → constants-CKkYLPtt.js.map} +1 -1
- package/dist/chunks/context-C3p0RQxR.js +664 -0
- package/dist/chunks/context-C3p0RQxR.js.map +1 -0
- 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-DXHx7nwR.js +349 -0
- package/dist/chunks/credentials-DXHx7nwR.js.map +1 -0
- package/dist/chunks/cx-export-Bt6NoqTQ.js +259 -0
- package/dist/chunks/cx-export-Bt6NoqTQ.js.map +1 -0
- package/dist/chunks/descriptor-B28U25x4.js +60 -0
- package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
- package/dist/chunks/descriptor-C-YDhtsn.js +48 -0
- package/dist/chunks/descriptor-C-YDhtsn.js.map +1 -0
- package/dist/chunks/descriptor-DLA5kINx.js +142 -0
- package/dist/chunks/descriptor-DLA5kINx.js.map +1 -0
- package/dist/chunks/{emit-CwU8cUmG.js → emit-BwHQkZle.js} +1690 -103
- package/dist/chunks/emit-BwHQkZle.js.map +1 -0
- package/dist/chunks/{escape-CgzxiYPg.js → escape-CuCIzNMB.js} +12 -12
- package/dist/chunks/{escape-CgzxiYPg.js.map → escape-CuCIzNMB.js.map} +1 -1
- package/dist/chunks/{export-BvqAXCKh.js → export-Cha4dRFz.js} +48 -1780
- package/dist/chunks/export-Cha4dRFz.js.map +1 -0
- package/dist/chunks/{exporter--Mk9gXCJ.js → exporter-BP6otMO6.js} +6 -4
- package/dist/chunks/{exporter--Mk9gXCJ.js.map → exporter-BP6otMO6.js.map} +1 -1
- package/dist/chunks/{exporter-CrDWIyiq.js → exporter-D2CETOMK.js} +1222 -154
- package/dist/chunks/exporter-D2CETOMK.js.map +1 -0
- package/dist/chunks/{exporter-DndFlGSa.js → exporter-D9yMtocA.js} +7 -6
- package/dist/chunks/{exporter-DndFlGSa.js.map → exporter-D9yMtocA.js.map} +1 -1
- package/dist/chunks/exporter-_jrBTnos.js +1009 -0
- package/dist/chunks/exporter-_jrBTnos.js.map +1 -0
- package/dist/chunks/{exporter-CJgfhF-l.js → exporter-nDfxIK5D.js} +9 -7
- package/dist/chunks/{exporter-CJgfhF-l.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-Dq1ntt9q.js → generic-ymWCETAJ.js} +387 -31
- package/dist/chunks/generic-ymWCETAJ.js.map +1 -0
- package/dist/chunks/{importer-CMmeMWlC.js → importer-B92x1xY5.js} +15 -263
- package/dist/chunks/importer-B92x1xY5.js.map +1 -0
- package/dist/chunks/{importer-DiZRmOQG.js → importer-CT9mJ1nn.js} +328 -90
- package/dist/chunks/importer-CT9mJ1nn.js.map +1 -0
- package/dist/chunks/{importer-COTK9Tsl.js → importer-DaLTjbds.js} +116 -1099
- package/dist/chunks/importer-DaLTjbds.js.map +1 -0
- package/dist/chunks/{importer-iFYPEKaJ.js → importer-GREKMdIf.js} +28 -16
- package/dist/chunks/importer-GREKMdIf.js.map +1 -0
- package/dist/chunks/{importer-BSvfrX_h.js → importer-PqaaKKnY.js} +23 -1016
- package/dist/chunks/importer-PqaaKKnY.js.map +1 -0
- package/dist/chunks/{importer-yh_aBCU6.js → importer-Vn5QvmmJ.js} +66 -12
- package/dist/chunks/importer-Vn5QvmmJ.js.map +1 -0
- package/dist/chunks/{importer-e6LGpqHB.js → importer-vRq4h3j5.js} +1470 -354
- package/dist/chunks/importer-vRq4h3j5.js.map +1 -0
- package/dist/chunks/input-CAxt_aV-.js +1397 -0
- package/dist/chunks/input-CAxt_aV-.js.map +1 -0
- package/dist/chunks/{json-elements-DJZRZ6jd.js → json-elements-Cq76WjnZ.js} +4 -4
- package/dist/chunks/{json-elements-DJZRZ6jd.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
- package/dist/chunks/{lexicon-CT69Kd87.js → lexicon-Clf4QIyl.js} +299 -77
- package/dist/chunks/lexicon-Clf4QIyl.js.map +1 -0
- package/dist/chunks/{ontology-export-G4MqRdux.js → ontology-export-OMo91mb0.js} +4 -3
- package/dist/chunks/{ontology-export-G4MqRdux.js.map → ontology-export-OMo91mb0.js.map} +1 -1
- package/dist/chunks/{records-CiaWZrFH.js → records-NJiYvekn.js} +2 -2
- package/dist/chunks/{records-CiaWZrFH.js.map → records-NJiYvekn.js.map} +1 -1
- package/dist/chunks/{format-BpQBx8MZ.js → report-CwMfYa9J.js} +70 -127
- package/dist/chunks/report-CwMfYa9J.js.map +1 -0
- 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-EokFic1V.js +247 -0
- package/dist/chunks/sigv4-EokFic1V.js.map +1 -0
- package/dist/chunks/{styles-BQnsga7p.js → styles-CCs214_3.js} +1300 -168
- 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-UMFdNqze.js +1213 -0
- package/dist/chunks/styles-yed-UMFdNqze.js.map +1 -0
- package/dist/chunks/{text-CzJNFOS9.js → text-ystE2bYi.js} +2 -2
- package/dist/chunks/{text-CzJNFOS9.js.map → text-ystE2bYi.js.map} +1 -1
- package/dist/csv.js +7 -5
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +5 -4
- package/dist/cx.js.map +1 -1
- 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 -10
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +850 -193
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +1189 -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 -4
- package/dist/neo4j.js.map +1 -1
- 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.d.ts +1 -0
- package/dist/sources-cypher.js +1351 -0
- package/dist/sources-cypher.js.map +1 -0
- package/dist/sources-ndex.d.ts +1 -0
- package/dist/sources-ndex.js +278 -0
- package/dist/sources-ndex.js.map +1 -0
- package/dist/sources-rest.d.ts +1 -0
- package/dist/sources-rest.js +1377 -0
- package/dist/sources-rest.js.map +1 -0
- 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/common/report.d.ts +6 -3
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +15 -9
- package/dist/src/common/report.js.map +1 -1
- 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 +118 -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 +1457 -120
- 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 +60 -16
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +883 -131
- 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 +756 -103
- 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 +8 -12
- 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 +749 -148
- 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 +1279 -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 +278 -60
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +10 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -2
- 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/registry.d.ts +173 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +196 -1
- package/dist/src/registry.js.map +1 -1
- package/dist/src/sources/builtins.d.ts +11 -0
- package/dist/src/sources/builtins.d.ts.map +1 -0
- package/dist/src/sources/builtins.js +53 -0
- package/dist/src/sources/builtins.js.map +1 -0
- package/dist/src/sources/codes.d.ts +230 -0
- package/dist/src/sources/codes.d.ts.map +1 -0
- package/dist/src/sources/codes.js +58 -0
- package/dist/src/sources/codes.js.map +1 -0
- package/dist/src/sources/context.d.ts +112 -0
- package/dist/src/sources/context.d.ts.map +1 -0
- package/dist/src/sources/context.js +740 -0
- package/dist/src/sources/context.js.map +1 -0
- package/dist/src/sources/credentials.d.ts +179 -0
- package/dist/src/sources/credentials.d.ts.map +1 -0
- package/dist/src/sources/credentials.js +301 -0
- package/dist/src/sources/credentials.js.map +1 -0
- package/dist/src/sources/cypher/descriptor.d.ts +21 -0
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -0
- package/dist/src/sources/cypher/descriptor.js +124 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -0
- package/dist/src/sources/cypher/flatten.d.ts +72 -0
- package/dist/src/sources/cypher/flatten.d.ts.map +1 -0
- package/dist/src/sources/cypher/flatten.js +279 -0
- package/dist/src/sources/cypher/flatten.js.map +1 -0
- package/dist/src/sources/cypher/index.d.ts +33 -0
- package/dist/src/sources/cypher/index.d.ts.map +1 -0
- package/dist/src/sources/cypher/index.js +511 -0
- package/dist/src/sources/cypher/index.js.map +1 -0
- package/dist/src/sources/cypher/params.d.ts +40 -0
- package/dist/src/sources/cypher/params.d.ts.map +1 -0
- package/dist/src/sources/cypher/params.js +6 -0
- package/dist/src/sources/cypher/params.js.map +1 -0
- package/dist/src/sources/cypher/profiles.d.ts +44 -0
- package/dist/src/sources/cypher/profiles.d.ts.map +1 -0
- package/dist/src/sources/cypher/profiles.js +61 -0
- package/dist/src/sources/cypher/profiles.js.map +1 -0
- package/dist/src/sources/cypher/query-builder.d.ts +123 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -0
- package/dist/src/sources/cypher/query-builder.js +267 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts +21 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.js +185 -0
- package/dist/src/sources/cypher/transports/bolt.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts +15 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js +38 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts +31 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.js +104 -0
- package/dist/src/sources/cypher/transports/neptune-https.js.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts +14 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.js +80 -0
- package/dist/src/sources/cypher/transports/query-api.js.map +1 -0
- package/dist/src/sources/cypher/transports/transport.d.ts +78 -0
- package/dist/src/sources/cypher/transports/transport.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/transport.js +77 -0
- package/dist/src/sources/cypher/transports/transport.js.map +1 -0
- package/dist/src/sources/cypher/types-map.d.ts +91 -0
- package/dist/src/sources/cypher/types-map.d.ts.map +1 -0
- package/dist/src/sources/cypher/types-map.js +306 -0
- package/dist/src/sources/cypher/types-map.js.map +1 -0
- package/dist/src/sources/define.d.ts +47 -0
- package/dist/src/sources/define.d.ts.map +1 -0
- package/dist/src/sources/define.js +173 -0
- package/dist/src/sources/define.js.map +1 -0
- package/dist/src/sources/fail.d.ts +33 -0
- package/dist/src/sources/fail.d.ts.map +1 -0
- package/dist/src/sources/fail.js +49 -0
- package/dist/src/sources/fail.js.map +1 -0
- package/dist/src/sources/ids.d.ts +69 -0
- package/dist/src/sources/ids.d.ts.map +1 -0
- package/dist/src/sources/ids.js +69 -0
- package/dist/src/sources/ids.js.map +1 -0
- package/dist/src/sources/ndex/client.d.ts +31 -0
- package/dist/src/sources/ndex/client.d.ts.map +1 -0
- package/dist/src/sources/ndex/client.js +90 -0
- package/dist/src/sources/ndex/client.js.map +1 -0
- package/dist/src/sources/ndex/descriptor.d.ts +10 -0
- package/dist/src/sources/ndex/descriptor.d.ts.map +1 -0
- package/dist/src/sources/ndex/descriptor.js +55 -0
- package/dist/src/sources/ndex/descriptor.js.map +1 -0
- package/dist/src/sources/ndex/expand.d.ts +20 -0
- package/dist/src/sources/ndex/expand.d.ts.map +1 -0
- package/dist/src/sources/ndex/expand.js +87 -0
- package/dist/src/sources/ndex/expand.js.map +1 -0
- package/dist/src/sources/ndex/index.d.ts +25 -0
- package/dist/src/sources/ndex/index.d.ts.map +1 -0
- package/dist/src/sources/ndex/index.js +191 -0
- package/dist/src/sources/ndex/index.js.map +1 -0
- package/dist/src/sources/ndex/params.d.ts +17 -0
- package/dist/src/sources/ndex/params.d.ts.map +1 -0
- package/dist/src/sources/ndex/params.js +6 -0
- package/dist/src/sources/ndex/params.js.map +1 -0
- package/dist/src/sources/ndex/share-url.d.ts +40 -0
- package/dist/src/sources/ndex/share-url.d.ts.map +1 -0
- package/dist/src/sources/ndex/share-url.js +64 -0
- package/dist/src/sources/ndex/share-url.js.map +1 -0
- package/dist/src/sources/params.d.ts +31 -0
- package/dist/src/sources/params.d.ts.map +1 -0
- package/dist/src/sources/params.js +6 -0
- package/dist/src/sources/params.js.map +1 -0
- package/dist/src/sources/registry.d.ts +118 -0
- package/dist/src/sources/registry.d.ts.map +1 -0
- package/dist/src/sources/registry.js +193 -0
- package/dist/src/sources/registry.js.map +1 -0
- package/dist/src/sources/rest/descriptor.d.ts +16 -0
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -0
- package/dist/src/sources/rest/descriptor.js +76 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -0
- package/dist/src/sources/rest/index.d.ts +14 -0
- package/dist/src/sources/rest/index.d.ts.map +1 -0
- package/dist/src/sources/rest/index.js +13 -0
- package/dist/src/sources/rest/index.js.map +1 -0
- package/dist/src/sources/rest/mapping.d.ts +30 -0
- package/dist/src/sources/rest/mapping.d.ts.map +1 -0
- package/dist/src/sources/rest/mapping.js +362 -0
- package/dist/src/sources/rest/mapping.js.map +1 -0
- package/dist/src/sources/rest/openalex.d.ts +27 -0
- package/dist/src/sources/rest/openalex.d.ts.map +1 -0
- package/dist/src/sources/rest/openalex.js +269 -0
- package/dist/src/sources/rest/openalex.js.map +1 -0
- package/dist/src/sources/rest/paging.d.ts +53 -0
- package/dist/src/sources/rest/paging.d.ts.map +1 -0
- package/dist/src/sources/rest/paging.js +138 -0
- package/dist/src/sources/rest/paging.js.map +1 -0
- package/dist/src/sources/rest/params.d.ts +216 -0
- package/dist/src/sources/rest/params.d.ts.map +1 -0
- package/dist/src/sources/rest/params.js +7 -0
- package/dist/src/sources/rest/params.js.map +1 -0
- package/dist/src/sources/rest/records.d.ts +41 -0
- package/dist/src/sources/rest/records.d.ts.map +1 -0
- package/dist/src/sources/rest/records.js +240 -0
- package/dist/src/sources/rest/records.js.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts +10 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.js +47 -0
- package/dist/src/sources/rest/samples/deps-dev.js.map +1 -0
- package/dist/src/sources/rest/samples/string.d.ts +9 -0
- package/dist/src/sources/rest/samples/string.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/string.js +42 -0
- package/dist/src/sources/rest/samples/string.js.map +1 -0
- package/dist/src/sources/rest/selectors.d.ts +41 -0
- package/dist/src/sources/rest/selectors.d.ts.map +1 -0
- package/dist/src/sources/rest/selectors.js +81 -0
- package/dist/src/sources/rest/selectors.js.map +1 -0
- package/dist/src/sources/rest/source.d.ts +67 -0
- package/dist/src/sources/rest/source.d.ts.map +1 -0
- package/dist/src/sources/rest/source.js +650 -0
- package/dist/src/sources/rest/source.js.map +1 -0
- package/dist/src/sources/rest/templates.d.ts +38 -0
- package/dist/src/sources/rest/templates.d.ts.map +1 -0
- package/dist/src/sources/rest/templates.js +125 -0
- package/dist/src/sources/rest/templates.js.map +1 -0
- package/dist/src/sources/run.d.ts +93 -0
- package/dist/src/sources/run.d.ts.map +1 -0
- package/dist/src/sources/run.js +673 -0
- package/dist/src/sources/run.js.map +1 -0
- package/dist/src/sources/sha256.d.ts +12 -0
- package/dist/src/sources/sha256.d.ts.map +1 -0
- package/dist/src/sources/sha256.js +95 -0
- package/dist/src/sources/sha256.js.map +1 -0
- package/dist/src/sources/sigv4.d.ts +26 -0
- package/dist/src/sources/sigv4.d.ts.map +1 -0
- package/dist/src/sources/sigv4.js +184 -0
- package/dist/src/sources/sigv4.js.map +1 -0
- 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/testing.d.ts +96 -0
- package/dist/src/sources/testing.d.ts.map +1 -0
- package/dist/src/sources/testing.js +138 -0
- package/dist/src/sources/testing.js.map +1 -0
- package/dist/src/sources/types.d.ts +696 -0
- package/dist/src/sources/types.d.ts.map +1 -0
- package/dist/src/sources/types.js +10 -0
- package/dist/src/sources/types.js.map +1 -0
- 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 +82 -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 +1037 -35
- 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 +5 -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 +216 -12
- 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 +48 -2
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +463 -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 +204 -44
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +97 -3
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +413 -79
- 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 +46 -3
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +632 -22
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/cytoscape/translate.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/translate.js +10 -10
- package/dist/src/styles/cytoscape/translate.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +50 -0
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +315 -37
- 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/block.d.ts.map +1 -1
- package/dist/src/styles/io/block.js +9 -0
- package/dist/src/styles/io/block.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 +13 -4
- 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 +13 -1
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +53 -6
- 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 +638 -5
- 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 +218 -1
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/src/types.d.ts +19 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/styles.js +29 -238
- package/dist/styles.js.map +1 -1
- package/dist/xgmml.js +3 -3
- package/docs/samples/people.json +6 -0
- package/package.json +53 -8
- package/src/common/report.ts +27 -7
- package/src/formats/cx/importer.ts +6 -1
- package/src/formats/cx/styles.ts +144 -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 +1657 -154
- 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 +1144 -142
- 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 +854 -111
- package/src/formats/graphml/styles-plain.ts +8 -23
- package/src/formats/graphml/styles-yed.ts +821 -159
- 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 +1382 -133
- package/src/formats/pajek/syntax.ts +27 -2
- package/src/formats/xgmml/emit.ts +73 -5
- package/src/formats/xgmml/styles.ts +331 -71
- package/src/index.ts +94 -0
- 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/registry.ts +326 -1
- package/src/sources/builtins.ts +63 -0
- package/src/sources/codes.ts +235 -0
- package/src/sources/context.ts +894 -0
- package/src/sources/credentials.ts +409 -0
- package/src/sources/cypher/descriptor.ts +131 -0
- package/src/sources/cypher/flatten.ts +323 -0
- package/src/sources/cypher/index.ts +628 -0
- package/src/sources/cypher/params.ts +41 -0
- package/src/sources/cypher/profiles.ts +78 -0
- package/src/sources/cypher/query-builder.ts +327 -0
- package/src/sources/cypher/transports/bolt.ts +228 -0
- package/src/sources/cypher/transports/neptune-analytics.ts +41 -0
- package/src/sources/cypher/transports/neptune-https.ts +122 -0
- package/src/sources/cypher/transports/query-api.ts +100 -0
- package/src/sources/cypher/transports/transport.ts +139 -0
- package/src/sources/cypher/types-map.ts +418 -0
- package/src/sources/define.ts +195 -0
- package/src/sources/fail.ts +70 -0
- package/src/sources/ids.ts +80 -0
- package/src/sources/ndex/client.ts +102 -0
- package/src/sources/ndex/descriptor.ts +64 -0
- package/src/sources/ndex/expand.ts +100 -0
- package/src/sources/ndex/index.ts +235 -0
- package/src/sources/ndex/params.ts +17 -0
- package/src/sources/ndex/share-url.ts +84 -0
- package/src/sources/params.ts +32 -0
- package/src/sources/registry.ts +325 -0
- package/src/sources/rest/descriptor.ts +79 -0
- package/src/sources/rest/index.ts +22 -0
- package/src/sources/rest/mapping.ts +401 -0
- package/src/sources/rest/openalex.ts +288 -0
- package/src/sources/rest/paging.ts +180 -0
- package/src/sources/rest/params.ts +243 -0
- package/src/sources/rest/records.ts +289 -0
- package/src/sources/rest/samples/deps-dev.ts +49 -0
- package/src/sources/rest/samples/string.ts +44 -0
- package/src/sources/rest/selectors.ts +91 -0
- package/src/sources/rest/source.ts +776 -0
- package/src/sources/rest/templates.ts +151 -0
- package/src/sources/run.ts +793 -0
- package/src/sources/sha256.ts +99 -0
- package/src/sources/sigv4.ts +209 -0
- 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/testing.ts +210 -0
- package/src/sources/types.ts +776 -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 +99 -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 +1193 -38
- package/src/styles/cyjs/defaults-table.ts +5 -0
- package/src/styles/cyjs/emit.ts +247 -16
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +498 -28
- package/src/styles/cyjs/routes.ts +432 -0
- package/src/styles/cytoscape/charts.ts +684 -0
- package/src/styles/cytoscape/emit.ts +220 -44
- package/src/styles/cytoscape/lexicon.ts +459 -80
- package/src/styles/cytoscape/mappings.ts +108 -0
- package/src/styles/cytoscape/resolve.ts +763 -23
- package/src/styles/cytoscape/translate.ts +11 -11
- package/src/styles/defaults.ts +436 -38
- package/src/styles/index.ts +5 -0
- package/src/styles/internal.ts +1 -0
- package/src/styles/io/block.ts +10 -0
- package/src/styles/io/generic.ts +79 -23
- package/src/styles/io/round-trip.ts +202 -0
- package/src/styles/io/writer.ts +14 -4
- 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 +61 -6
- package/src/styles/slots.ts +25 -0
- package/src/styles/types.ts +658 -4
- package/src/styles/vocabulary.ts +226 -3
- package/src/types.ts +19 -5
- package/dist/chunks/block-DiGq58c3.js.map +0 -1
- package/dist/chunks/choose--jM0yYCo.js +0 -57
- package/dist/chunks/choose--jM0yYCo.js.map +0 -1
- package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
- package/dist/chunks/emit-CwU8cUmG.js.map +0 -1
- package/dist/chunks/export-BvqAXCKh.js.map +0 -1
- package/dist/chunks/exporter-CrDWIyiq.js.map +0 -1
- package/dist/chunks/format-BpQBx8MZ.js.map +0 -1
- package/dist/chunks/generic-Dq1ntt9q.js.map +0 -1
- package/dist/chunks/importer-BSvfrX_h.js.map +0 -1
- package/dist/chunks/importer-CMmeMWlC.js.map +0 -1
- package/dist/chunks/importer-COTK9Tsl.js.map +0 -1
- package/dist/chunks/importer-DiZRmOQG.js.map +0 -1
- package/dist/chunks/importer-e6LGpqHB.js.map +0 -1
- package/dist/chunks/importer-iFYPEKaJ.js.map +0 -1
- package/dist/chunks/importer-yh_aBCU6.js.map +0 -1
- package/dist/chunks/lexicon-CT69Kd87.js.map +0 -1
- package/dist/chunks/styles-BQnsga7p.js.map +0 -1
- package/dist/chunks/styles-D3fRphrO.js +0 -690
- package/dist/chunks/styles-D3fRphrO.js.map +0 -1
- package/dist/chunks/styles-yed-BF5x3_Y5.js +0 -842
- package/dist/chunks/styles-yed-BF5x3_Y5.js.map +0 -1
- package/dist/chunks/writer-DMKvthQE.js +0 -448
- package/dist/chunks/writer-DMKvthQE.js.map +0 -1
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pajek styles: each vertex's shape keyword and drawing parameters (`ic`, `bc`, `bw`, `x_fact`, `y_fact`, `lc`, `fos`)
|
|
3
|
-
* and each line's `c`, `w` and `p`, read the way Pajek draws them
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* and each line's `c`, `w` and `p`, read the way Pajek 6.02 draws them (parameters carried from line to line, `CARRIED`),
|
|
4
|
+
* with Pajek's own defaults beneath (a #ffd9bc ellipse with a #660000 border, grey arcs with an arrow at the target,
|
|
5
|
+
* teal edges). Colors are Pajek's: the dvips names and the ten Pajek adds, `GrayNN`, `RGBrrggbb`, `RGB(r,g,b)` and the
|
|
6
|
+
* CMYK forms. Lengths are in PostScript points, the unit of Pajek's EPS and SVG export, where the drawing's [0,1] square
|
|
7
|
+
* is [0,500] (`PAJEK_POINTS_PER_UNIT`): a vertex is Pajek's normal size 20 times its `x_fact` and `y_fact`,
|
|
8
|
+
* `bw` and `fos` are points as written, an arc is `w` wide and an edge twice `w`.
|
|
7
9
|
*
|
|
8
10
|
* Writing: the same parameters from what graphty draws, leaving out what Pajek draws by default; a color that is a
|
|
9
11
|
* dvips name is written by name, any other as `RGBrrggbb`, so colors are exact. The `graphty.styles` block, with the
|
|
10
12
|
* per-element values its rules read inside it (Pajek has no other place for them), is one comment line,
|
|
11
13
|
* `% graphty.styles <json>`, which Pajek skips and graph-io reads back.
|
|
12
14
|
*/
|
|
15
|
+
import { explicitWeights } from "../../common/weights.js";
|
|
13
16
|
import { canonColor, colorOpacity } from "../../styles/canon/color.js";
|
|
14
17
|
import { DVIPS_COLORS } from "../../styles/canon/color-tables.js";
|
|
15
18
|
import { canonEnum } from "../../styles/canon/enums.js";
|
|
16
19
|
import { canonNumber } from "../../styles/canon/number.js";
|
|
20
|
+
import { noteAt } from "../../styles/canon/site.js";
|
|
17
21
|
import { canonText } from "../../styles/canon/text.js";
|
|
22
|
+
import { STYLE_ISSUE } from "../../styles/codes.js";
|
|
23
|
+
import { toolDefaults } from "../../styles/defaults.js";
|
|
18
24
|
import { StyleApproximations } from "../../styles/io/approximations.js";
|
|
19
|
-
import {
|
|
25
|
+
import { styleBlockLosses, writeStyleBlock } from "../../styles/io/block.js";
|
|
26
|
+
import { elementValues, takeFromBlock } from "../../styles/io/round-trip.js";
|
|
20
27
|
import { StyleNotes } from "../../styles/notes.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
28
|
+
import { plainCell } from "../../styles/plan/resolve.js";
|
|
29
|
+
import { graphvizFontName, postscriptFont } from "../dot/drawing.js";
|
|
23
30
|
import { valueColumns } from "../graphml/styles-yed.js";
|
|
24
|
-
import {
|
|
31
|
+
import { drawLines, drawsLineLabels, drawVertices } from "./draw.js";
|
|
32
|
+
import { LABEL_COLUMN, PAJEK_STYLE_COMMENT, SHAPE_COLUMN, VALUE_COLUMN } from "./syntax.js";
|
|
25
33
|
/**
|
|
26
|
-
* What the Pajek writer holds natively: the vertex label, the vertex shape keyword
|
|
34
|
+
* What the Pajek writer holds natively: the vertex label, the vertex shape keyword (a polygon only as Pajek's diamond,
|
|
35
|
+
* `shapePoints` with its `q`) and drawing parameters, the line
|
|
27
36
|
* parameters, and the arrows Pajek draws on arcs. The `graphty.styles` block is a comment line the writer places itself.
|
|
28
37
|
* @category Built-in formats
|
|
29
38
|
*/
|
|
30
39
|
export const PAJEK_STYLE_CAPABILITIES = Object.freeze({
|
|
40
|
+
tool: "pajek",
|
|
31
41
|
node: Object.freeze([
|
|
32
42
|
"label",
|
|
33
43
|
"fill",
|
|
@@ -36,23 +46,130 @@ export const PAJEK_STYLE_CAPABILITIES = Object.freeze({
|
|
|
36
46
|
"borderColor",
|
|
37
47
|
"borderWidth",
|
|
38
48
|
"shape",
|
|
49
|
+
"shapePoints",
|
|
39
50
|
"width",
|
|
40
51
|
"height",
|
|
41
52
|
"labelColor",
|
|
42
53
|
"labelSize",
|
|
54
|
+
"labelFont",
|
|
55
|
+
"labelPosition",
|
|
56
|
+
"labelOffsetX",
|
|
57
|
+
"labelOffsetY",
|
|
58
|
+
"labelShiftX",
|
|
59
|
+
]),
|
|
60
|
+
edge: Object.freeze([
|
|
61
|
+
"color",
|
|
62
|
+
"opacity",
|
|
63
|
+
"width",
|
|
64
|
+
"lineStyle",
|
|
65
|
+
"sourceArrow",
|
|
66
|
+
"targetArrow",
|
|
67
|
+
"arrowPosition",
|
|
68
|
+
"label",
|
|
69
|
+
"labelColor",
|
|
70
|
+
"labelSize",
|
|
71
|
+
"labelFont",
|
|
43
72
|
]),
|
|
44
|
-
edge: Object.freeze(["color", "opacity", "width", "lineStyle", "sourceArrow", "targetArrow"]),
|
|
45
73
|
block: "native",
|
|
46
74
|
});
|
|
47
75
|
/**
|
|
48
|
-
* Pajek's
|
|
49
|
-
*
|
|
76
|
+
* Pajek's normal vertex size, in points: what `x_fact` and `y_fact` multiply (the manual, p. 89, names `x_fact` and
|
|
77
|
+
* `y_fact` "magnification" without stating the value).
|
|
78
|
+
* Measured in Pajek 6.02's own SVG export (`test/fidelity/oracles/pajek-*.svg`): a vertex with no size parameter is
|
|
79
|
+
* drawn 20 across, and `x_fact 1.54` 30.8, on the drawing's [0,500] square.
|
|
50
80
|
*/
|
|
51
|
-
const
|
|
81
|
+
const PAJEK_VERTEX_SIZE = 20;
|
|
82
|
+
/**
|
|
83
|
+
* How far past its vertex size Pajek draws its man and woman figures, across and up: Pajek 6.02's SVG export draws
|
|
84
|
+
* them as paths that reach beyond the vertex's own square, a man 2.5 times its size across and 6.49 times its size
|
|
85
|
+
* tall, a woman (her skirt and arms wider) 3 times across and 6.48 tall (`pajek-specimen-node-shapes`, vertices 9 and
|
|
86
|
+
* 10 at `x_fact 0.5`: the man's path spans x -12.51..12.51 and y -32.74..32.13, the woman's -15.02..15.02 and
|
|
87
|
+
* -32.99..31.79, around a size of 10).
|
|
88
|
+
*/
|
|
89
|
+
const PAJEK_FIGURES = new Map([
|
|
90
|
+
["other:man", [2.502, 6.487]],
|
|
91
|
+
["other:woman", [3.003, 6.478]],
|
|
92
|
+
]);
|
|
93
|
+
/**
|
|
94
|
+
* Points per coordinate unit: "When Postscript picture is obtained, the square [0,1]x[0,1] is transformed to
|
|
95
|
+
* [0,500]x[0,500]" (Pajek, "Pajek to EPS", http://mrvar.fdv.uni-lj.si/pajek/DrawEPS.htm).
|
|
96
|
+
*/
|
|
97
|
+
export const PAJEK_POINTS_PER_UNIT = 500;
|
|
52
98
|
/** The vertex parameters read as styles. */
|
|
53
|
-
const NODE_KEYS = [
|
|
99
|
+
const NODE_KEYS = [
|
|
100
|
+
"ic",
|
|
101
|
+
"bc",
|
|
102
|
+
"bw",
|
|
103
|
+
"s_size",
|
|
104
|
+
"x_fact",
|
|
105
|
+
"y_fact",
|
|
106
|
+
"phi",
|
|
107
|
+
"q",
|
|
108
|
+
"lc",
|
|
109
|
+
"fos",
|
|
110
|
+
"font",
|
|
111
|
+
"lr",
|
|
112
|
+
"lphi",
|
|
113
|
+
"la",
|
|
114
|
+
];
|
|
54
115
|
/** The line parameters read as styles. */
|
|
55
|
-
const EDGE_KEYS = ["c", "w", "p"];
|
|
116
|
+
const EDGE_KEYS = ["c", "w", "p", "s", "ap", "l", "lc", "fos", "font"];
|
|
117
|
+
/**
|
|
118
|
+
* What Pajek carries from one line of a section to the next. A line (arc or edge) that does not set one of these
|
|
119
|
+
* parameters is drawn with the value the line before it set. A vertex line that sets no parameter and names no shape
|
|
120
|
+
* is drawn exactly as the vertex line before it; a vertex line that sets any starts again from Pajek's defaults.
|
|
121
|
+
* Measured in Pajek 6.02's own SVG export: `test/fidelity/oracles/pajek-kdorola.svg` (vertices 2 to 59, which set
|
|
122
|
+
* nothing, drawn with vertex 1's `lr 11 lphi 285 fos 9`, and 61 on as vertex 60's `box`), `pajek-1crn.svg` (vertex 3
|
|
123
|
+
* drawn as vertex 2), `pajek-synth-lines.svg` (arc 3, which sets `w 3` but no `c`, drawn in arc 2's `c Blue`), and
|
|
124
|
+
* the generated `shapes-and-lines.net` (vertex 5 at the default size after vertex 4's `x_fact 8`). A line's label `l`
|
|
125
|
+
* is its own; its label's color, size and font are not carried here, as they only show with a label.
|
|
126
|
+
*/
|
|
127
|
+
const CARRIED = {
|
|
128
|
+
node: [SHAPE_COLUMN, ...NODE_KEYS],
|
|
129
|
+
edge: ["c", "w", "p", "s", "ap"],
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* What Pajek 6.02 carries from line to line as it reads: not the pattern `p`, which the writer still restates
|
|
133
|
+
* (`pajek-synth-lines`: edge `3 10` after `1 8 ... p Dots` and arc `5 6 -1` after a `p Solid` are drawn as if no line
|
|
134
|
+
* before set one).
|
|
135
|
+
*/
|
|
136
|
+
const CARRIED_LINE = CARRIED.edge.filter((key) => key !== "p");
|
|
137
|
+
/** The width Pajek draws an edge (undirected) at for each unit of `w`; an arc is drawn `w` wide. */
|
|
138
|
+
const EDGE_WIDTH_PER_W = 2;
|
|
139
|
+
/** The color and width Pajek draws an arc with when it sets no `c` or `w` (an edge's are the tool defaults). */
|
|
140
|
+
const ARC_DEFAULTS = { color: "#999999", width: 1 };
|
|
141
|
+
/**
|
|
142
|
+
* A getter that gives an element the parameters an element before it set, as Pajek reads them: for a line each
|
|
143
|
+
* parameter it leaves out, for a vertex all of them when it sets none (`CARRIED`).
|
|
144
|
+
* @param keys - the parameters carried
|
|
145
|
+
* @param whole - true for vertices: carried only to an element that sets none, and then all together
|
|
146
|
+
* @returns for each element in order, its getter
|
|
147
|
+
*/
|
|
148
|
+
function carriedParams(keys, whole) {
|
|
149
|
+
let last = new Map();
|
|
150
|
+
return (get) => {
|
|
151
|
+
const own = new Map();
|
|
152
|
+
for (const key of keys) {
|
|
153
|
+
const v = get(key);
|
|
154
|
+
if (v !== null) {
|
|
155
|
+
own.set(key, v);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (whole) {
|
|
159
|
+
if (own.size > 0) {
|
|
160
|
+
last = own;
|
|
161
|
+
return get;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
for (const [key, v] of own) {
|
|
166
|
+
last.set(key, v);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const carried = last;
|
|
170
|
+
return (key) => get(key) ?? (keys.includes(key) ? (carried.get(key) ?? null) : null);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
56
173
|
/** The style column marking arcs, which Pajek draws with an arrow at the target. */
|
|
57
174
|
const DIRECTED_KEY = "directed";
|
|
58
175
|
/** The properties the reader reads, per target: what a file graphty wrote can bring back from its block. */
|
|
@@ -60,6 +177,8 @@ const READ = {
|
|
|
60
177
|
node: [
|
|
61
178
|
"label",
|
|
62
179
|
"shape",
|
|
180
|
+
"shapePoints",
|
|
181
|
+
"shapePointsStretch",
|
|
63
182
|
"fill",
|
|
64
183
|
"fillOpacity",
|
|
65
184
|
"borderColor",
|
|
@@ -68,8 +187,25 @@ const READ = {
|
|
|
68
187
|
"height",
|
|
69
188
|
"labelColor",
|
|
70
189
|
"labelSize",
|
|
190
|
+
"labelFont",
|
|
191
|
+
"labelPosition",
|
|
192
|
+
"labelOffsetX",
|
|
193
|
+
"labelOffsetY",
|
|
194
|
+
"labelShiftX",
|
|
195
|
+
"labelRotation",
|
|
196
|
+
],
|
|
197
|
+
edge: [
|
|
198
|
+
"color",
|
|
199
|
+
"opacity",
|
|
200
|
+
"width",
|
|
201
|
+
"lineStyle",
|
|
202
|
+
"arrowSize",
|
|
203
|
+
"arrowPosition",
|
|
204
|
+
"label",
|
|
205
|
+
"labelColor",
|
|
206
|
+
"labelSize",
|
|
207
|
+
"labelFont",
|
|
71
208
|
],
|
|
72
|
-
edge: ["color", "opacity", "width", "lineStyle"],
|
|
73
209
|
};
|
|
74
210
|
/**
|
|
75
211
|
* Reads a Pajek color and its alpha.
|
|
@@ -85,6 +221,13 @@ function readColor(raw, property, opacity, put, at) {
|
|
|
85
221
|
}
|
|
86
222
|
const c = canonColor(raw, "dvips", at(property));
|
|
87
223
|
if (c === null) {
|
|
224
|
+
// a name Pajek does not know, or a known one in another case (`red`), fills a vertex white and draws a line
|
|
225
|
+
// black (`pajek-specimen-node-fills-borders-p3` `ic-unknown-name`, `ic-lowercase-name`); ponytail: measured
|
|
226
|
+
// on names in `ic` and `c` only, so a border or label color and an unreadable RGB / CMYK form keep the default
|
|
227
|
+
const unknown = UNKNOWN_COLORS.get(property);
|
|
228
|
+
if (unknown !== undefined && typeof raw === "string" && /^[A-Za-z]\w*$/.test(raw.trim())) {
|
|
229
|
+
put(property, unknown);
|
|
230
|
+
}
|
|
88
231
|
return;
|
|
89
232
|
}
|
|
90
233
|
put(property, c.color);
|
|
@@ -93,6 +236,11 @@ function readColor(raw, property, opacity, put, at) {
|
|
|
93
236
|
put(opacity, alpha);
|
|
94
237
|
}
|
|
95
238
|
}
|
|
239
|
+
/** What Pajek draws for a color it cannot read, by property. */
|
|
240
|
+
const UNKNOWN_COLORS = new Map([
|
|
241
|
+
["fill", "#ffffff"],
|
|
242
|
+
["color", "#000000"],
|
|
243
|
+
]);
|
|
96
244
|
/**
|
|
97
245
|
* Reads a length or factor.
|
|
98
246
|
* @param raw - the parameter's value, or null
|
|
@@ -110,41 +258,686 @@ function readNumber(raw, property, put, at) {
|
|
|
110
258
|
* @param get - the vertex's parameters
|
|
111
259
|
* @param put - receives the values
|
|
112
260
|
* @param at - the sites
|
|
261
|
+
* @param place - the vertex's place in the file's coordinates, or null when it has none
|
|
113
262
|
*/
|
|
114
|
-
function readVertex(get, put, at) {
|
|
263
|
+
function readVertex(get, put, at, place = null) {
|
|
115
264
|
// an empty label draws nothing
|
|
116
265
|
const label = get(LABEL_COLUMN);
|
|
117
266
|
if (label !== null && label !== "") {
|
|
118
267
|
put("label", canonText(label, at("label")));
|
|
119
268
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
269
|
+
const raw = get(SHAPE_COLUMN);
|
|
270
|
+
const shape = raw === null ? null : canonEnum("shape", raw, "dvips", at("shape"));
|
|
271
|
+
if (raw !== null) {
|
|
272
|
+
put("shape", shape);
|
|
123
273
|
}
|
|
124
274
|
readColor(get("ic"), "fill", "fillOpacity", put, at);
|
|
125
275
|
readColor(get("bc"), "borderColor", null, put, at);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
put("borderWidth", width === null ? null : width / VERTEX_SIZE);
|
|
130
|
-
}
|
|
131
|
-
readNumber(get("x_fact"), "width", put, at);
|
|
132
|
-
readNumber(get("y_fact"), "height", put, at);
|
|
276
|
+
readNumber(get("bw"), "borderWidth", put, at);
|
|
277
|
+
readSize(get, put, at, PAJEK_FIGURES.get(String(shape)));
|
|
278
|
+
readOutline(get, put, shape);
|
|
133
279
|
readColor(get("lc"), "labelColor", null, put, at);
|
|
134
280
|
readNumber(get("fos"), "labelSize", put, at);
|
|
281
|
+
readFont(get("font"), put, at);
|
|
282
|
+
readLabelPosition(get, put, at);
|
|
283
|
+
readLabelAngle(get("la"), put, at, place);
|
|
284
|
+
if (shape === "none") {
|
|
285
|
+
// an `empty` vertex's label is drawn white at size 1 on its center, whatever the line sets
|
|
286
|
+
// (`pajek-synth-vertices` `empty *`, `pajek-lin-rel4` v226 to v233)
|
|
287
|
+
for (const [property, value] of EMPTY_LABEL) {
|
|
288
|
+
put(property, value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The corners Pajek 6.02's SVG export draws a box, a triangle and a house with, as `shapePoints` (fractions of the half
|
|
294
|
+
* width and height, y up): `pajek-specimen-node-shapes`, `shape-box`, `shape-triangle`, `shape-house`.
|
|
295
|
+
*/
|
|
296
|
+
const PAJEK_OUTLINES = new Map([
|
|
297
|
+
[
|
|
298
|
+
"rectangle",
|
|
299
|
+
[
|
|
300
|
+
[-1, 1],
|
|
301
|
+
[1, 1],
|
|
302
|
+
[1, -1],
|
|
303
|
+
[-1, -1],
|
|
304
|
+
],
|
|
305
|
+
],
|
|
306
|
+
[
|
|
307
|
+
"triangle",
|
|
308
|
+
[
|
|
309
|
+
[1, -1],
|
|
310
|
+
[0, 1],
|
|
311
|
+
[-1, -1],
|
|
312
|
+
],
|
|
313
|
+
],
|
|
314
|
+
[
|
|
315
|
+
"other:house",
|
|
316
|
+
[
|
|
317
|
+
[-0.7, -1],
|
|
318
|
+
[0.7, -1],
|
|
319
|
+
[0.7, 0.3],
|
|
320
|
+
[1, 0.3],
|
|
321
|
+
[1, 0.4],
|
|
322
|
+
[0, 1],
|
|
323
|
+
[-1, 0.4],
|
|
324
|
+
[-1, 0.3],
|
|
325
|
+
[-0.7, 0.3],
|
|
326
|
+
],
|
|
327
|
+
],
|
|
328
|
+
]);
|
|
329
|
+
/** A diamond's `q` where the line sets none (Pajek's shipped SHAPES.CFG). */
|
|
330
|
+
const PAJEK_DIAMOND_Q = 0.001;
|
|
331
|
+
/**
|
|
332
|
+
* A vertex's outline where Pajek draws one no named shape is: a diamond is Pajek's six-cornered one, its top and bottom
|
|
333
|
+
* cut `q` of its half width wide (`pajek-specimen-node-shapes`: `q 0.001` by default, `q 0.5` a hexagon, `q 1` a
|
|
334
|
+
* square, `q 2` a bow tie twice as wide), and `phi` turns a box, a triangle, a house or a diamond `phi` degrees
|
|
335
|
+
* counterclockwise about its center (`phi-30-box`, `phi-90-triangle`: Pajek draws the shape at its size, then turns
|
|
336
|
+
* it). ponytail: the corners are fractions of the size the line gives (`x_fact`, `y_fact`); a turned shape whose width
|
|
337
|
+
* and height the Draw window's Size of Vertices or vectors scale apart is turned in the wrong box. A turned ellipse,
|
|
338
|
+
* man or woman is drawn unturned: an outline of corners would draw an ellipse as a polygon.
|
|
339
|
+
* @param get - the vertex's parameters
|
|
340
|
+
* @param put - receives the values
|
|
341
|
+
* @param shape - its shape
|
|
342
|
+
*/
|
|
343
|
+
function readOutline(get, put, shape) {
|
|
344
|
+
const phi = numberOrNull(get("phi")) ?? 0;
|
|
345
|
+
const q = numberOrNull(get("q")) ?? PAJEK_DIAMOND_Q;
|
|
346
|
+
const diamond = [
|
|
347
|
+
[-1, 0],
|
|
348
|
+
[-q, 1],
|
|
349
|
+
[q, 1],
|
|
350
|
+
[1, 0],
|
|
351
|
+
[q, -1],
|
|
352
|
+
[-q, -1],
|
|
353
|
+
];
|
|
354
|
+
const corners = shape === "diamond" ? diamond : PAJEK_OUTLINES.get(String(shape));
|
|
355
|
+
if (corners === undefined || (shape !== "diamond" && phi % 360 === 0)) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// turned in the drawn box, x_fact by y_fact, and back to fractions of it
|
|
359
|
+
const [w, h] = [numberOrNull(get("x_fact")) || 1, numberOrNull(get("y_fact")) || 1];
|
|
360
|
+
const [c, s] = [Math.cos((phi * Math.PI) / 180), Math.sin((phi * Math.PI) / 180)];
|
|
361
|
+
const round = (v) => String(Number(v.toFixed(4)) + 0);
|
|
362
|
+
const points = corners.map(([x, y]) => {
|
|
363
|
+
const [px, py] = [x * w, y * h];
|
|
364
|
+
return `${round((px * c - py * s) / w)},${round((px * s + py * c) / h)}`;
|
|
365
|
+
});
|
|
366
|
+
put("shape", "polygon");
|
|
367
|
+
put("shapePoints", points.join(" "));
|
|
368
|
+
put("shapePointsStretch", false);
|
|
369
|
+
}
|
|
370
|
+
/** How Pajek 6.02's SVG export draws an `empty` vertex's label. */
|
|
371
|
+
const EMPTY_LABEL = [
|
|
372
|
+
["labelSize", 1],
|
|
373
|
+
["labelColor", "#ffffff"],
|
|
374
|
+
["labelPosition", "center"],
|
|
375
|
+
["labelOffsetX", 0],
|
|
376
|
+
["labelOffsetY", 0],
|
|
377
|
+
["labelShiftX", 0],
|
|
378
|
+
];
|
|
379
|
+
/**
|
|
380
|
+
* A label's `font`: Pajek writes it into its SVG export as the family, as given, so a PostScript name (`Courier-Bold`,
|
|
381
|
+
* `Helvetica-Oblique`) is drawn in its family, with a generic one after it, and upright, as the pinned fonts draw it
|
|
382
|
+
* (`pajek-specimen-labels` `font-courier-bold` monospace, `font-helvetica-oblique` sans-serif and upright); any other
|
|
383
|
+
* name is the family as written. Pajek draws every label bold whatever the name says.
|
|
384
|
+
* @param raw - the parameter's value, or null
|
|
385
|
+
* @param put - receives the values
|
|
386
|
+
* @param at - the sites
|
|
387
|
+
*/
|
|
388
|
+
function readFont(raw, put, at) {
|
|
389
|
+
if (raw === null || raw === "") {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const ps = typeof raw === "string" ? postscriptFont(raw.trim()) : null;
|
|
393
|
+
if (ps === null) {
|
|
394
|
+
readText(raw, "labelFont", put, at);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
put("labelFont", ps.family);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* A vertex label's angle `la` (manual p. 90), degrees counterclockwise, as a clockwise rotation: Pajek 6.02's SVG export
|
|
401
|
+
* turns the label by `rotate(-la)` (`pajek-specimen-labels`, `la-30` .. `la-270`). An angle of 360 or more turns the
|
|
402
|
+
* label away from the middle of the file's square, (0.5, 0.5) in its own coordinates, and then `la - 360` further
|
|
403
|
+
* (`la-360` at (0.4533, 0.3706) is drawn at -109.83, the direction from the middle; `la-400` at (0.5467, 0.3706) at
|
|
404
|
+
* -110.17, that direction, 70.17, and 40 more); without the vertex's place it is left unread.
|
|
405
|
+
* @param raw - the parameter's value, or null
|
|
406
|
+
* @param put - receives the value
|
|
407
|
+
* @param at - the sites
|
|
408
|
+
* @param place - the vertex's place in the file's coordinates, or null
|
|
409
|
+
*/
|
|
410
|
+
function readLabelAngle(raw, put, at, place) {
|
|
411
|
+
let a = raw === null ? null : canonNumber(raw, at("labelRotation"));
|
|
412
|
+
if (a !== null && a >= 360) {
|
|
413
|
+
a = place === null ? null : (Math.atan2(0.5 - place[1], place[0] - 0.5) * 180) / Math.PI + a - 360;
|
|
414
|
+
}
|
|
415
|
+
if (a !== null) {
|
|
416
|
+
put("labelRotation", Number(((((360 - a) % 360) + 360) % 360).toPrecision(12)));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* A vertex's width and height in points: the normal size times its `x_fact` and `y_fact`, each 1 when unset; a vertex
|
|
421
|
+
* that sets neither is left to the default beneath. The manual (p. 89) calls `s_size` "default size", but Pajek 6.02
|
|
422
|
+
* draws a vertex the same size whatever its `s_size` (`pajek-specimen-node-sizes-opacity`: `s_size` 0.5, 2 and 3 all
|
|
423
|
+
* drawn 36 across at `x_fact 1.8`), so it is not read. A man or a woman is the box of the figure Pajek draws for
|
|
424
|
+
* that size (`PAJEK_FIGURES`), set or not.
|
|
425
|
+
* @param get - the vertex's parameters
|
|
426
|
+
* @param put - receives the values
|
|
427
|
+
* @param at - the sites
|
|
428
|
+
* @param figure - a figure's width and height over its size, or undefined for another shape
|
|
429
|
+
*/
|
|
430
|
+
function readSize(get, put, at, figure) {
|
|
431
|
+
for (const [key, property, k] of [
|
|
432
|
+
["x_fact", "width", 0],
|
|
433
|
+
["y_fact", "height", 1],
|
|
434
|
+
]) {
|
|
435
|
+
const f = get(key);
|
|
436
|
+
if (f === null && figure === undefined) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
const factor = f === null ? 1 : canonNumber(f, at(property));
|
|
440
|
+
const over = figure?.[k] ?? 1;
|
|
441
|
+
put(property, factor === null ? null : Number((PAJEK_VERTEX_SIZE * factor * over).toPrecision(15)));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* A text parameter (a PostScript font name).
|
|
446
|
+
* @param raw - the parameter's value, or null
|
|
447
|
+
* @param property - the property
|
|
448
|
+
* @param put - receives the value
|
|
449
|
+
* @param at - the sites
|
|
450
|
+
*/
|
|
451
|
+
function readText(raw, property, put, at) {
|
|
452
|
+
if (raw !== null && raw !== "") {
|
|
453
|
+
put(property, canonText(raw, at(property)));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/** The `lphi` written for each side graphty puts a label on, and the side written for each Pajek has no angle for. */
|
|
457
|
+
const SIDE_ANGLES = new Map([
|
|
458
|
+
["right", 0],
|
|
459
|
+
["top-right", 90],
|
|
460
|
+
["left", 180],
|
|
461
|
+
["bottom-right", 285],
|
|
462
|
+
]);
|
|
463
|
+
const NEAREST_SIDES = new Map([
|
|
464
|
+
["top", "top-right"],
|
|
465
|
+
["top-left", "top-right"],
|
|
466
|
+
["bottom", "bottom-right"],
|
|
467
|
+
["bottom-left", "bottom-right"],
|
|
468
|
+
]);
|
|
469
|
+
/**
|
|
470
|
+
* A vertex's label place from Pajek's polar label parameters (manual p. 90): `lr` is the distance of the label from
|
|
471
|
+
* the vertex center, 0 centering it, and `lphi` its angle in degrees counterclockwise. Pajek 6.02's SVG export starts
|
|
472
|
+
* the text at that point, its baseline through it (`text-anchor` start at y = the point), so the label's left edge is
|
|
473
|
+
* at the point's x (`labelShiftX` 0.5) and its middle `PAJEK_BASELINE_TO_MIDDLE` of its size above the point's y
|
|
474
|
+
* (`pajek-specimen-labels` `lr-*`, `lphi-*`; every corpus label). A vertex that sets none of `lr`, `lphi` and `fos`
|
|
475
|
+
* is left to the default beneath, the same place at the default size.
|
|
476
|
+
* @param get - the vertex's parameters
|
|
477
|
+
* @param put - receives the values
|
|
478
|
+
* @param at - the sites
|
|
479
|
+
*/
|
|
480
|
+
function readLabelPosition(get, put, at) {
|
|
481
|
+
const [lr, lphi, fos] = [get("lr"), get("lphi"), get("fos")];
|
|
482
|
+
if (lr === null && lphi === null && fos === null) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const radius = lr === null ? PAJEK_LABEL_RADIUS : canonNumber(lr, at("labelPosition"));
|
|
486
|
+
const angle = lphi === null ? PAJEK_LABEL_ANGLE : canonNumber(lphi, at("labelPosition"));
|
|
487
|
+
const size = fos === null ? PAJEK_LABEL_SIZE : canonNumber(fos, at("labelSize"));
|
|
488
|
+
if (radius === null || angle === null || size === null) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const [x, y] = labelOffset(radius, angle, size);
|
|
492
|
+
put("labelPosition", "center");
|
|
493
|
+
put("labelOffsetX", x);
|
|
494
|
+
put("labelOffsetY", y);
|
|
495
|
+
put("labelShiftX", radius === 0 ? 0 : 0.5);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Where Pajek's polar label parameters put a label, from the vertex center, y down: the middle of its left edge, or
|
|
499
|
+
* its middle when `lr` is 0, which centers it.
|
|
500
|
+
* @param radius - `lr`
|
|
501
|
+
* @param angle - `lphi`, degrees counterclockwise
|
|
502
|
+
* @param size - the label's size
|
|
503
|
+
* @returns the offset across and down
|
|
504
|
+
*/
|
|
505
|
+
function labelOffset(radius, angle, size) {
|
|
506
|
+
if (radius === 0) {
|
|
507
|
+
return [0, 0];
|
|
508
|
+
}
|
|
509
|
+
const t = (angle * Math.PI) / 180;
|
|
510
|
+
const round = (v) => Number(v.toFixed(9)) + 0;
|
|
511
|
+
return [round(radius * Math.cos(t)), round(-radius * Math.sin(t) - PAJEK_BASELINE_TO_MIDDLE * size)];
|
|
135
512
|
}
|
|
136
513
|
/**
|
|
137
|
-
*
|
|
514
|
+
* The label radius and angle Pajek uses when a vertex sets none: 20 and 285, below and to the right of the vertex.
|
|
515
|
+
* Measured in Pajek 6.02's own SVG export (`test/fidelity/oracles/pajek-football.svg`, `pajek-specimen-labels`
|
|
516
|
+
* `default`: every such label starts 20 from its vertex at 285 degrees); the size is the default label size.
|
|
517
|
+
*/
|
|
518
|
+
const PAJEK_LABEL_RADIUS = 20;
|
|
519
|
+
const PAJEK_LABEL_ANGLE = 285;
|
|
520
|
+
const PAJEK_LABEL_SIZE = 15;
|
|
521
|
+
/**
|
|
522
|
+
* How far above its baseline a label's middle is, per unit of its size: half the ascent less the descent of Arial
|
|
523
|
+
* (Liberation Sans: 0.905 and 0.212), the face Pajek draws its labels in by default.
|
|
524
|
+
*/
|
|
525
|
+
const PAJEK_BASELINE_TO_MIDDLE = 0.3465;
|
|
526
|
+
/**
|
|
527
|
+
* One line's style: its color, width and pattern. Pajek draws an edge (undirected) twice as wide as an arc of the
|
|
528
|
+
* same `w`.
|
|
138
529
|
* @param get - the line's parameters
|
|
139
530
|
* @param put - receives the values
|
|
140
531
|
* @param at - the sites
|
|
532
|
+
* @param directed - whether the line is an arc
|
|
533
|
+
* @param labels - whether its label is drawn (`drawsLineLabels`)
|
|
534
|
+
* @param run - the line from its source's center to its target's, in drawn units, y down, or null when unplaced
|
|
535
|
+
* @param loop - for a loop on a placed node, receives its control points; null for any other line
|
|
141
536
|
*/
|
|
142
|
-
function readLine(get, put, at) {
|
|
537
|
+
function readLine(get, put, at, directed, labels = true, run = null, loop = null) {
|
|
143
538
|
readColor(get("c"), "color", "opacity", put, at);
|
|
144
|
-
readNumber(get("w"), "width",
|
|
539
|
+
readNumber(get("w"), "width", (property, value) => {
|
|
540
|
+
put(property, typeof value === "number" && !directed ? value * EDGE_WIDTH_PER_W : value);
|
|
541
|
+
}, at);
|
|
145
542
|
const p = get("p");
|
|
146
|
-
if (p
|
|
147
|
-
put("lineStyle",
|
|
543
|
+
if (p === "Dots") {
|
|
544
|
+
put("lineStyle", pajekDash(get, directed));
|
|
545
|
+
}
|
|
546
|
+
else if (p === "Solid") {
|
|
547
|
+
put("lineStyle", "solid");
|
|
548
|
+
}
|
|
549
|
+
else if (p !== null) {
|
|
550
|
+
// Pajek knows Solid and Dots, case for case; any other pattern (`Dashed`, `dots`) draws a solid line
|
|
551
|
+
noteAt(at("lineStyle"), STYLE_ISSUE.UNKNOWN_VALUE, typeof p === "string" ? p : JSON.stringify(p));
|
|
552
|
+
put("lineStyle", "solid");
|
|
553
|
+
}
|
|
554
|
+
// an arrowhead is 6 x `s` long and 5 x `s` wide; `s` 1, Pajek's normal size, is 6 long (the pajek tool arrowhead)
|
|
555
|
+
readNumber(get("s"), "arrowSize", put, at);
|
|
556
|
+
readArrowPosition(get("ap"), put, at);
|
|
557
|
+
// a loop is drawn as the Bezier route of a line PAJEK_POINTS_PER_UNIT long to the right, its two ends on the node
|
|
558
|
+
const line = loop === null ? get : loopParam(get);
|
|
559
|
+
const controls = loop === null ? null : readLoop(line, put, loop);
|
|
560
|
+
if (labels) {
|
|
561
|
+
readText(get("l"), "label", put, at);
|
|
562
|
+
if (controls === null) {
|
|
563
|
+
readLineLabelPlace(get, put, at, run);
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
readLineLabelPlace(line, put, at, [PAJEK_POINTS_PER_UNIT, 0], loopTop(controls));
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (loop === null) {
|
|
570
|
+
readBezier(get, put, run);
|
|
571
|
+
}
|
|
572
|
+
readColor(get("lc"), "labelColor", null, put, at);
|
|
573
|
+
readNumber(get("fos"), "labelSize", put, at);
|
|
574
|
+
readFont(get("font"), put, at);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* The route parameters Pajek 6.02's SVG export draws a loop with where the line sets none (`pajek-specimen-edges-lines-p2`
|
|
578
|
+
* `loop` and `loop-arc`, `pajek-specimen-edge-labels` `on-loop`: a cubic from the node's center up and back, its control
|
|
579
|
+
* points 74.9 out at 70 and 110 degrees up from the right).
|
|
580
|
+
*/
|
|
581
|
+
const LOOP_DEFAULTS = { a1: -70, k1: 0.3, a2: -70, k2: 0.3 };
|
|
582
|
+
/**
|
|
583
|
+
* A loop's route parameters: the line's own, Pajek's loop defaults for any it leaves out.
|
|
584
|
+
* @param get - the line's parameters
|
|
585
|
+
* @returns the parameters with the defaults
|
|
586
|
+
*/
|
|
587
|
+
function loopParam(get) {
|
|
588
|
+
return (key) => get(key) ?? (key in LOOP_DEFAULTS ? LOOP_DEFAULTS[key] : null);
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* A loop's route (manual p. 90: "if arc is a loop (arc to itself) bezier loop will be drawn"), as Pajek 6.02's SVG
|
|
592
|
+
* export draws it: the Bezier route of a line PAJEK_POINTS_PER_UNIT long running right, both its ends on the node
|
|
593
|
+
* (`a1 -130 k1 0.6 a2 -130 k2 0.6`: control points 150 out at 130 and 50 degrees up from the right, measured on
|
|
594
|
+
* `pajek-specimen-edges-lines-p2` `loop-bezier`). Its bends are written once the nodes' sizes are known
|
|
595
|
+
* (`layLoops`). ponytail: measured in one Draw window (1200 x 900) and one vertex size; whether Pajek scales a loop
|
|
596
|
+
* with either was not measured.
|
|
597
|
+
* @param get - the line's parameters, with the loop defaults
|
|
598
|
+
* @param put - receives the values
|
|
599
|
+
* @param loop - receives the control points
|
|
600
|
+
* @returns the control points, or null when the line's parameters give none
|
|
601
|
+
*/
|
|
602
|
+
function readLoop(get, put, loop) {
|
|
603
|
+
const run = [PAJEK_POINTS_PER_UNIT, 0];
|
|
604
|
+
const controls = bezierControls(get, run);
|
|
605
|
+
if (controls === null) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
const [[a1, l1], [a2, l2]] = controls;
|
|
609
|
+
const L = PAJEK_POINTS_PER_UNIT;
|
|
610
|
+
// along the line is right, left of it up: the second point is measured back from the line's far end, the node
|
|
611
|
+
const [c1, c2] = [
|
|
612
|
+
[a1 * L, -l1 * L],
|
|
613
|
+
[(a2 - 1) * L, -l2 * L],
|
|
614
|
+
];
|
|
615
|
+
loop([c1, c2]);
|
|
616
|
+
put("curved", true);
|
|
617
|
+
put("bendCurve", "bezier");
|
|
618
|
+
// an arc's head is drawn where the loop comes back to its node's center, under the node
|
|
619
|
+
// (`pajek-specimen-edges-lines-p2` `loop-arc`, `s 1 a A`: no head shows)
|
|
620
|
+
put("targetArrow", "none");
|
|
621
|
+
return [c1, c2];
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* The way a loop runs at its top, where its label is drawn (`lp` 0.5): from its first control point to its second
|
|
625
|
+
* (`pajek-specimen-edge-labels` `on-loop`: 179.97). ponytail: a label elsewhere on the loop (`lp`) is turned as at
|
|
626
|
+
* its top.
|
|
627
|
+
* @param controls - the loop's control points
|
|
628
|
+
* @returns the direction, in degrees clockwise on screen
|
|
629
|
+
*/
|
|
630
|
+
function loopTop(controls) {
|
|
631
|
+
const [c1, c2] = controls;
|
|
632
|
+
return (Math.atan2(c2[1] - c1[1], c2[0] - c1[0]) * 180) / Math.PI;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Writes each loop's control points as its bends, fractions of its node's half width and half height, y up, once the
|
|
636
|
+
* nodes are sized, and draws it round whatever the Draw window does to the other lines.
|
|
637
|
+
* @param snapshot - the graph
|
|
638
|
+
* @param loops - each loop's control points by edge
|
|
639
|
+
* @param node - the node values, sized
|
|
640
|
+
* @param edge - the edge values; changed in place
|
|
641
|
+
*/
|
|
642
|
+
function layLoops(snapshot, loops, node, edge) {
|
|
643
|
+
const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
|
|
644
|
+
for (const [e, controls] of loops) {
|
|
645
|
+
const v = snapshot.edgeSource(e);
|
|
646
|
+
const half = (property) => {
|
|
647
|
+
const size = node[property]?.[v];
|
|
648
|
+
return (typeof size === "number" && size > 0 ? size : PAJEK_VERTEX_SIZE) / 2;
|
|
649
|
+
};
|
|
650
|
+
const [hw, hh] = [half("width"), half("height")];
|
|
651
|
+
const column = (property) => (edge[property] ?? (edge[property] = new Array(snapshot.edgeCount).fill(null)));
|
|
652
|
+
column("bends")[e] = controls.map(([x, y]) => `${fraction(x / hw)},${fraction(-y / hh)}`).join(" ");
|
|
653
|
+
// Export Line Default / Straight Lines straightens every other line; a loop is still drawn round
|
|
654
|
+
// (`pajek-specimen-edges-lines-p4`)
|
|
655
|
+
column("curved")[e] = true;
|
|
656
|
+
column("bendCurve")[e] = "bezier";
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Where Pajek 6.02's SVG export draws a line's label (`pajek-specimen-edge-labels`): its middle at `lp` from the
|
|
661
|
+
* terminal vertex, a fraction of the line up to 1 (0.5 by default, 0.2 near the target) and a distance beyond it
|
|
662
|
+
* (`lp 20` 20 from the target), moved by `lr` at `lphi` degrees counterclockwise (`lr 12 lphi 90` 12 above), its
|
|
663
|
+
* baseline through that point, and turned along the line and `la` degrees counterclockwise from it (`la 45` drawn
|
|
664
|
+
* rotate(-45) on a level line; `la 405` as `la 45`). graphty hangs a line's label on the line's middle, so the place is
|
|
665
|
+
* an offset from there, the words' middle above the baseline in the label's own turned frame.
|
|
666
|
+
* @param get - the line's parameters
|
|
667
|
+
* @param put - receives the values
|
|
668
|
+
* @param at - the sites
|
|
669
|
+
* @param run - the line, or null when unplaced
|
|
670
|
+
* @param direction - the line's direction at the label, in degrees clockwise on screen, where `run` does not give it
|
|
671
|
+
* (a loop)
|
|
672
|
+
*/
|
|
673
|
+
function readLineLabelPlace(get, put, at, run, direction) {
|
|
674
|
+
const length = run === null ? 0 : Math.hypot(run[0], run[1]);
|
|
675
|
+
if (run === null || length === 0) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
const n = (key, fallback, property) => {
|
|
679
|
+
const v = get(key);
|
|
680
|
+
return v === null ? fallback : canonNumber(v, at(property));
|
|
681
|
+
};
|
|
682
|
+
const [lp, lr, lphi, la] = [
|
|
683
|
+
n("lp", 0.5, "labelOffsetX"),
|
|
684
|
+
n("lr", 0, "labelOffsetX"),
|
|
685
|
+
n("lphi", 0, "labelOffsetX"),
|
|
686
|
+
n("la", 0, "labelRotation"),
|
|
687
|
+
];
|
|
688
|
+
const size = n("fos", PAJEK_LABEL_SIZE, "labelSize");
|
|
689
|
+
if (lp === null || lr === null || lphi === null || la === null || size === null) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
// from the line's middle to the point lp from its target, then out by lr at lphi
|
|
693
|
+
const along = 0.5 - (lp <= 1 ? lp : lp / length);
|
|
694
|
+
const t = (lphi * Math.PI) / 180;
|
|
695
|
+
const round = (v) => Number(v.toFixed(9)) + 0;
|
|
696
|
+
const turn = (((direction ?? lineDirection(get, run, along + 0.5)) - la) % 360) + 360;
|
|
697
|
+
// the baseline runs through the point; the words' middle is above it in the label's own turned frame
|
|
698
|
+
const up = (turn * Math.PI) / 180;
|
|
699
|
+
const rise = PAJEK_BASELINE_TO_MIDDLE * size;
|
|
700
|
+
put("labelPosition", "center");
|
|
701
|
+
put("labelOffsetX", round(along * run[0] + lr * Math.cos(t) + rise * Math.sin(up)));
|
|
702
|
+
put("labelOffsetY", round(along * run[1] - lr * Math.sin(t) - rise * Math.cos(up)));
|
|
703
|
+
put("labelRotation", round(turn % 360));
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* A line's Bezier route (manual p. 90: `a1`, `k1` at its source, `a2`, `k2` at its target), as Pajek 6.02's SVG export
|
|
707
|
+
* draws it (`pajek-specimen-edges-lines-p2`, `pajek-specimen-edge-labels`): one cubic Bezier curve whose first control
|
|
708
|
+
* point is `k1` / 2 of the line's length from the source, turned `a1` degrees clockwise on screen from the line, and
|
|
709
|
+
* whose second is `k2` / 2 of it back from the target, turned `a2` degrees counterclockwise (`a1 40 k1 1.5 a2 -40 k2
|
|
710
|
+
* 1.5` an S, `a2 40` a bow). A negative `k1` is one of Pajek's oval, circular arc or double routes, which its SVG export
|
|
711
|
+
* draws straight. A loop is `readLoop`'s. ponytail: a line that sets only some of the four reads the
|
|
712
|
+
* others as 0 and 1; Pajek's values for them were not measured.
|
|
713
|
+
* @param get - the line's parameters
|
|
714
|
+
* @param put - receives the values
|
|
715
|
+
* @param run - the line, or null when unplaced
|
|
716
|
+
*/
|
|
717
|
+
function readBezier(get, put, run) {
|
|
718
|
+
const controls = bezierControls(get, run);
|
|
719
|
+
if (controls === null) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
|
|
723
|
+
put("curved", true);
|
|
724
|
+
put("bendCurve", "bezier");
|
|
725
|
+
put("bends", controls.map(([along, across]) => `${fraction(along)},${fraction(across)}`).join(" "));
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Where Pajek 6.02's SVG export ends an arc's Bezier route (`readBezier`): at its arrowhead's back, not at its target's
|
|
729
|
+
* center. It places the arrowhead as on a straight arc, its tip 1.5 short of where the straight line meets the
|
|
730
|
+
* target's outline, turns it `-a2` degrees about that point, and runs the curve from the source's center to the
|
|
731
|
+
* arrowhead's back, its control points measured on that shorter line (`pajek-specimen-edges-lines-p2`
|
|
732
|
+
* `route-bezier-opposite-arc`: the arrowhead's back at (347.02, 124.32), 6.5 back from the outline at (352, 128.5),
|
|
733
|
+
* turned 40 degrees; `route-bezier-same-arc` at (571.02, 132.68), turned -40). graphty draws the route to the target's
|
|
734
|
+
* center and stops it at the outline, so the curve's control points are written in the frame of that line.
|
|
735
|
+
* ponytail: the outline is the ellipse of the vertex's width and height, as the file sizes it (before the Draw
|
|
736
|
+
* window's Size of Vertices or vectors), whatever its shape.
|
|
737
|
+
* @param get - the line's parameters
|
|
738
|
+
* @param put - receives the values
|
|
739
|
+
* @param run - the line from its source's center to its target's, in drawn units, y down
|
|
740
|
+
* @param target - the target vertex's width and height
|
|
741
|
+
*/
|
|
742
|
+
function readArcEnd(get, put, run, target) {
|
|
743
|
+
const ap = numberOrNull(get("ap")) ?? 0;
|
|
744
|
+
const length = Math.hypot(run[0], run[1]);
|
|
745
|
+
if (ap !== 0 || length === 0 || bezierControls(get, run) === null) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const [ux, uy] = [run[0] / length, run[1] / length];
|
|
749
|
+
// the straight line meets the outline r from the target's center; the arrowhead's back is 1.5 + 5 s before it
|
|
750
|
+
const r = 1 / Math.hypot(ux / (target[0] / 2), uy / (target[1] / 2));
|
|
751
|
+
const back = 1.5 + 5 * (numberOrNull(get("s")) ?? 1);
|
|
752
|
+
const turn = (-(numberOrNull(get("a2")) ?? 0) * Math.PI) / 180;
|
|
753
|
+
const [c, s] = [Math.cos(turn), Math.sin(turn)];
|
|
754
|
+
// the arrowhead's back, from the source's center
|
|
755
|
+
const end = [run[0] - r * ux - back * (ux * c - uy * s), run[1] - r * uy - back * (ux * s + uy * c)];
|
|
756
|
+
const controls = bezierControls(get, end);
|
|
757
|
+
if (controls === null) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// each control point on screen from the source's center, then along and to the left of the line to the target
|
|
761
|
+
const L2 = length * length;
|
|
762
|
+
const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
|
|
763
|
+
const bends = controls.map(([along, left]) => {
|
|
764
|
+
const [x, y] = [along * end[0] + left * end[1], along * end[1] - left * end[0]];
|
|
765
|
+
return `${fraction((x * run[0] + y * run[1]) / L2)},${fraction((x * run[1] - y * run[0]) / L2)}`;
|
|
766
|
+
});
|
|
767
|
+
put("bends", bends.join(" "));
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* A line's two Bezier control points (`readBezier`), each `[along, across]` as fractions of the line from its source:
|
|
771
|
+
* along it, and to its left on screen.
|
|
772
|
+
* @param get - the line's parameters
|
|
773
|
+
* @param run - the line, or null when unplaced
|
|
774
|
+
* @returns the points, or null for a line Pajek draws straight or a loop
|
|
775
|
+
*/
|
|
776
|
+
function bezierControls(get, run) {
|
|
777
|
+
const [a1, k1, a2, k2] = ["a1", "k1", "a2", "k2"].map((key) => numberOrNull(get(key)));
|
|
778
|
+
if ((a1 === null && k1 === null && a2 === null && k2 === null) || run === null || (run[0] === 0 && run[1] === 0)) {
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
const [s, t] = [k1 ?? 1, k2 ?? 1];
|
|
782
|
+
if (s < 0 || t < 0) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
const rad = Math.PI / 180;
|
|
786
|
+
const [u, v] = [(a1 ?? 0) * rad, (a2 ?? 0) * rad];
|
|
787
|
+
return [
|
|
788
|
+
[(s / 2) * Math.cos(u), (-s / 2) * Math.sin(u)],
|
|
789
|
+
[1 - (t / 2) * Math.cos(v), (-t / 2) * Math.sin(v)],
|
|
790
|
+
];
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* A line's direction on screen, in degrees clockwise, where its label is drawn: along a straight line, or along its
|
|
794
|
+
* Bezier curve (`bezierControls`) at the label's place, `along` of the way from the source.
|
|
795
|
+
* @param get - the line's parameters
|
|
796
|
+
* @param run - the line
|
|
797
|
+
* @param along - the label's place, 0 at the source and 1 at the target
|
|
798
|
+
* @returns the direction
|
|
799
|
+
*/
|
|
800
|
+
function lineDirection(get, run, along) {
|
|
801
|
+
const controls = bezierControls(get, run);
|
|
802
|
+
let [dx, dy] = run;
|
|
803
|
+
if (controls !== null) {
|
|
804
|
+
// the cubic's tangent at `along`, in the line's own frame (along, left), then on screen
|
|
805
|
+
const t = Math.min(1, Math.max(0, along));
|
|
806
|
+
const p = [[0, 0], ...controls, [1, 0]];
|
|
807
|
+
const d = (k) => 3 * (1 - t) ** 2 * (p[1][k] - p[0][k]) +
|
|
808
|
+
6 * (1 - t) * t * (p[2][k] - p[1][k]) +
|
|
809
|
+
3 * t ** 2 * (p[3][k] - p[2][k]);
|
|
810
|
+
const [a, l] = [d(0), d(1)];
|
|
811
|
+
// left of (dx, dy) on screen, y down, is (dy, -dx)
|
|
812
|
+
[dx, dy] = [a * run[0] + l * run[1], a * run[1] - l * run[0]];
|
|
813
|
+
}
|
|
814
|
+
return (Math.atan2(dy, dx) * 180) / Math.PI;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* What a line's value draws (manual 5.3 p. 90): a line of value 0 is not drawn, and a negative one is drawn as Dots
|
|
818
|
+
* unless the line sets a pattern.
|
|
819
|
+
* @param value - the line's value, or null
|
|
820
|
+
* @param get - the line's parameters
|
|
821
|
+
* @param put - receives the values
|
|
822
|
+
* @param directed - whether the line is an arc
|
|
823
|
+
*/
|
|
824
|
+
function readLineValue(value, get, put, directed = true) {
|
|
825
|
+
if (value === 0) {
|
|
826
|
+
put("visible", false);
|
|
827
|
+
}
|
|
828
|
+
else if (value !== null && value < 0 && get("p") === null) {
|
|
829
|
+
// drawn as Dots are (`pajek-specimen-edges-lines` `value-negative`)
|
|
830
|
+
put("lineStyle", pajekDash(get, directed));
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
/** The dash and the gap of Pajek 6.02's Dots, in px whatever the line's width (`stroke-dasharray:5`). */
|
|
834
|
+
const PAJEK_DASH = 5;
|
|
835
|
+
/**
|
|
836
|
+
* How a line drawn as Pajek's Dots looks: Pajek 6.02's SVG export draws it `stroke-dasharray:5`, dashes and gaps 5 px
|
|
837
|
+
* long whatever the line's width, so a line 10/3 px wide or wider, its dashes no longer than one and a half widths,
|
|
838
|
+
* shows dots and a thinner one dashes (`pajek-specimen-edges-lines` `p-dots` at 1.5: dashes; `pajek-synth-lines`
|
|
839
|
+
* arc `12 13` at w 5 and edge `1 8` at w 3, drawn 6 wide: dots).
|
|
840
|
+
* @param get - the line's parameters
|
|
841
|
+
* @param directed - whether the line is an arc, drawn `w` wide (an edge twice `w`)
|
|
842
|
+
* @returns the line style
|
|
843
|
+
*/
|
|
844
|
+
function pajekDash(get, directed) {
|
|
845
|
+
const w = numberOrNull(get("w"));
|
|
846
|
+
// without a `w`, Pajek's arc is 1 wide and its edge 2
|
|
847
|
+
const width = (w ?? 1) * (directed ? 1 : EDGE_WIDTH_PER_W);
|
|
848
|
+
return PAJEK_DASH <= 1.5 * Math.max(1, width) ? "dotted" : "dashed";
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* A line's hooks `h1` and `h2` (manual p. 90): the points of its source's and its target's outline it runs between,
|
|
852
|
+
* numbered by Pajek's shipped SHAPES.CFG for the vertex's shape. An ellipse's hook k is at k degrees counterclockwise
|
|
853
|
+
* from the right (CIRC `10 1`), a box's runs round its border in 400 steps from the middle of its right side,
|
|
854
|
+
* counterclockwise (CART), and a cross, which Pajek draws as an ellipse, has an ellipse's; `pajek-specimen-edges-lines-p2`:
|
|
855
|
+
* `h1 90 h2 270` runs from the top of the source to the bottom of the target, `h1 1 h2 1` ends on the far side of the
|
|
856
|
+
* target, `h1 1` on a box leaves at its right side. 0 (the center) and -1 (the nearest hook) are where graphty runs a
|
|
857
|
+
* line anyway. ponytail: the hooks of the other shapes (a diamond's 360 polar radii, a triangle's, a figure's) are
|
|
858
|
+
* not read; Pajek's box hook 100 was measured 0.22 of the half width left of the top's middle, where SHAPES.CFG puts
|
|
859
|
+
* it.
|
|
860
|
+
* @param get - the line's parameters
|
|
861
|
+
* @param put - receives the values
|
|
862
|
+
* @param source - the source vertex's shape keyword, or null
|
|
863
|
+
* @param target - the target vertex's shape keyword, or null
|
|
864
|
+
*/
|
|
865
|
+
function readHooks(get, put, source, target) {
|
|
866
|
+
for (const [key, property, shape] of [
|
|
867
|
+
["h1", "sourcePort", source],
|
|
868
|
+
["h2", "targetPort", target],
|
|
869
|
+
]) {
|
|
870
|
+
const hook = numberOrNull(get(key));
|
|
871
|
+
const port = hook === null ? null : hookPort(shape, hook);
|
|
872
|
+
if (port !== null) {
|
|
873
|
+
const round = (v) => String(Number(v.toFixed(4)) + 0);
|
|
874
|
+
put(property, `${round(port[0])},${round(port[1])}`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* One hook's point on its vertex (`readHooks`), as fractions of the half width and height, y up.
|
|
880
|
+
* @param shape - the vertex's shape keyword, null for Pajek's default ellipse
|
|
881
|
+
* @param hook - the hook's number
|
|
882
|
+
* @returns the point, or null where Pajek's hook is not read
|
|
883
|
+
*/
|
|
884
|
+
function hookPort(shape, hook) {
|
|
885
|
+
if (!Number.isInteger(hook) || hook < 1) {
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
const keyword = typeof shape === "string" ? shape.toLowerCase() : "ellipse";
|
|
889
|
+
// Pajek 6.02 draws a cross as an ellipse, with an ellipse's hooks (`h-cross-1-3`: hook 3 at 3 degrees)
|
|
890
|
+
if (keyword === "ellipse" || keyword === "cross") {
|
|
891
|
+
const a = (hook * Math.PI) / 180;
|
|
892
|
+
return [Math.cos(a), Math.sin(a)];
|
|
893
|
+
}
|
|
894
|
+
if (keyword !== "box" || hook > 400) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
// 0.02 of the half size a step: up the right side's top half, across the top, down the left, across the
|
|
898
|
+
// bottom and up the right side's bottom half
|
|
899
|
+
const d = hook * 0.02;
|
|
900
|
+
if (hook <= 50) {
|
|
901
|
+
return [1, d];
|
|
902
|
+
}
|
|
903
|
+
if (hook <= 150) {
|
|
904
|
+
return [2 - d, 1];
|
|
905
|
+
}
|
|
906
|
+
if (hook <= 250) {
|
|
907
|
+
return [-1, 4 - d];
|
|
908
|
+
}
|
|
909
|
+
return hook <= 350 ? [d - 6, -1] : [1, d - 8];
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* A cell's number: a number as is, a numeric text parsed, anything else null.
|
|
913
|
+
* @param raw - the cell
|
|
914
|
+
* @returns the number, or null
|
|
915
|
+
*/
|
|
916
|
+
function numberOrNull(raw) {
|
|
917
|
+
if (typeof raw === "string" && raw.trim() !== "") {
|
|
918
|
+
raw = Number(raw);
|
|
919
|
+
}
|
|
920
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : null;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Where a line's arrowhead sits, Pajek's `ap` (manual p. 90): a fraction of the line from its end up to 1 (0.5 is the
|
|
924
|
+
* middle); a value above 1 is a distance from the end, which the vocabulary does not hold, so it is noted and not read.
|
|
925
|
+
* @param raw - the parameter's value, or null
|
|
926
|
+
* @param put - receives the value
|
|
927
|
+
* @param at - the sites
|
|
928
|
+
*/
|
|
929
|
+
function readArrowPosition(raw, put, at) {
|
|
930
|
+
if (raw === null) {
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
const ap = canonNumber(raw, at("arrowPosition"));
|
|
934
|
+
if (ap !== null && ap > 1) {
|
|
935
|
+
noteAt(at("arrowPosition"), STYLE_ISSUE.NOT_CARRIED, `ap ${String(ap)}`);
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
// 0 is Pajek's own place for the arrow, at the line's end, which a line restates after one that moved it
|
|
939
|
+
if (ap !== 0) {
|
|
940
|
+
put("arrowPosition", ap);
|
|
148
941
|
}
|
|
149
942
|
}
|
|
150
943
|
/**
|
|
@@ -154,8 +947,18 @@ function readLine(get, put, at) {
|
|
|
154
947
|
* @returns the getter
|
|
155
948
|
*/
|
|
156
949
|
function cells(table, i) {
|
|
157
|
-
return (key) =>
|
|
950
|
+
return (key) => {
|
|
951
|
+
const v = table.has(key) ? plainCell(table.value(key, i)) : null;
|
|
952
|
+
// a color written as numbers (`c 0.700 0.700 0.700`) is no color to Pajek 6.02: the line keeps the color it
|
|
953
|
+
// carries from the line before, or Pajek's default (`pajek-1crn`, `pajek-specimen-edges-lines`
|
|
954
|
+
// `c-three-fractions`). ponytail: measured on lines; vertex colors are read the same way
|
|
955
|
+
return COLOR_PARAMS.has(key) && typeof v === "string" && NUMERIC_COLOR.test(v) ? null : v;
|
|
956
|
+
};
|
|
158
957
|
}
|
|
958
|
+
/** The parameters that hold a color. */
|
|
959
|
+
const COLOR_PARAMS = new Set(["ic", "bc", "lc", "c"]);
|
|
960
|
+
/** A color written as numbers rather than a name or an RGB / CMYK form. */
|
|
961
|
+
const NUMERIC_COLOR = /^[\d.]+(?: [\d.]+)*$/;
|
|
159
962
|
/**
|
|
160
963
|
* Whether each edge is an arc (directed).
|
|
161
964
|
* @param snapshot - the graph
|
|
@@ -181,37 +984,89 @@ function styleColumns(table, keys) {
|
|
|
181
984
|
return keys.filter((k) => table.has(k));
|
|
182
985
|
}
|
|
183
986
|
/**
|
|
184
|
-
* The styles of a Pajek file, read the way Pajek draws them, with Pajek's
|
|
185
|
-
* with a
|
|
987
|
+
* The styles of a Pajek file, read the way Pajek draws them, with Pajek's own defaults beneath: a labeled #ffd9bc
|
|
988
|
+
* ellipse with a #660000 border, teal edges, and grey arcs with an arrow at the target. A file graphty wrote gives back its `graphty.styles` block.
|
|
186
989
|
* @param snapshot - the graph the import built
|
|
187
990
|
* @param context - the work budget and the block text the import kept
|
|
188
991
|
* @returns the styles
|
|
189
992
|
*/
|
|
190
993
|
export function pajekStyles(snapshot, context) {
|
|
191
994
|
const notes = new StyleNotes();
|
|
995
|
+
const { block, draw, voided } = keptOf(context.kept);
|
|
996
|
+
const labels = drawsLineLabels(draw);
|
|
997
|
+
const place = places(snapshot);
|
|
998
|
+
// Pajek stretches the file's 0..1 to its Draw window one axis at a time, 500 x 500 without one
|
|
999
|
+
const window = draw ?? { width: PAJEK_POINTS_PER_UNIT, height: PAJEK_POINTS_PER_UNIT };
|
|
1000
|
+
const loops = new Map();
|
|
1001
|
+
const runOf = (e) => {
|
|
1002
|
+
const [s, t] = [place(snapshot.edgeSource(e)), place(snapshot.edgeTarget(e))];
|
|
1003
|
+
return s === null || t === null ? null : [(t[0] - s[0]) * window.width, (t[1] - s[1]) * window.height];
|
|
1004
|
+
};
|
|
192
1005
|
const read = (target) => {
|
|
193
1006
|
const table = target === "node" ? snapshot.nodes : snapshot.edges;
|
|
194
1007
|
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
195
1008
|
const out = valueColumns(n);
|
|
1009
|
+
const carry = carriedParams(target === "node" ? CARRIED.node : CARRIED_LINE, target === "node");
|
|
196
1010
|
for (let i = 0; i < n; i++) {
|
|
197
1011
|
context.budget.spend(target, 1);
|
|
198
1012
|
const at = (property) => ({ notes, target, property, element: i, budget: context.budget });
|
|
199
|
-
|
|
1013
|
+
const put = (property, value) => {
|
|
200
1014
|
out.put(i, property, value);
|
|
201
|
-
}
|
|
1015
|
+
};
|
|
1016
|
+
const own = cells(table, i);
|
|
1017
|
+
const get = target === "node" && voided.has(i) ? voidedParams(own, keywords[i - 1] ?? null) : carry(own);
|
|
1018
|
+
if (target === "node") {
|
|
1019
|
+
readVertex(get, put, at, place(i));
|
|
1020
|
+
keywords[i] = get(SHAPE_COLUMN);
|
|
1021
|
+
}
|
|
1022
|
+
else {
|
|
1023
|
+
readEdge(i, get, put, at);
|
|
1024
|
+
}
|
|
202
1025
|
}
|
|
203
1026
|
return out.values;
|
|
204
1027
|
};
|
|
1028
|
+
const readEdge = (i, get, put, at) => {
|
|
1029
|
+
// a loop on a placed node: an unplaced one is laid out by graphty, which draws its own loop, and a
|
|
1030
|
+
// file graphty wrote keeps its routes in its block
|
|
1031
|
+
const run = runOf(i);
|
|
1032
|
+
const loop = run !== null && block === null && snapshot.edgeSource(i) === snapshot.edgeTarget(i)
|
|
1033
|
+
? (controls) => {
|
|
1034
|
+
loops.set(i, controls);
|
|
1035
|
+
}
|
|
1036
|
+
: null;
|
|
1037
|
+
readLine(get, put, at, directed[i], labels, run, loop);
|
|
1038
|
+
if (directed[i] && loop === null && run !== null) {
|
|
1039
|
+
readArcEnd(get, put, run, targetSize(snapshot.edgeTarget(i)));
|
|
1040
|
+
}
|
|
1041
|
+
readLineValue(lineValue(i), get, put, directed[i]);
|
|
1042
|
+
readHooks(get, put, keywords[snapshot.edgeSource(i)], keywords[snapshot.edgeTarget(i)]);
|
|
1043
|
+
};
|
|
1044
|
+
const directed = directedEdges(snapshot);
|
|
1045
|
+
const keywords = [];
|
|
1046
|
+
const weights = explicitWeights(snapshot);
|
|
1047
|
+
// the line's value: its weight, or the `value` column when the import kept the value as an attribute
|
|
1048
|
+
const lineValue = (e) => weights.isExplicit(e) ? weights.value(e) : numberOrNull(cells(snapshot.edges, e)(VALUE_COLUMN));
|
|
205
1049
|
const node = read("node");
|
|
1050
|
+
// a vertex's width and height as the file draws it, for where an arc's arrowhead meets it
|
|
1051
|
+
const targetSize = (v) => {
|
|
1052
|
+
const size = (property) => {
|
|
1053
|
+
const s = node[property]?.[v];
|
|
1054
|
+
return typeof s === "number" && s > 0 ? s : PAJEK_VERTEX_SIZE;
|
|
1055
|
+
};
|
|
1056
|
+
return [size("width"), size("height")];
|
|
1057
|
+
};
|
|
206
1058
|
const edge = read("edge");
|
|
207
|
-
|
|
1059
|
+
if (draw !== null) {
|
|
1060
|
+
drawVertices(draw, snapshot, node);
|
|
1061
|
+
drawLines(draw, snapshot, node, edge);
|
|
1062
|
+
}
|
|
1063
|
+
layLoops(snapshot, loops, node, edge);
|
|
208
1064
|
if (block !== null) {
|
|
209
|
-
exactFromBlock(snapshot, block, { node, edge });
|
|
1065
|
+
exactFromBlock(snapshot, block, { node, edge }, labels);
|
|
210
1066
|
}
|
|
211
|
-
// Pajek's
|
|
1067
|
+
// Pajek's defaults that are a rule: an arc has an arrow at its target and is drawn grey and thinner, an edge not
|
|
212
1068
|
const rules = [];
|
|
213
1069
|
const columns = new Map();
|
|
214
|
-
const directed = directedEdges(snapshot);
|
|
215
1070
|
if (directed.some(Boolean)) {
|
|
216
1071
|
columns.set(DIRECTED_KEY, directed.map((d) => (d ? true : null)));
|
|
217
1072
|
rules.push({
|
|
@@ -220,14 +1075,14 @@ export function pajekStyles(snapshot, context) {
|
|
|
220
1075
|
role: "group",
|
|
221
1076
|
origin: "tool",
|
|
222
1077
|
where: { has: { style: DIRECTED_KEY } },
|
|
223
|
-
set: { targetArrow: "triangle" },
|
|
1078
|
+
set: { targetArrow: "triangle", color: ARC_DEFAULTS.color, width: ARC_DEFAULTS.width },
|
|
224
1079
|
});
|
|
225
1080
|
}
|
|
226
1081
|
return {
|
|
227
1082
|
canonical: true,
|
|
228
1083
|
dialect: "dvips",
|
|
229
1084
|
tool: "pajek",
|
|
230
|
-
units: "
|
|
1085
|
+
units: "px",
|
|
231
1086
|
node: { values: node },
|
|
232
1087
|
edge: { values: edge, rules, columns },
|
|
233
1088
|
notes: notes.list(),
|
|
@@ -238,6 +1093,60 @@ export function pajekStyles(snapshot, context) {
|
|
|
238
1093
|
},
|
|
239
1094
|
};
|
|
240
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Each vertex's place in the file's own coordinates, as the position column holds them.
|
|
1098
|
+
* @param snapshot - the graph
|
|
1099
|
+
* @returns a getter of a vertex's place, null when it has none
|
|
1100
|
+
*/
|
|
1101
|
+
function places(snapshot) {
|
|
1102
|
+
const col = snapshot.nodes.byRole("position");
|
|
1103
|
+
return (i) => {
|
|
1104
|
+
const v = col === null || col === undefined ? null : col.value(i);
|
|
1105
|
+
if (v === null || typeof v !== "object" || !("length" in v)) {
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
const [x, y] = v;
|
|
1109
|
+
return typeof x === "number" && typeof y === "number" ? [x, y] : null;
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* What the import kept for the styles: the `graphty.styles` block, the Draw window of the `pajekDraw` option, and the
|
|
1114
|
+
* vertices whose line Pajek draws with none of its parameters.
|
|
1115
|
+
* @param kept - the kept value: the block's text, or `{ block, pajekDraw, voided }`
|
|
1116
|
+
* @returns the block and the draw settings, each null when absent, and the voided vertices
|
|
1117
|
+
*/
|
|
1118
|
+
function keptOf(kept) {
|
|
1119
|
+
if (typeof kept === "string") {
|
|
1120
|
+
return { block: kept, draw: null, voided: new Set() };
|
|
1121
|
+
}
|
|
1122
|
+
if (typeof kept === "object" && kept !== null) {
|
|
1123
|
+
const { block, pajekDraw, voided } = kept;
|
|
1124
|
+
return {
|
|
1125
|
+
block: typeof block === "string" ? block : null,
|
|
1126
|
+
draw: pajekDraw ?? null,
|
|
1127
|
+
voided: new Set(voided ?? []),
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
return { block: null, draw: null, voided: new Set() };
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* The parameters Pajek 6.02 draws a voided vertex line with (`VOIDING_KEYS` in the importer): its label, and none of
|
|
1134
|
+
* its own parameters, so the vertex is Pajek's default size and colors, in the shape of the vertex line before it
|
|
1135
|
+
* (`pajek-specimen-node-sizes-opacity` `s-size-no-shape`, after a box: a box 20 across in #ffd9bc). ponytail: probes
|
|
1136
|
+
* showed the shape is not always the line before's (after `box ic Green` a voided line drew an ellipse in one file and
|
|
1137
|
+
* the triangle of two lines before in another); the rule Pajek follows was not found.
|
|
1138
|
+
* @param own - the line's own parameters
|
|
1139
|
+
* @param before - the shape keyword of the vertex line before it, or null
|
|
1140
|
+
* @returns the getter
|
|
1141
|
+
*/
|
|
1142
|
+
function voidedParams(own, before) {
|
|
1143
|
+
return (key) => {
|
|
1144
|
+
if (key === LABEL_COLUMN) {
|
|
1145
|
+
return own(key);
|
|
1146
|
+
}
|
|
1147
|
+
return key === SHAPE_COLUMN ? before : null;
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
241
1150
|
/** Pajek's shape keywords for graphty's shapes; a shape not listed is written as its nearest. */
|
|
242
1151
|
const SHAPES = new Map([
|
|
243
1152
|
["ellipse", "ellipse"],
|
|
@@ -296,12 +1205,57 @@ function shapeKeyword(get, approximate) {
|
|
|
296
1205
|
if (keyword !== undefined) {
|
|
297
1206
|
return keyword;
|
|
298
1207
|
}
|
|
1208
|
+
if (shape === "polygon" && diamondQ(get) !== null) {
|
|
1209
|
+
return "diamond";
|
|
1210
|
+
}
|
|
299
1211
|
approximate("shape", shape);
|
|
1212
|
+
const points = get("shapePoints");
|
|
1213
|
+
if (shape === "polygon" && points !== null) {
|
|
1214
|
+
approximate("shapePoints", points);
|
|
1215
|
+
}
|
|
300
1216
|
return NEAREST_SHAPES.get(shape) ?? "ellipse";
|
|
301
1217
|
}
|
|
302
1218
|
/**
|
|
303
|
-
*
|
|
304
|
-
*
|
|
1219
|
+
* The `q` of a polygon that is Pajek's unturned diamond (`readOutline`), or null for any other.
|
|
1220
|
+
* @param get - the vertex's values
|
|
1221
|
+
* @returns the diamond's `q`, or null
|
|
1222
|
+
*/
|
|
1223
|
+
function diamondQ(get) {
|
|
1224
|
+
const points = get("shapePoints");
|
|
1225
|
+
const corners = typeof points === "string"
|
|
1226
|
+
? points
|
|
1227
|
+
.trim()
|
|
1228
|
+
.split(/\s+/)
|
|
1229
|
+
.map((p) => p.split(",").map(Number))
|
|
1230
|
+
: [];
|
|
1231
|
+
if (corners.length !== 6) {
|
|
1232
|
+
return null;
|
|
1233
|
+
}
|
|
1234
|
+
const q = corners[2][0];
|
|
1235
|
+
const want = [
|
|
1236
|
+
[-1, 0],
|
|
1237
|
+
[-q, 1],
|
|
1238
|
+
[q, 1],
|
|
1239
|
+
[1, 0],
|
|
1240
|
+
[q, -1],
|
|
1241
|
+
[-q, -1],
|
|
1242
|
+
];
|
|
1243
|
+
return want.every(([x, y], k) => corners[k][0] === x && corners[k][1] === y) ? q : null;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* What Pajek draws by default for a property (`styles/defaults.ts`), which the writer leaves out.
|
|
1247
|
+
* @param target - nodes or edges
|
|
1248
|
+
* @param property - the property
|
|
1249
|
+
* @returns the default, or undefined
|
|
1250
|
+
*/
|
|
1251
|
+
function pajekDefault(target, property) {
|
|
1252
|
+
const values = toolDefaults("pajek")?.[target];
|
|
1253
|
+
return values?.[property]?.value;
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* A vertex's parameters from its values, leaving out the ellipse and the black border 1 wide Pajek draws by default;
|
|
1257
|
+
* the inverse of `readVertex`: `x_fact` and `y_fact` are the width and height over the normal size, the other lengths
|
|
1258
|
+
* points as they are.
|
|
305
1259
|
* @param get - the vertex's values
|
|
306
1260
|
* @param approximate - records approximations
|
|
307
1261
|
* @returns the parameters, the shape keyword under `shape`
|
|
@@ -313,43 +1267,139 @@ function vertexParams(get, approximate) {
|
|
|
313
1267
|
if (keyword !== "ellipse") {
|
|
314
1268
|
out.set(SHAPE_COLUMN, keyword);
|
|
315
1269
|
}
|
|
1270
|
+
const q = diamondQ(get);
|
|
1271
|
+
if (q !== null && q !== PAJEK_DIAMOND_Q) {
|
|
1272
|
+
out.set("q", q);
|
|
1273
|
+
}
|
|
1274
|
+
vertexColorParams(get, out);
|
|
1275
|
+
vertexSizeParams(get, out);
|
|
1276
|
+
const bw = get("borderWidth");
|
|
1277
|
+
if (typeof bw === "number" && bw !== pajekDefault("node", "borderWidth")) {
|
|
1278
|
+
out.set("bw", bw);
|
|
1279
|
+
}
|
|
1280
|
+
fontParam(get, out, pajekDefault("node", "labelFont"));
|
|
1281
|
+
labelPositionParams(get, out, approximate);
|
|
1282
|
+
return out;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* A vertex's colors as parameters (`ic`, `bc`, `lc`), leaving out Pajek's defaults.
|
|
1286
|
+
* @param get - the vertex's values
|
|
1287
|
+
* @param out - receives the parameters
|
|
1288
|
+
*/
|
|
1289
|
+
function vertexColorParams(get, out) {
|
|
316
1290
|
const colors = [
|
|
317
1291
|
["fill", "ic"],
|
|
318
1292
|
["borderColor", "bc"],
|
|
319
1293
|
["labelColor", "lc"],
|
|
320
1294
|
];
|
|
321
|
-
const numbers = [
|
|
322
|
-
["width", "x_fact"],
|
|
323
|
-
["height", "y_fact"],
|
|
324
|
-
["labelSize", "fos"],
|
|
325
|
-
];
|
|
326
1295
|
for (const [property, key] of colors) {
|
|
327
1296
|
const v = get(property);
|
|
328
|
-
if (typeof v === "string" &&
|
|
1297
|
+
if (typeof v === "string" && v !== pajekDefault("node", property)) {
|
|
329
1298
|
out.set(key, pajekColorText(v));
|
|
330
1299
|
}
|
|
331
1300
|
}
|
|
332
|
-
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* A vertex's sizes as parameters (`x_fact`, `y_fact`, `fos`), leaving out Pajek's defaults.
|
|
1304
|
+
* @param get - the vertex's values
|
|
1305
|
+
* @param out - receives the parameters
|
|
1306
|
+
*/
|
|
1307
|
+
function vertexSizeParams(get, out) {
|
|
1308
|
+
const numbers = [
|
|
1309
|
+
["width", "x_fact", PAJEK_VERTEX_SIZE],
|
|
1310
|
+
["height", "y_fact", PAJEK_VERTEX_SIZE],
|
|
1311
|
+
["labelSize", "fos", 1],
|
|
1312
|
+
];
|
|
1313
|
+
// a man's or a woman's box is the figure's, which reaches past the size its x_fact and y_fact give (readSize)
|
|
1314
|
+
const figure = PAJEK_FIGURES.get(String(get("shape")));
|
|
1315
|
+
for (const [property, key, per] of numbers) {
|
|
333
1316
|
const v = get(property);
|
|
334
|
-
|
|
335
|
-
|
|
1317
|
+
let over = 1;
|
|
1318
|
+
if (figure !== undefined && key !== "fos") {
|
|
1319
|
+
over = figure[key === "x_fact" ? 0 : 1];
|
|
1320
|
+
}
|
|
1321
|
+
if (typeof v === "number" && (over !== 1 || v !== pajekDefault("node", property))) {
|
|
1322
|
+
out.set(key, Number((v / (per * over)).toPrecision(15)));
|
|
336
1323
|
}
|
|
337
1324
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* A label's `font`, the inverse of `readFont`: a PostScript family with a generic one after it is written by its
|
|
1328
|
+
* PostScript name (`Courier, monospace` as `Courier`), any other family as it is; Pajek draws every label bold and
|
|
1329
|
+
* upright, so neither the weight nor the slant is written.
|
|
1330
|
+
* @param get - the element's values
|
|
1331
|
+
* @param out - the parameters, changed in place
|
|
1332
|
+
* @param skip - the font left out, Pajek's default, or undefined
|
|
1333
|
+
*/
|
|
1334
|
+
function fontParam(get, out, skip) {
|
|
1335
|
+
const font = get("labelFont");
|
|
1336
|
+
const name = typeof font === "string" && font !== "" ? graphvizFontName(font, false, false) : null;
|
|
1337
|
+
if (name !== null && name !== skip) {
|
|
1338
|
+
out.set("font", name);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* A label position as Pajek's polar label parameters, leaving out the default (20 from the center at 285 degrees): a
|
|
1343
|
+
* label centered with its left edge's middle offset from the center is `lr` and `lphi` (the inverse of
|
|
1344
|
+
* `readLabelPosition`), one centered on the vertex `lr 0`, and a side its angle `lphi`; a side Pajek cannot put a
|
|
1345
|
+
* label on is written as the nearest it can, and noted.
|
|
1346
|
+
* @param get - the vertex's values
|
|
1347
|
+
* @param out - the parameters, changed in place
|
|
1348
|
+
* @param approximate - records approximations
|
|
1349
|
+
*/
|
|
1350
|
+
function labelPositionParams(get, out, approximate) {
|
|
1351
|
+
const position = get("labelPosition");
|
|
1352
|
+
if (typeof position !== "string") {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (position === "center") {
|
|
1356
|
+
const polar = polarOf(get);
|
|
1357
|
+
if (polar === null) {
|
|
1358
|
+
out.set("lr", 0);
|
|
343
1359
|
}
|
|
344
|
-
else {
|
|
345
|
-
out.set("
|
|
1360
|
+
else if (polar[0] !== PAJEK_LABEL_RADIUS || polar[1] !== PAJEK_LABEL_ANGLE) {
|
|
1361
|
+
out.set("lr", polar[0]);
|
|
1362
|
+
out.set("lphi", polar[1]);
|
|
346
1363
|
}
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
const nearest = NEAREST_SIDES.get(position);
|
|
1367
|
+
if (nearest !== undefined) {
|
|
1368
|
+
approximate("labelPosition", position);
|
|
1369
|
+
}
|
|
1370
|
+
const angle = SIDE_ANGLES.get(nearest ?? position);
|
|
1371
|
+
if (angle !== undefined && angle !== PAJEK_LABEL_ANGLE) {
|
|
1372
|
+
out.set("lphi", angle);
|
|
347
1373
|
}
|
|
348
|
-
return out;
|
|
349
1374
|
}
|
|
350
1375
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
1376
|
+
* The `lr` and `lphi` that put a centered label where its offsets say (`labelOffset`, inverted), 6 places each.
|
|
1377
|
+
* @param get - the vertex's values
|
|
1378
|
+
* @returns `[lr, lphi]`, or null for a label on the vertex's center (no offset, no shift)
|
|
1379
|
+
*/
|
|
1380
|
+
function polarOf(get) {
|
|
1381
|
+
const [x, y, shift] = [get("labelOffsetX"), get("labelOffsetY"), get("labelShiftX")];
|
|
1382
|
+
if (typeof x !== "number" || typeof y !== "number" || shift !== 0.5) {
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
const size = get("labelSize");
|
|
1386
|
+
const up = y + PAJEK_BASELINE_TO_MIDDLE * (typeof size === "number" ? size : PAJEK_LABEL_SIZE);
|
|
1387
|
+
const round = (v) => Number(v.toFixed(6)) + 0;
|
|
1388
|
+
const lr = round(Math.hypot(x, up));
|
|
1389
|
+
return lr === 0 ? null : [lr, round(((((Math.atan2(-up, x) * 180) / Math.PI) % 360) + 360) % 360)];
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* A line's color and width when it sets neither: an arc's, or an edge's (the tool defaults).
|
|
1393
|
+
* @param directed - whether the line is an arc
|
|
1394
|
+
* @returns the color and width
|
|
1395
|
+
*/
|
|
1396
|
+
function lineDefaults(directed) {
|
|
1397
|
+
return directed ? ARC_DEFAULTS : { color: pajekDefault("edge", "color"), width: pajekDefault("edge", "width") };
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* A line's parameters from its values, leaving out the solid line Pajek draws by default (grey and 1 wide for an arc,
|
|
1401
|
+
* teal and 2 wide for an edge; `w` is half an edge's width). Arrows are Pajek's own: an arc has one at its target and
|
|
1402
|
+
* an edge none, so any other arrow is noted.
|
|
353
1403
|
* @param get - the line's values
|
|
354
1404
|
* @param directed - whether the line is an arc
|
|
355
1405
|
* @param approximate - records approximations
|
|
@@ -358,18 +1408,24 @@ function vertexParams(get, approximate) {
|
|
|
358
1408
|
function lineParams(get, directed, approximate) {
|
|
359
1409
|
const out = new Map();
|
|
360
1410
|
opaque(get, ["opacity"], approximate);
|
|
1411
|
+
const defaults = lineDefaults(directed);
|
|
361
1412
|
const color = get("color");
|
|
362
|
-
if (typeof color === "string" && color !==
|
|
1413
|
+
if (typeof color === "string" && color !== defaults.color) {
|
|
363
1414
|
out.set("c", pajekColorText(color));
|
|
364
1415
|
}
|
|
365
1416
|
const width = get("width");
|
|
366
|
-
if (typeof width === "number") {
|
|
367
|
-
out.set("w", width);
|
|
1417
|
+
if (typeof width === "number" && width !== defaults.width) {
|
|
1418
|
+
out.set("w", directed ? width : Number((width / EDGE_WIDTH_PER_W).toPrecision(15)));
|
|
368
1419
|
}
|
|
369
1420
|
const lineStyle = get("lineStyle");
|
|
370
|
-
if (typeof lineStyle === "string" && lineStyle !== "solid" && pajekDots(lineStyle, approximate)) {
|
|
1421
|
+
if (typeof lineStyle === "string" && lineStyle !== "solid" && pajekDots(lineStyle, out, directed, approximate)) {
|
|
371
1422
|
out.set("p", "Dots");
|
|
372
1423
|
}
|
|
1424
|
+
const position = get("arrowPosition");
|
|
1425
|
+
if (typeof position === "number" && position > 0) {
|
|
1426
|
+
out.set("ap", position);
|
|
1427
|
+
}
|
|
1428
|
+
lineLabelParams(get, out, approximate);
|
|
373
1429
|
const target = get("targetArrow");
|
|
374
1430
|
if (target !== null && target !== (directed ? "triangle" : "none")) {
|
|
375
1431
|
approximate("targetArrow", target);
|
|
@@ -381,77 +1437,88 @@ function lineParams(get, directed, approximate) {
|
|
|
381
1437
|
return out;
|
|
382
1438
|
}
|
|
383
1439
|
/**
|
|
384
|
-
*
|
|
1440
|
+
* A line's label parameters: its text `l` (a line break or a double quote written as Pajek can hold it, noted), its
|
|
1441
|
+
* color `lc`, size `fos` and font `font`.
|
|
1442
|
+
* @param get - the line's values
|
|
1443
|
+
* @param out - the parameters, changed in place
|
|
1444
|
+
* @param approximate - records approximations
|
|
1445
|
+
*/
|
|
1446
|
+
function lineLabelParams(get, out, approximate) {
|
|
1447
|
+
const label = get("label");
|
|
1448
|
+
if (typeof label === "string" && label !== "") {
|
|
1449
|
+
const text = pajekLabelText(label);
|
|
1450
|
+
if (text !== label) {
|
|
1451
|
+
approximate("label", label);
|
|
1452
|
+
}
|
|
1453
|
+
out.set("l", text);
|
|
1454
|
+
}
|
|
1455
|
+
const labelColor = get("labelColor");
|
|
1456
|
+
if (typeof labelColor === "string") {
|
|
1457
|
+
out.set("lc", pajekColorText(labelColor));
|
|
1458
|
+
}
|
|
1459
|
+
const labelSize = get("labelSize");
|
|
1460
|
+
if (typeof labelSize === "number") {
|
|
1461
|
+
out.set("fos", labelSize);
|
|
1462
|
+
}
|
|
1463
|
+
fontParam(get, out);
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Whether a line other than a solid one is written as Pajek's Dots: Pajek draws Solid and Dots only, and its Dots
|
|
1467
|
+
* shows dots on a wide line and dashes on a thin one (`pajekDash`); the other of the two and any other dashed kind is
|
|
385
1468
|
* nearest to Dots, any other line to Solid.
|
|
386
1469
|
* @param lineStyle - the line style
|
|
1470
|
+
* @param params - the line's parameters written so far, its `w` among them
|
|
1471
|
+
* @param directed - whether the line is an arc
|
|
387
1472
|
* @param approximate - records approximations
|
|
388
1473
|
* @returns true for Dots
|
|
389
1474
|
*/
|
|
390
|
-
function pajekDots(lineStyle, approximate) {
|
|
391
|
-
if (lineStyle ===
|
|
1475
|
+
function pajekDots(lineStyle, params, directed, approximate) {
|
|
1476
|
+
if (lineStyle === pajekDash((key) => params.get(key) ?? null, directed)) {
|
|
392
1477
|
return true;
|
|
393
1478
|
}
|
|
394
1479
|
approximate("lineStyle", lineStyle);
|
|
395
|
-
return
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Each element's values of the properties the writer writes, as a getter per element.
|
|
399
|
-
* @param picture - each element's value of a property
|
|
400
|
-
* @param target - nodes or edges
|
|
401
|
-
* @returns the getter
|
|
402
|
-
*/
|
|
403
|
-
function getter(picture, target) {
|
|
404
|
-
const columns = new Map();
|
|
405
|
-
for (const p of PAJEK_STYLE_CAPABILITIES[target]) {
|
|
406
|
-
columns.set(p, picture(target, p));
|
|
407
|
-
}
|
|
408
|
-
return (i) => (property) => columns.get(property)?.[i] ?? null;
|
|
1480
|
+
return ["dashed", "dotted", "dash-dot", "long-dash"].includes(lineStyle);
|
|
409
1481
|
}
|
|
410
1482
|
/**
|
|
411
1483
|
* For a file graphty wrote: where a value read from the parameters is what the writer writes for the block's own
|
|
412
|
-
* value (a hexagon written as an ellipse, a
|
|
1484
|
+
* value (a hexagon written as an ellipse, a dotted line as Dots), the block's exact value is the truth, so a re-import
|
|
413
1485
|
* gives back the same rules; a value another program changed since stays the truth.
|
|
414
1486
|
* @param snapshot - the graph
|
|
415
1487
|
* @param text - the block's text
|
|
416
1488
|
* @param read - the values read, changed in place
|
|
417
1489
|
* @param read.node - the node values
|
|
418
1490
|
* @param read.edge - the edge values
|
|
1491
|
+
* @param labels - whether the lines' labels are drawn
|
|
419
1492
|
*/
|
|
420
|
-
function exactFromBlock(snapshot, text, read) {
|
|
421
|
-
const parsed = parseStyleBlock(text, styleFingerprint(snapshot));
|
|
422
|
-
const ex = parsed.ok ? blockStyles(parsed.block, snapshot, "pajek") : null;
|
|
423
|
-
if (ex === null) {
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
1493
|
+
function exactFromBlock(snapshot, text, read, labels) {
|
|
426
1494
|
const notes = new StyleNotes();
|
|
427
1495
|
const directed = directedEdges(snapshot);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
values[property] ?? (values[property] = new Array(n).fill(null));
|
|
440
|
-
values[property][i] = w;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
1496
|
+
takeFromBlock(snapshot, text, "pajek", (target) => ({
|
|
1497
|
+
values: read[target],
|
|
1498
|
+
properties: READ[target],
|
|
1499
|
+
writes: PAJEK_STYLE_CAPABILITIES[target],
|
|
1500
|
+
readBack: (i, want) => {
|
|
1501
|
+
const back = writtenAndReadBack(target, want, directed[i], notes, labels);
|
|
1502
|
+
return (property) => back.get(property) ?? null;
|
|
1503
|
+
},
|
|
1504
|
+
// a label the block places by a side clears the offsets its `lphi` reads back as
|
|
1505
|
+
take: (property, wanted) => wanted !== null || LABEL_PLACE.has(property) || OUTLINE.has(property),
|
|
1506
|
+
}));
|
|
445
1507
|
}
|
|
1508
|
+
/** The outline a shape written as `diamond` reads back as, which the block's own shape clears. */
|
|
1509
|
+
const OUTLINE = new Set(["shapePoints", "shapePointsStretch"]);
|
|
1510
|
+
/** The label place properties a side written as `lphi` reads back as. */
|
|
1511
|
+
const LABEL_PLACE = new Set(["labelOffsetX", "labelOffsetY", "labelShiftX"]);
|
|
446
1512
|
/**
|
|
447
1513
|
* An element's values written as the writer writes them and read back as the reader reads them.
|
|
448
1514
|
* @param target - nodes or edges
|
|
449
1515
|
* @param want - its values
|
|
450
1516
|
* @param directed - for a line, whether it is an arc
|
|
451
1517
|
* @param notes - a scratch for the notes the round trip makes
|
|
1518
|
+
* @param labels - whether the lines' labels are drawn
|
|
452
1519
|
* @returns the values read back, by property
|
|
453
1520
|
*/
|
|
454
|
-
function writtenAndReadBack(target, want, directed, notes) {
|
|
1521
|
+
function writtenAndReadBack(target, want, directed, notes, labels) {
|
|
455
1522
|
const ignore = () => undefined;
|
|
456
1523
|
const params = target === "node" ? vertexParams(want, ignore) : lineParams(want, directed, ignore);
|
|
457
1524
|
const back = new Map();
|
|
@@ -459,11 +1526,28 @@ function writtenAndReadBack(target, want, directed, notes) {
|
|
|
459
1526
|
if (typeof label === "string") {
|
|
460
1527
|
params.set(LABEL_COLUMN, pajekLabelText(label));
|
|
461
1528
|
}
|
|
462
|
-
|
|
1529
|
+
// what the writer restates so that nothing is carried to this element (`restateCarried`)
|
|
1530
|
+
if (target === "node" && [...params.keys()].every((key) => key === LABEL_COLUMN)) {
|
|
1531
|
+
params.set(SHAPE_COLUMN, "ellipse");
|
|
1532
|
+
}
|
|
1533
|
+
for (const key of target === "edge" ? CARRIED.edge : []) {
|
|
1534
|
+
if (!params.has(key)) {
|
|
1535
|
+
params.set(key, lineRestated(key, directed));
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
const get = (key) => params.get(key) ?? null;
|
|
1539
|
+
const put = (property, value) => {
|
|
463
1540
|
if (value !== null) {
|
|
464
1541
|
back.set(property, value);
|
|
465
1542
|
}
|
|
466
|
-
}
|
|
1543
|
+
};
|
|
1544
|
+
const at = (property) => ({ notes, target, property });
|
|
1545
|
+
if (target === "node") {
|
|
1546
|
+
readVertex(get, put, at);
|
|
1547
|
+
}
|
|
1548
|
+
else {
|
|
1549
|
+
readLine(get, put, at, directed, labels);
|
|
1550
|
+
}
|
|
467
1551
|
return back;
|
|
468
1552
|
}
|
|
469
1553
|
/**
|
|
@@ -486,10 +1570,15 @@ export function pajekStyledExport(snapshot, input) {
|
|
|
486
1570
|
const approximate = (property, value) => {
|
|
487
1571
|
approximated.add(target, property, value);
|
|
488
1572
|
};
|
|
489
|
-
const get =
|
|
1573
|
+
const get = elementValues((t, p) => input.picture(t, p), target, PAJEK_STYLE_CAPABILITIES[target]);
|
|
490
1574
|
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
491
1575
|
const params = (i) => target === "node" ? vertexParams(get(i), approximate) : lineParams(get(i), directed[i], approximate);
|
|
492
|
-
|
|
1576
|
+
const columns = paramColumns(n, params);
|
|
1577
|
+
if (target === "edge") {
|
|
1578
|
+
keepLineLabels(snapshot, columns);
|
|
1579
|
+
}
|
|
1580
|
+
restateCarried(target, columns, directed);
|
|
1581
|
+
replaceParamColumns(table, target === "node" ? [SHAPE_COLUMN, ...NODE_KEYS] : EDGE_KEYS, columns);
|
|
493
1582
|
}
|
|
494
1583
|
out.nodes.set(LABEL_COLUMN, drawnLabels(input, snapshot.nodeCount, approximated), { dtype: "string", role: "label" }, {
|
|
495
1584
|
replaceRole: true,
|
|
@@ -499,6 +1588,29 @@ export function pajekStyledExport(snapshot, input) {
|
|
|
499
1588
|
notes.push(...styleBlockLosses(block, input.rules.styles.rules.length, "size"));
|
|
500
1589
|
return { snapshot: out, comment: PAJEK_STYLE_COMMENT + block, notes };
|
|
501
1590
|
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Keeps each line's own label `l` where graphty draws none: Pajek draws no line label by default (`drawsLineLabels`),
|
|
1593
|
+
* so a label the file holds is not drawn, and writing it back keeps it for a Draw window that marks lines with labels.
|
|
1594
|
+
* @param snapshot - the graph handed to the exporter
|
|
1595
|
+
* @param columns - the written edge columns, by key, changed in place
|
|
1596
|
+
*/
|
|
1597
|
+
function keepLineLabels(snapshot, columns) {
|
|
1598
|
+
if (!snapshot.edges.has("l")) {
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const own = (e) => plainCell(snapshot.edges.value("l", e));
|
|
1602
|
+
let col = columns.get("l");
|
|
1603
|
+
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
1604
|
+
const v = own(e);
|
|
1605
|
+
if (typeof v === "string" && v !== "" && (col?.[e] ?? null) === null) {
|
|
1606
|
+
col ?? (col = new Array(snapshot.edgeCount).fill(null));
|
|
1607
|
+
col[e] = pajekLabelText(v);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (col !== undefined) {
|
|
1611
|
+
columns.set("l", col);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
502
1614
|
/**
|
|
503
1615
|
* Each vertex's label as graphty draws it; a vertex graphty draws without one gets an empty label, which Pajek draws
|
|
504
1616
|
* as nothing (with no label, Pajek writes and draws the vertex's id).
|
|
@@ -547,6 +1659,59 @@ function replaceParamColumns(table, keys, columns) {
|
|
|
547
1659
|
table.set(key, col, { dtype: numeric ? "f64" : "string" });
|
|
548
1660
|
}
|
|
549
1661
|
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Keeps Pajek from drawing an element with the parameters of the one before it (`CARRIED`): a line writes Pajek's own
|
|
1664
|
+
* default for each parameter another line writes and it leaves out, and a vertex that writes no parameter while
|
|
1665
|
+
* another does writes its shape, `ellipse`, which starts it again from Pajek's defaults.
|
|
1666
|
+
* @param target - nodes or edges
|
|
1667
|
+
* @param columns - the written columns, by key, changed in place
|
|
1668
|
+
* @param directed - for each line, whether it is an arc
|
|
1669
|
+
*/
|
|
1670
|
+
function restateCarried(target, columns, directed) {
|
|
1671
|
+
if (target === "node") {
|
|
1672
|
+
const all = [...columns.values()];
|
|
1673
|
+
if (all.length === 0) {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
const n = all[0].length;
|
|
1677
|
+
const shape = columns.get(SHAPE_COLUMN) ?? new Array(n).fill(null);
|
|
1678
|
+
for (let i = 0; i < n; i++) {
|
|
1679
|
+
if (all.every((col) => col[i] === null)) {
|
|
1680
|
+
shape[i] = "ellipse";
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
columns.set(SHAPE_COLUMN, shape);
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
for (const key of CARRIED.edge) {
|
|
1687
|
+
const col = columns.get(key);
|
|
1688
|
+
if (col === undefined) {
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
for (let i = 0; i < col.length; i++) {
|
|
1692
|
+
col[i] ?? (col[i] = lineRestated(key, directed[i]));
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
/**
|
|
1697
|
+
* What a line writes for a carried parameter it leaves at Pajek's default.
|
|
1698
|
+
* @param key - the parameter
|
|
1699
|
+
* @param directed - whether the line is an arc
|
|
1700
|
+
* @returns the value written
|
|
1701
|
+
*/
|
|
1702
|
+
function lineRestated(key, directed) {
|
|
1703
|
+
const defaults = lineDefaults(directed);
|
|
1704
|
+
switch (key) {
|
|
1705
|
+
case "c":
|
|
1706
|
+
return pajekColorText(String(defaults.color));
|
|
1707
|
+
case "w":
|
|
1708
|
+
return directed ? Number(defaults.width) : Number(defaults.width) / EDGE_WIDTH_PER_W;
|
|
1709
|
+
case "p":
|
|
1710
|
+
return "Solid";
|
|
1711
|
+
default:
|
|
1712
|
+
return 0;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
550
1715
|
/**
|
|
551
1716
|
* Every element's parameters, as columns.
|
|
552
1717
|
* @param n - the element count
|