diagrammatron 0.4.2 → 0.4.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 393c2881f870f2371e5af2e9a33fcfac3f82d9c3da69f7f377d87606b7230557
4
- data.tar.gz: '019f726f35066af4fc209d61a2adbf36de1c6393d0089924912ca6c0e73baef0'
3
+ metadata.gz: 7f4b7974989ef344d2eaaae0c54f82567b8ed9edd9c7fb5d2dfc3e405895efa7
4
+ data.tar.gz: efdd52da27d648f9da7fed309ba668eae6237eeddd51a703c47c46c45c394435
5
5
  SHA512:
6
- metadata.gz: 737105dcbe2c8dc6d636833079d2313be3b5f2c66d86d252127664948365b92f976622b65019e9b5ddd1f7b760f35a15fef9e30fdd749fae99441a31fb03bb8e
7
- data.tar.gz: c091a6a5f862353afb8f730dbf8b35cf226c5627e6d352f1ad8366ca6d03cb338e61264c22876948806afdc0965f1df0ee81223f07750f61c73a8cd171ab0538
6
+ metadata.gz: e235a20fb0fb4013e4f0006731743830f84500519d2ab4262b04caa9bae0962bd7da5127cd30e44c9e6bf891b735a02f10fe193149047fa6b54ec0bd6185f2e5
7
+ data.tar.gz: e6c4c3db889c83d23390ee874379215747fb4336fbb3f1f2f543226ab72788fe948a6394e500ea89ed4d4a013126a324b10fa5b49bf73be9233cd94e9781a024
@@ -158,6 +158,10 @@ Segment = Struct.new(:vertical, :cc, :range, :edge_index, :at_node, :segment_ind
158
158
  def increase?
159
159
  range[0] < range[1]
160
160
  end
161
+
162
+ def within(s)
163
+ s.range.min < range.min && range.max < s.range.max
164
+ end
161
165
  end
162
166
 
163
167
  def segment(x0, y0, x1, y1)
@@ -415,40 +419,16 @@ def path_order_at_side(a, b, conn)
415
419
  d
416
420
  end
417
421
 
418
- def segment_order(a, b)
419
- d = a[1] <=> b[1]
422
+ def length_order(a, b)
423
+ d = a[2].length <=> b[2].length
420
424
  return d unless d.zero?
421
- case a[1]
422
- when 0 # Ascending on length, range minimum. =|
423
- d = a[2].length <=> b[2].length
424
- return d unless d.zero?
425
- d = a[2].range.min <=> b[2].range.min
426
- return d unless d.zero?
427
- when 1 # Top left, vertical, bottom right: -|_
428
- d = a[2].range.min <=> b[2].range.min # Ascend on minimum.
429
- return d unless d.zero?
430
- d = a[2].length <=> b[2].length # Ascend on length.
431
- return d unless d.zero?
432
- when 2 # From top right, down, bottom left: _|-
433
- d = a[2].range.max <=> b[2].range.max # Descend on maximum.
434
- return -d unless d.zero?
435
- d = a[2].length <=> b[2].length # Ascend on length.
436
- return d unless d.zero?
437
- when 3 # Descending on length, range maximum. |=
438
- d = a[2].length <=> b[2].length
439
- return -d unless d.zero?
440
- d = a[2].range.max <=> b[2].range.max
441
- return -d unless d.zero?
442
- end
443
425
  a[0].edge_index <=> b[0].edge_index
444
426
  end
445
427
 
446
- def zigzag_order(from_right_up_to_left, from_left_up_to_right)
447
- # Eventually interleave the two sets, if it makes sense.
448
- out = []
449
- from_right_up_to_left.each { |x| out.push x }
450
- from_left_up_to_right.each { |x| out.push x }
451
- out
428
+ def min_order(a, b)
429
+ d = a[2].range.min <=> b[2].range.min
430
+ return d unless d.zero?
431
+ a[0].edge_index <=> b[0].edge_index
452
432
  end
453
433
 
454
434
  def overlaps_set(c, others)
@@ -458,47 +438,59 @@ def overlaps_set(c, others)
458
438
  false
459
439
  end
460
440
 
461
- def group_minimal_offsets(group)
462
- return 0 if group.empty?
463
- off = { 1 => [] }
464
- cands = off.keys
465
- group.each do |a|
466
- fit = false
467
- cands.each do |k|
468
- next if overlaps_set(a[2], off[k])
469
- off[k].push(a)
470
- fit = true
471
- break
441
+ def layered_order(u_shaped, z_shaped)
442
+ u_shaped.sort! { |a, b| length_order(a, b) }
443
+ z_shaped.sort! { |a, b| min_order(a, b) }
444
+ out = []
445
+ layer = []
446
+ until u_shaped.empty?
447
+ rejects = []
448
+ found = false
449
+ u_shaped.each do |a|
450
+ unless overlaps_set(a[2], layer)
451
+ found = true
452
+ # Creates crossing by putting in front of shorter segment fully within?
453
+ rejects.each do |r|
454
+ if r[2].within(a[2])
455
+ found = false
456
+ break
457
+ end
458
+ end
459
+ end
460
+ if found
461
+ layer.push a
462
+ found = false
463
+ else
464
+ rejects.push a
465
+ end
466
+ end
467
+ u_shaped = rejects
468
+ unless layer.empty?
469
+ out.concat layer
470
+ out.push nil
471
+ layer = []
472
472
  end
473
- next if fit
474
- cands.push(cands.last + 1)
475
- off[cands.last] = [ a ]
476
473
  end
477
- off.each_pair do |offset, fitting|
478
- fitting.each do |sg|
479
- sg[0].offset = offset
474
+ until z_shaped.empty?
475
+ rejects = []
476
+ found = false
477
+ z_shaped.each do |a|
478
+ if overlaps_set(a[2], layer)
479
+ rejects.push a
480
+ else
481
+ layer.push a
482
+ found = true
483
+ end
484
+ end
485
+ z_shaped = rejects
486
+ unless layer.empty?
487
+ out.concat layer
488
+ out.push nil
489
+ layer = []
480
490
  end
481
491
  end
482
- off.keys.max
483
- end
484
-
485
- def group_stacked_offsets(group)
486
- return 0 if group.empty?
487
- group.each_index do |k|
488
- group[k][0].offset = k + 1
489
- end
490
- return group.size
491
- %q(
492
- # This produces narrower gaps but they may be less clear.
493
- prev = group[0]
494
- prev[0].offset = 1
495
- (1...group.size).each do |k|
496
- g = group[k]
497
- g[0].offset = prev[0].offset + (g[2].range_overlap(prev[2]) ? 1 : 0)
498
- prev = g
499
- end
500
- prev[0].offset
501
- )
492
+ out.concat(layer) unless layer.empty?
493
+ out
502
494
  end
503
495
 
504
496
  def direct_range(paths)
@@ -631,36 +623,22 @@ def place_edges(work)
631
623
  end
632
624
  gaps.each_value do |direction|
633
625
  direction.each_value do |gap|
634
- #gap.sort! { |a, b| segment_order(a, b) }
635
626
  gleft = gap.select { |a| a[1].zero? }
636
- gleft.sort! { |a, b| segment_order(a, b) }
627
+ grul = gap.select { |a| a[1] == 1 }
628
+ glur = gap.select { |a| a[1] == 2 }
637
629
  gright = gap.select { |a| a[1] == 3 }
638
- gright.sort! { |a, b| segment_order(a, b) }
639
- gright.reverse!
640
- grul = gap.select() { |a| a[1] == 1 }
641
- grul.sort! { |a, b| segment_order(a, b) }
642
- glur = gap.select() { |a| a[1] == 2 }
643
- glur.sort! { |a, b| segment_order(a, b) }
644
- gmiddle = zigzag_order(grul, glur)
645
- gmiddle.each do |s|
646
- s[1] = 1
647
- end
648
- gap = gleft + gmiddle + gright
649
- c = [
650
- group_minimal_offsets(gleft),
651
- group_stacked_offsets(gmiddle),
652
- 0,
653
- group_minimal_offsets(gright)
654
- ]
655
- before = [ 0 ]
656
- denominator = 1 + c[0]
657
- (1...c.size).each do |k|
658
- denominator += c[k]
659
- before.push(c[k - 1] + before.last)
660
- end
661
- gap.each do |sg|
662
- sg[0].offset = c[sg[1]] + 1 - sg[0].offset if sg[1] > 1
663
- sg[0].offset = Rational(sg[0].offset + before[sg[1]], denominator)
630
+ all = layered_order(gleft, grul)
631
+ all.push nil
632
+ all.concat(layered_order(gright, glur).reverse)
633
+ # Give each rational offset using layer index + 1 and layer count + 2.
634
+ denominator = 2 + all.count { |x| x.nil? }
635
+ layer = 1
636
+ all.each do |sg|
637
+ if sg.nil?
638
+ layer += 1
639
+ else
640
+ sg[0].offset = Rational(layer, denominator)
641
+ end
664
642
  end
665
643
  end
666
644
  end
@@ -80,9 +80,10 @@ class Styles
80
80
  def base_styles(m, styles, group)
81
81
  d = styles.dig(group, 'default')
82
82
  if d.nil?
83
- d = m.fetch('default', {}) if d.nil?
83
+ d = m.fetch('default', {}) # No default in styles.
84
84
  else
85
85
  m['default'] = m.fetch('default', {}).merge(d)
86
+ d = m['default']
86
87
  end
87
88
  styles.fetch(group, {}).each_pair do |name, values|
88
89
  s = d.clone
@@ -280,6 +281,27 @@ def apply(doc, template)
280
281
  out
281
282
  end
282
283
 
284
+ def reverse_depth_order(a, b)
285
+ d = b['depth'] <=> a['depth']
286
+ return d unless d.zero?
287
+ d = a['index'] <=> b['index']
288
+ return d unless d.zero?
289
+ a['kind'] <=> b['kind']
290
+ end
291
+
292
+ def reverse_depth_sort(items)
293
+ arr = []
294
+ items.each_index do |k|
295
+ arr.push({
296
+ 'depth' => items[k].fetch('depth', 0),
297
+ 'index' => k,
298
+ 'kind' => items[k].fetch('kind', 'unknown')
299
+ })
300
+ end
301
+ arr.sort! { |a, b| reverse_depth_order(a, b) }
302
+ arr.map { |x| items[x['index']] }
303
+ end
304
+
283
305
  def main
284
306
  template = nil
285
307
  input = nil
@@ -354,6 +376,30 @@ Output is the file produced by the erb-template.
354
376
  remap_coordinates(xcoords, xmax, x2min, doc.dig('diagram', 'edge_gap'))
355
377
  remap_coordinates(ycoords, ymax, y2min, doc.dig('diagram', 'edge_gap'))
356
378
 
379
+ doc['nodes'] = reverse_depth_sort(doc.fetch('nodes', []))
380
+ doc['edges'] = reverse_depth_sort(doc.fetch('edges', []))
381
+ all = doc.fetch('nodes', []).map do |a|
382
+ {
383
+ 'kind' => 'node',
384
+ 'depth' => a.fetch('depth', 0),
385
+ 'item' => a
386
+ }
387
+ end
388
+ all.concat(doc.fetch('edges', []).map do |a|
389
+ {
390
+ 'kind' => 'edge',
391
+ 'depth' => a.fetch('depth', 0),
392
+ 'item' => a
393
+ }
394
+ end)
395
+ all = reverse_depth_sort(all)
396
+ doc['all'] = all.map do |x|
397
+ {
398
+ 'kind' => x['kind'],
399
+ 'item' => x['item']
400
+ }
401
+ end
402
+
357
403
  dump_result(output, apply(doc, template), 5)
358
404
  end
359
405
 
@@ -19,6 +19,7 @@ styles:
19
19
  fill: "#ffffff"
20
20
  stroke: "#000000"
21
21
  stroke_width: 2
22
+ depth: 0
22
23
  size_estimator: |
23
24
  $render.default_size($render.node['font_size'],
24
25
  $render.node['font_width'], $render.node['font_height'],
@@ -29,4 +30,5 @@ styles:
29
30
  default:
30
31
  stroke_width: 2
31
32
  stroke: "#000000"
32
- base64template: PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwlPQp3LCBoaCA9ICRyZW5kZXIuZGltZW5zaW9ucwpoaCArPSAkcmVuZGVyLmRvYy5kaWcoJ2RpYWdyYW0nLCAnaGVpZ2h0X21hcmdpbicpCgpvdXQgPSBbCiAgJSg8c3ZnIHdpZHRoPSIje3cgKyAkcmVuZGVyLmRvYy5kaWcoJ2RpYWdyYW0nLCAnd2lkdGhfbWFyZ2luJyl9IiBoZWlnaHQ9IiN7aGh9IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiPikKXQokcmVuZGVyLmRvYy5mZXRjaCgnZWRnZXMnLCBbXSkuZWFjaCBkbyB8ZWRnZXwKICBsaW5lc3R5bGUgPSAlKGZpbGw9Im5vbmUiIHN0cm9rZT0iI3tlZGdlWydzdHJva2UnXX0iIHN0cm9rZS13aWR0aD0iI3tlZGdlWydzdHJva2Vfd2lkdGgnXX0iKQogIHBhdGggPSBlZGdlLmZldGNoKCdwYXRoJywgbmlsKQogIG5leHQgaWYgcGF0aC5uaWw/CiAgcGF0aC5lYWNoIGRvIHxwfAogICAgcFsneG8nXSA9IHBbJ3hvJ10udG9faS50b19zCiAgICBwWyd5byddID0gKGhoIC0gcFsneW8nXSkudG9faS50b19zCiAgZW5kCiAgaWYgcGF0aC5zaXplID09IDIKICAgIG91dC5wdXNoKCUoPGxpbmUgI3tsaW5lc3R5bGV9IHgxPSIje3BhdGhbMF1bJ3hvJ119IiB4Mj0iI3twYXRoWzFdWyd4byddfSIgeTE9IiN7cGF0aFswXVsneW8nXX0iIHkyPSIje3BhdGhbMV1bJ3lvJ119Ii8+KSkKICBlbHNlCiAgICBwdHMgPSBwYXRoLm1hcCB7IHxwfCAiI3twWyd4byddfSwje3BbJ3lvJ119IiB9CiAgICBvdXQucHVzaCglKDxwb2x5bGluZSAje2xpbmVzdHlsZX0gcG9pbnRzPSIje3B0cy5qb2luKCcgJyl9Ii8+KSkKICBlbmQKZW5kCiRyZW5kZXIuZG9jLmZldGNoKCdub2RlcycsIFtdKS5lYWNoIGRvIHxub2RlfAogIHcgPSBub2RlWyd3J10udG9faQogIGggPSBub2RlWydoJ10udG9faQogIHggPSBub2RlWyd4byddLnRvX2kKICB5ID0gaGggLSBub2RlWyd5byddLnRvX2kgLSBoCiAgbm9kZXN0eWxlID0gJShmaWxsPSIje25vZGVbJ2ZpbGwnXX0iIHN0cm9rZT0iI3tub2RlWydzdHJva2UnXX0iIHN0cm9rZS13aWR0aD0iI3tub2RlWydzdHJva2Vfd2lkdGgnXX0iKQogIG91dC5wdXNoKCUoPHJlY3QgI3tub2Rlc3R5bGV9IGhlaWdodD0iI3tofSIgd2lkdGg9IiN7d30iIHg9IiN7eH0iIHk9IiN7eX0iLz4pKQogIHggKz0gbm9kZVsnd2lkdGhfbWFyZ2luJ10KICBmcyA9IG5vZGVbJ2ZvbnRfc2l6ZSddCiAgbGggPSBmcyAqICgxICsgbm9kZVsnZm9udF9saW5lX3NwYWNpbmcnXSkKICB5ICs9IG5vZGVbJ2hlaWdodF9tYXJnaW4nXSArIGZzICogbm9kZVsnZm9udF9hc2NlbmQnXSAjIEJhc2VsaW5lIGZvciBmaXJzdCBsaW5lLgogIHVybCA9IG5vZGUuZmV0Y2goJ3VybCcsIG5pbCkKICB1cmwuZW5jb2RlISg6eG1sID0+IDphdHRyKSB1bmxlc3MgdXJsLm5pbD8KICB5MCA9IHkKICB0ZXh0c3R5bGUgPSAlKGZpbGw9IiN7bm9kZVsnZm9udF9maWxsJ119IiBmb250LWZhbWlseT0ic2VyaWYiIGZvbnQtc2l6ZT0iI3tmc30iIHN0cm9rZT0iI3tub2RlWydmb250X2ZpbGwnXX0iIHN0cm9rZS13aWR0aD0iMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIpCiAgbGlua3N0eWxlID0gJShmaWxsPSIje25vZGVbJ3VybF9maWxsJ119IiBmb250LWZhbWlseT0ic2VyaWYiIGZvbnQtc2l6ZT0iI3tmc30iIHN0cm9rZT0iI3tub2RlWyd1cmxfZmlsbCddfSIgc3Ryb2tlLXdpZHRoPSIwIiB4bWw6c3BhY2U9InByZXNlcnZlIikKICBub2RlWyd0ZXh0J10uZWFjaCBkbyB8bGluZXwKICAgIGxpbmUuZW5jb2RlISg6eG1sID0+IDp0ZXh0KQogICAgaWYgdXJsLm5pbD8KICAgICAgb3V0LnB1c2goJSg8dGV4dCAje3RleHRzdHlsZX0geD0iI3t4fSIgeT0iI3t5MH0iPiN7bGluZX08L3RleHQ+KSkKICAgIGVsc2UKICAgICAgb3V0LnB1c2goJSg8YSB4bGluazpocmVmPSN7dXJsfSB0YXJnZXQ9Il9wYXJlbnQiPjx0ZXh0ICN7bGlua3N0eWxlfSB4PSIje3h9IiB5PSIje3kwfSI+I3tsaW5lfTwvdGV4dD48L2E+KSkKICAgIGVuZAogICAgeTAgKz0gbGggIyBTaGlmdCBiYXNlbGluZSBieSBmdWxsIGxpbmUgKyBzcGFjaW5nIGhlaWdodC4KICBlbmQKZW5kCm91dC5qb2luKCJcbiIpCiU+Cjwvc3ZnPgo=
33
+ depth: 0
34
+ base64template: PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwlPQp3LCBoaCA9ICRyZW5kZXIuZGltZW5zaW9ucwpoaCArPSAkcmVuZGVyLmRvYy5kaWcoJ2RpYWdyYW0nLCAnaGVpZ2h0X21hcmdpbicpCgpvdXQgPSBbCiAgJSg8c3ZnIHdpZHRoPSIje3cgKyAkcmVuZGVyLmRvYy5kaWcoJ2RpYWdyYW0nLCAnd2lkdGhfbWFyZ2luJyl9IiBoZWlnaHQ9IiN7aGh9IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiPikKXQokcmVuZGVyLmRvY1snYWxsJ10uZWFjaCBkbyB8aXRlbXwKICBpZiBpdGVtWydraW5kJ10gPT0gJ25vZGUnCiAgICBub2RlID0gaXRlbVsnaXRlbSddCiAgICB3ID0gbm9kZVsndyddLnRvX2kKICAgIGggPSBub2RlWydoJ10udG9faQogICAgeCA9IG5vZGVbJ3hvJ10udG9faQogICAgeSA9IGhoIC0gbm9kZVsneW8nXS50b19pIC0gaAogICAgbm9kZXN0eWxlID0gJShmaWxsPSIje25vZGVbJ2ZpbGwnXX0iIHN0cm9rZT0iI3tub2RlWydzdHJva2UnXX0iIHN0cm9rZS13aWR0aD0iI3tub2RlWydzdHJva2Vfd2lkdGgnXX0iKQogICAgb3V0LnB1c2goJSg8cmVjdCAje25vZGVzdHlsZX0gaGVpZ2h0PSIje2h9IiB3aWR0aD0iI3t3fSIgeD0iI3t4fSIgeT0iI3t5fSIvPikpCiAgICB4ICs9IG5vZGVbJ3dpZHRoX21hcmdpbiddCiAgICBmcyA9IG5vZGVbJ2ZvbnRfc2l6ZSddCiAgICBsaCA9IGZzICogKDEgKyBub2RlWydmb250X2xpbmVfc3BhY2luZyddKQogICAgeSArPSBub2RlWydoZWlnaHRfbWFyZ2luJ10gKyBmcyAqIG5vZGVbJ2ZvbnRfYXNjZW5kJ10gIyBCYXNlbGluZSBmb3IgZmlyc3QgbGluZS4KICAgIHVybCA9IG5vZGUuZmV0Y2goJ3VybCcsIG5pbCkKICAgIHVybC5lbmNvZGUhKDp4bWwgPT4gOmF0dHIpIHVubGVzcyB1cmwubmlsPwogICAgeTAgPSB5CiAgICB0ZXh0c3R5bGUgPSAlKGZpbGw9IiN7bm9kZVsnZm9udF9maWxsJ119IiBmb250LWZhbWlseT0ic2VyaWYiIGZvbnQtc2l6ZT0iI3tmc30iIHN0cm9rZT0iI3tub2RlWydmb250X2ZpbGwnXX0iIHN0cm9rZS13aWR0aD0iMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIpCiAgICBsaW5rc3R5bGUgPSAlKGZpbGw9IiN7bm9kZVsndXJsX2ZpbGwnXX0iIGZvbnQtZmFtaWx5PSJzZXJpZiIgZm9udC1zaXplPSIje2ZzfSIgc3Ryb2tlPSIje25vZGVbJ3VybF9maWxsJ119IiBzdHJva2Utd2lkdGg9IjAiIHhtbDpzcGFjZT0icHJlc2VydmUiKQogICAgbm9kZVsndGV4dCddLmVhY2ggZG8gfGxpbmV8CiAgICAgIGxpbmUuZW5jb2RlISg6eG1sID0+IDp0ZXh0KQogICAgICBpZiB1cmwubmlsPwogICAgICAgIG91dC5wdXNoKCUoPHRleHQgI3t0ZXh0c3R5bGV9IHg9IiN7eH0iIHk9IiN7eTB9Ij4je2xpbmV9PC90ZXh0PikpCiAgICAgIGVsc2UKICAgICAgICBvdXQucHVzaCglKDxhIHhsaW5rOmhyZWY9I3t1cmx9IHRhcmdldD0iX3BhcmVudCI+PHRleHQgI3tsaW5rc3R5bGV9IHg9IiN7eH0iIHk9IiN7eTB9Ij4je2xpbmV9PC90ZXh0PjwvYT4pKQogICAgICBlbmQKICAgICAgeTAgKz0gbGggIyBTaGlmdCBiYXNlbGluZSBieSBmdWxsIGxpbmUgKyBzcGFjaW5nIGhlaWdodC4KICAgIGVuZAogIGVsc2UKICAgIGVkZ2UgPSBpdGVtWydpdGVtJ10KICAgIGxpbmVzdHlsZSA9ICUoZmlsbD0ibm9uZSIgc3Ryb2tlPSIje2VkZ2VbJ3N0cm9rZSddfSIgc3Ryb2tlLXdpZHRoPSIje2VkZ2VbJ3N0cm9rZV93aWR0aCddfSIpCiAgICBwYXRoID0gZWRnZS5mZXRjaCgncGF0aCcsIG5pbCkKICAgIG5leHQgaWYgcGF0aC5uaWw/CiAgICBwYXRoLmVhY2ggZG8gfHB8CiAgICAgIHBbJ3hvJ10gPSBwWyd4byddLnRvX2kudG9fcwogICAgICBwWyd5byddID0gKGhoIC0gcFsneW8nXSkudG9faS50b19zCiAgICBlbmQKICAgIGlmIHBhdGguc2l6ZSA9PSAyCiAgICAgIG91dC5wdXNoKCUoPGxpbmUgI3tsaW5lc3R5bGV9IHgxPSIje3BhdGhbMF1bJ3hvJ119IiB4Mj0iI3twYXRoWzFdWyd4byddfSIgeTE9IiN7cGF0aFswXVsneW8nXX0iIHkyPSIje3BhdGhbMV1bJ3lvJ119Ii8+KSkKICAgIGVsc2UKICAgICAgcHRzID0gcGF0aC5tYXAgeyB8cHwgIiN7cFsneG8nXX0sI3twWyd5byddfSIgfQogICAgICBvdXQucHVzaCglKDxwb2x5bGluZSAje2xpbmVzdHlsZX0gcG9pbnRzPSIje3B0cy5qb2luKCcgJyl9Ii8+KSkKICAgIGVuZAogIGVuZAplbmQKb3V0LmpvaW4oIlxuIikKJT4KPC9zdmc+Cg==
data/template/root.yaml CHANGED
@@ -18,6 +18,7 @@ styles:
18
18
  fill: "#ffffff"
19
19
  stroke: "#000000"
20
20
  stroke_width: 2
21
+ depth: 0
21
22
  size_estimator: |
22
23
  $render.default_size($render.node['font_size'],
23
24
  $render.node['font_width'], $render.node['font_height'],
@@ -28,3 +29,4 @@ styles:
28
29
  default:
29
30
  stroke_width: 2
30
31
  stroke: "#000000"
32
+ depth: 0
data/template/svg_1.1.erb CHANGED
@@ -6,45 +6,48 @@ hh += $render.doc.dig('diagram', 'height_margin')
6
6
  out = [
7
7
  %(<svg width="#{w + $render.doc.dig('diagram', 'width_margin')}" height="#{hh}" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">)
8
8
  ]
9
- $render.doc.fetch('edges', []).each do |edge|
10
- linestyle = %(fill="none" stroke="#{edge['stroke']}" stroke-width="#{edge['stroke_width']}")
11
- path = edge.fetch('path', nil)
12
- next if path.nil?
13
- path.each do |p|
14
- p['xo'] = p['xo'].to_i.to_s
15
- p['yo'] = (hh - p['yo']).to_i.to_s
16
- end
17
- if path.size == 2
18
- out.push(%(<line #{linestyle} x1="#{path[0]['xo']}" x2="#{path[1]['xo']}" y1="#{path[0]['yo']}" y2="#{path[1]['yo']}"/>))
9
+ $render.doc['all'].each do |item|
10
+ if item['kind'] == 'node'
11
+ node = item['item']
12
+ w = node['w'].to_i
13
+ h = node['h'].to_i
14
+ x = node['xo'].to_i
15
+ y = hh - node['yo'].to_i - h
16
+ nodestyle = %(fill="#{node['fill']}" stroke="#{node['stroke']}" stroke-width="#{node['stroke_width']}")
17
+ out.push(%(<rect #{nodestyle} height="#{h}" width="#{w}" x="#{x}" y="#{y}"/>))
18
+ x += node['width_margin']
19
+ fs = node['font_size']
20
+ lh = fs * (1 + node['font_line_spacing'])
21
+ y += node['height_margin'] + fs * node['font_ascend'] # Baseline for first line.
22
+ url = node.fetch('url', nil)
23
+ url.encode!(:xml => :attr) unless url.nil?
24
+ y0 = y
25
+ textstyle = %(fill="#{node['font_fill']}" font-family="serif" font-size="#{fs}" stroke="#{node['font_fill']}" stroke-width="0" xml:space="preserve")
26
+ linkstyle = %(fill="#{node['url_fill']}" font-family="serif" font-size="#{fs}" stroke="#{node['url_fill']}" stroke-width="0" xml:space="preserve")
27
+ node['text'].each do |line|
28
+ line.encode!(:xml => :text)
29
+ if url.nil?
30
+ out.push(%(<text #{textstyle} x="#{x}" y="#{y0}">#{line}</text>))
31
+ else
32
+ out.push(%(<a xlink:href=#{url} target="_parent"><text #{linkstyle} x="#{x}" y="#{y0}">#{line}</text></a>))
33
+ end
34
+ y0 += lh # Shift baseline by full line + spacing height.
35
+ end
19
36
  else
20
- pts = path.map { |p| "#{p['xo']},#{p['yo']}" }
21
- out.push(%(<polyline #{linestyle} points="#{pts.join(' ')}"/>))
22
- end
23
- end
24
- $render.doc.fetch('nodes', []).each do |node|
25
- w = node['w'].to_i
26
- h = node['h'].to_i
27
- x = node['xo'].to_i
28
- y = hh - node['yo'].to_i - h
29
- nodestyle = %(fill="#{node['fill']}" stroke="#{node['stroke']}" stroke-width="#{node['stroke_width']}")
30
- out.push(%(<rect #{nodestyle} height="#{h}" width="#{w}" x="#{x}" y="#{y}"/>))
31
- x += node['width_margin']
32
- fs = node['font_size']
33
- lh = fs * (1 + node['font_line_spacing'])
34
- y += node['height_margin'] + fs * node['font_ascend'] # Baseline for first line.
35
- url = node.fetch('url', nil)
36
- url.encode!(:xml => :attr) unless url.nil?
37
- y0 = y
38
- textstyle = %(fill="#{node['font_fill']}" font-family="serif" font-size="#{fs}" stroke="#{node['font_fill']}" stroke-width="0" xml:space="preserve")
39
- linkstyle = %(fill="#{node['url_fill']}" font-family="serif" font-size="#{fs}" stroke="#{node['url_fill']}" stroke-width="0" xml:space="preserve")
40
- node['text'].each do |line|
41
- line.encode!(:xml => :text)
42
- if url.nil?
43
- out.push(%(<text #{textstyle} x="#{x}" y="#{y0}">#{line}</text>))
37
+ edge = item['item']
38
+ linestyle = %(fill="none" stroke="#{edge['stroke']}" stroke-width="#{edge['stroke_width']}")
39
+ path = edge.fetch('path', nil)
40
+ next if path.nil?
41
+ path.each do |p|
42
+ p['xo'] = p['xo'].to_i.to_s
43
+ p['yo'] = (hh - p['yo']).to_i.to_s
44
+ end
45
+ if path.size == 2
46
+ out.push(%(<line #{linestyle} x1="#{path[0]['xo']}" x2="#{path[1]['xo']}" y1="#{path[0]['yo']}" y2="#{path[1]['yo']}"/>))
44
47
  else
45
- out.push(%(<a xlink:href=#{url} target="_parent"><text #{linkstyle} x="#{x}" y="#{y0}">#{line}</text></a>))
48
+ pts = path.map { |p| "#{p['xo']},#{p['yo']}" }
49
+ out.push(%(<polyline #{linestyle} points="#{pts.join(' ')}"/>))
46
50
  end
47
- y0 += lh # Shift baseline by full line + spacing height.
48
51
  end
49
52
  end
50
53
  out.join("\n")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diagrammatron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismo Kärkkäinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-31 00:00:00.000000000 Z
11
+ date: 2023-02-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14