xyc
2025-02-21 664db98c9e8595ce4dd636a27f480e3a08b81ff5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* eslint-env qunit */
import '../editor/svgpathseg.js';
import {NS} from '../editor/namespaces.js';
import * as utilities from '../editor/utilities.js';
import * as transformlist from '../editor/svgtransformlist.js';
import * as math from '../editor/math.js';
 
// log function
QUnit.log((details) => {
  if (window.console && window.console.log) {
    window.console.log(details.result + ' :: ' + details.message);
  }
});
 
const currentLayer = document.getElementById('layer1');
 
function mockCreateSVGElement (jsonMap) {
  const elem = document.createElementNS(NS.SVG, jsonMap['element']);
  for (const attr in jsonMap['attr']) {
    elem.setAttribute(attr, jsonMap['attr'][attr]);
  }
  return elem;
}
function mockaddSVGElementFromJson (json) {
  const elem = mockCreateSVGElement(json);
  currentLayer.append(elem);
  return elem;
}
 
// const svg = document.createElementNS(NS.SVG, 'svg');
const groupWithMatrixTransform = document.getElementById('svg_group_with_matrix_transform');
const textWithMatrixTransform = document.getElementById('svg_text_with_matrix_transform');
 
function fillDocumentByCloningElement (elem, count) {
  const elemId = elem.getAttribute('id') + '-';
  for (let index = 0; index < count; index++) {
    const clone = elem.cloneNode(true); // t: deep clone
    // Make sure you set a unique ID like a real document.
    clone.setAttribute('id', elemId + index);
    const parent = elem.parentNode;
    parent.append(clone);
  }
}
 
QUnit.module('svgedit.utilities_performance', {
  beforeEach () {
  },
  afterEach () {
  }
});
 
const mockPathActions = {
  resetOrientation (path) {
    if (path == null || path.nodeName !== 'path') { return false; }
    const tlist = transformlist.getTransformList(path);
    const m = math.transformListToTransform(tlist).matrix;
    tlist.clear();
    path.removeAttribute('transform');
    const segList = path.pathSegList;
 
    const len = segList.numberOfItems;
    // let lastX, lastY;
 
    for (let i = 0; i < len; ++i) {
      const seg = segList.getItem(i);
      const type = seg.pathSegType;
      if (type === 1) { continue; }
      const pts = [];
      ['', 1, 2].forEach(function (n, j) {
        const x = seg['x' + n], y = seg['y' + n];
        if (x !== undefined && y !== undefined) {
          const pt = math.transformPoint(x, y, m);
          pts.splice(pts.length, 0, pt.x, pt.y);
        }
      });
      // path.replacePathSeg(type, i, pts, path);
    }
 
    // utilities.reorientGrads(path, m);
  }
};
 
// //////////////////////////////////////////////////////////
// Performance times with various browsers on Macbook 2011 8MB RAM OS X El Capitan 10.11.4
//
// To see 'Before Optimization' performance, making the following two edits.
// 1. utilities.getStrokedBBox - change if( elems.length === 1) to if( false && elems.length === 1)
// 2. utilities.getBBoxWithTransform - uncomment 'Old technique that was very slow'
 
// Chrome
// Before Optimization
//     Pass1 svgCanvas.getStrokedBBox total ms 4,218, ave ms 41.0,     min/max 37 51
//     Pass2 svgCanvas.getStrokedBBox total ms 4,458, ave ms 43.3,     min/max 32 63
// Optimized Code
//     Pass1 svgCanvas.getStrokedBBox total ms 1,112, ave ms 10.8,     min/max 9 20
//     Pass2 svgCanvas.getStrokedBBox total ms        34, ave ms    0.3,     min/max 0 20
 
// Firefox
// Before Optimization
//     Pass1 svgCanvas.getStrokedBBox total ms 3,794, ave ms 36.8,     min/max 33 48
//     Pass2 svgCanvas.getStrokedBBox total ms 4,049, ave ms 39.3,     min/max 28 53
// Optimized Code
//     Pass1 svgCanvas.getStrokedBBox total ms     104, ave ms 1.0,     min/max 0 23
//     Pass2 svgCanvas.getStrokedBBox total ms        71, ave ms 0.7,     min/max 0 23
 
// Safari
// Before Optimization
//     Pass1 svgCanvas.getStrokedBBox total ms 4,840, ave ms 47.0,     min/max 45 62
//     Pass2 svgCanvas.getStrokedBBox total ms 4,849, ave ms 47.1,     min/max 34 62
// Optimized Code
//     Pass1 svgCanvas.getStrokedBBox total ms        42, ave ms 0.4,     min/max 0 23
//     Pass2 svgCanvas.getStrokedBBox total ms        17, ave ms 0.2,     min/max 0 23
 
QUnit.test('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function (assert) {
  const done = assert.async();
  assert.expect(2);
  const {getStrokedBBox} = utilities;
  const {children} = currentLayer;
 
  let lastTime, now,
    min = Number.MAX_VALUE,
    max = 0,
    total = 0;
 
  fillDocumentByCloningElement(groupWithMatrixTransform, 50);
  fillDocumentByCloningElement(textWithMatrixTransform, 50);
 
  // The first pass through all elements is slower.
  const count = children.length;
  const start = lastTime = now = Date.now();
  // Skip the first child which is the title.
  for (let index = 1; index < count; index++) {
    const child = children[index];
    /* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
    now = Date.now(); const delta = now - lastTime; lastTime = now;
    total += delta;
    min = Math.min(min, delta);
    max = Math.max(max, delta);
  }
  total = lastTime - start;
  const ave = total / count;
  assert.ok(ave < 20, 'svgedit.utilities.getStrokedBBox average execution time is less than 20 ms');
  console.log('Pass1 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max);
 
  // The second pass is two to ten times faster.
  setTimeout(function () {
    const count = children.length;
 
    const start = lastTime = now = Date.now();
    // Skip the first child which is the title.
    for (let index = 1; index < count; index++) {
      const child = children[index];
      /* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
      now = Date.now(); const delta = now - lastTime; lastTime = now;
      total += delta;
      min = Math.min(min, delta);
      max = Math.max(max, delta);
    }
 
    total = lastTime - start;
    const ave = total / count;
    assert.ok(ave < 2, 'svgedit.utilities.getStrokedBBox average execution time is less than 1 ms');
    console.log('Pass2 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max);
 
    done();
  });
});