Skip to main content
Commonmark migration
Source Link

##Performance

Performance

##Style

Style

##Code

Code

##The rewrite.

The rewrite.

##Performance

##Style

##Code

##The rewrite.

Performance

Style

Code

The rewrite.

added 103 characters in body
Source Link
Blindman67
  • 22.3k
  • 2
  • 16
  • 40
  • Use const for constants. Eg canvas and ctx should be const.
  • Capitals only for names of objects that are instantiated with the new token. Eg GenerateRand should be generateRand
  • Avoid repeated code by using functions. Eg you create many instances of an object {x,y}, would be better as a function.
  • Spaces between operators, commas, etc.
  • Use === rather than ==
  • else on the same line as the closing }
  • TeThe final statement in function begin does not need the test `(randN == 5 || randN == 6)`` (randN == 5 || randN == 6) (assuming you want a new point each iteration)
const ctx = canvas.getContext('2d');


const padding = 5;
const renderDelay = 200;
const maxTime = 2;  // time in ms allowed to render points.
const maxPointsToDraw = canvas.width * canvas.height * (1 / 3); 
const pointCountTune = 1.2; // factor to change point count by.

var pointsPerRender = 500; // points to render per render pass
var totalPoints = 0; // count of total points drawn
ctx.fillStyle = '#fc3';

const generateRand = () => Math.random() * 3 | 0;
const point = (x, y) => ({x, y});
const drawDot = p => ctx.rect(p.x, p.y, 1, 1);

const updateDot = (p, p1) => {
    p.x = p.x < p1.x ? p.x + (p1.x - p.x) / 2 : p1.x + (p.x - p1.x) / 2;
    p.y = p.y < p1.y ? p.y + (p1.y - p.y) / 2 : p1.y + (p.y - p1.y) / 2;
    return p;
}

const points = [
    point(canvas.width / 2, padding),
    point(padding, canvas.height - padding),
    point(canvas.width - padding, canvas.height - padding)
];
const wPoint = point(canvas.width / 4, canvas.height / 2); // working point


const renderPoints = iterations => {
    totalPoints += iterations;
    
    const now = performance.now(); 
    ctx.beginPath();
    while (iterations --) { drawDot(updateDot(wPoint, points[generateRand()])) }
    ctx.fill();
    const time = performance.now() - now;

    // use render time to tune number points to draw 
    if// (Calculates approx time >per maxTime)point {and then calcs number of points
    // to render next pointsPerRendertime *=based 1on /that pointCountTune;speed.
    }// elseNote ifthat (security issues mean time <is maxTime)rounded {to much higher
    // value than 0.001 pointsPerRenderms *=so pointCountTune;must test for 0 incase time is zero
    }pointsPerRender = maxTime / ((time ? time : 0.1)/ pointsPerRender);

    if (totalPoints < maxPointsToDraw) {
        setTimeout(renderPoints, renderDelay, pointsPerRender | 0);
    }
}
renderPoints(pointsPerRender);
<canvas id="canvas" width="500" height="500"></canvas>
  • Use const for constants. Eg canvas and ctx should be const.
  • Capitals only for names of objects that are instantiated with the new token. Eg GenerateRand should be generateRand
  • Avoid repeated code by using functions. Eg you create many instances of an object {x,y}, would be better as a function.
  • Spaces between operators, commas, etc.
  • Use === rather than ==
  • else on the same line as the closing }
  • Te final statement in function begin does not need the test `(randN == 5 || randN == 6)`` (assuming you want a new point each iteration)
const ctx = canvas.getContext('2d');


const padding = 5;
const renderDelay = 200;
const maxTime = 2;  // time in ms allowed to render points.
const maxPointsToDraw = canvas.width * canvas.height * (1 / 3); 
const pointCountTune = 1.2; // factor to change point count by.

var pointsPerRender = 500; // points to render per render pass
var totalPoints = 0; // count of total points drawn
ctx.fillStyle = '#fc3';

const generateRand = () => Math.random() * 3 | 0;
const point = (x, y) => ({x, y});
const drawDot = p => ctx.rect(p.x, p.y, 1, 1);

const updateDot = (p, p1) => {
    p.x = p.x < p1.x ? p.x + (p1.x - p.x) / 2 : p1.x + (p.x - p1.x) / 2;
    p.y = p.y < p1.y ? p.y + (p1.y - p.y) / 2 : p1.y + (p.y - p1.y) / 2;
    return p;
}

const points = [
    point(canvas.width / 2, padding),
    point(padding, canvas.height - padding),
    point(canvas.width - padding, canvas.height - padding)
];
const wPoint = point(canvas.width / 4, canvas.height / 2); // working point


const renderPoints = iterations => {
    totalPoints += iterations;
    
    const now = performance.now(); 
    ctx.beginPath();
    while (iterations --) { drawDot(updateDot(wPoint, points[generateRand()])) }
    ctx.fill();
    const time = performance.now() - now;

    // use render time to tune number points to draw 
    if (time > maxTime) {
        pointsPerRender *= 1 / pointCountTune;
    } else if (time < maxTime) {
        pointsPerRender *= pointCountTune;
    }

    if (totalPoints < maxPointsToDraw) {
        setTimeout(renderPoints, renderDelay, pointsPerRender | 0);
    }
}
renderPoints(pointsPerRender);
<canvas id="canvas" width="500" height="500"></canvas>
  • Use const for constants. Eg canvas and ctx should be const.
  • Capitals only for names of objects that are instantiated with the new token. Eg GenerateRand should be generateRand
  • Avoid repeated code by using functions. Eg you create many instances of an object {x,y}, would be better as a function.
  • Spaces between operators, commas, etc.
  • Use === rather than ==
  • else on the same line as the closing }
  • The final statement in function begin does not need the test (randN == 5 || randN == 6) (assuming you want a new point each iteration)
const ctx = canvas.getContext('2d');


const padding = 5;
const renderDelay = 200;
const maxTime = 2;  // time in ms allowed to render points.
const maxPointsToDraw = canvas.width * canvas.height * (1 / 3); 

var pointsPerRender = 500; // points to render per render pass
var totalPoints = 0; // count of total points drawn
ctx.fillStyle = '#fc3';

const generateRand = () => Math.random() * 3 | 0;
const point = (x, y) => ({x, y});
const drawDot = p => ctx.rect(p.x, p.y, 1, 1);

const updateDot = (p, p1) => {
    p.x = p.x < p1.x ? p.x + (p1.x - p.x) / 2 : p1.x + (p.x - p1.x) / 2;
    p.y = p.y < p1.y ? p.y + (p1.y - p.y) / 2 : p1.y + (p.y - p1.y) / 2;
    return p;
}

const points = [
    point(canvas.width / 2, padding),
    point(padding, canvas.height - padding),
    point(canvas.width - padding, canvas.height - padding)
];
const wPoint = point(canvas.width / 4, canvas.height / 2); // working point


const renderPoints = iterations => {
    totalPoints += iterations;
    
    const now = performance.now(); 
    ctx.beginPath();
    while (iterations --) { drawDot(updateDot(wPoint, points[generateRand()])) }
    ctx.fill();
    const time = performance.now() - now;

    // use render time to tune number points to draw 
    // Calculates approx time per point and then calcs number of points
    // to render next time based on that speed.
    // Note that security issues mean time is rounded to much higher
    // value than 0.001 ms so must test for 0 incase time is zero
    pointsPerRender = maxTime / ((time ? time : 0.1)/ pointsPerRender);

    if (totalPoints < maxPointsToDraw) {
        setTimeout(renderPoints, renderDelay, pointsPerRender | 0);
    }
}
renderPoints(pointsPerRender);
<canvas id="canvas" width="500" height="500"></canvas>
Source Link
Blindman67
  • 22.3k
  • 2
  • 16
  • 40

##Performance

  • For positive numbers < 2 ^ 31 use num | 0 (bitwise or zero) to floor
  • You are drawing an arc that is 1 pixel in radius, with the stroke width of 1 the diameter is 3 pixels. This covers an area much greater than the point you sample. Use fillRect to draw a single pixel as its much quicker. Better yet as they are all the same color create a single path and use ctx.rect to add to it. Render all rect in one pass at the end of begin function.
  • Avoid creating objects needlessly. Create a working object and use that to hold intermediate values. This can greatly reduce memory allocation and GC overheads. Eg the object you return in updateDot is a waste of memory and time.
  • If you test two numbers to find the max or min, knowing either means you also know the other and thus do not need to test for it. The long lines Math.min(p.y, p1.y) + (Math.max(p.y, p1.y) - Math.min(p.y, p1.y)) / 2 can be reduced by a single test and give significant performance improvement.

##Style

  • Use const for constants. Eg canvas and ctx should be const.
  • Capitals only for names of objects that are instantiated with the new token. Eg GenerateRand should be generateRand
  • Avoid repeated code by using functions. Eg you create many instances of an object {x,y}, would be better as a function.
  • Spaces between operators, commas, etc.
  • Use === rather than ==
  • else on the same line as the closing }
  • Te final statement in function begin does not need the test `(randN == 5 || randN == 6)`` (assuming you want a new point each iteration)

##Code

The random number generated is from 0 to 6 and you ignore 0, redrawing the same point 1 in 7 times. You can reduce the random to give 3 values 0,1,2 and perform the correct calculation on that or use a counter and cycle the points.

You could also put the points pA, pB, pC in an array and index them directly via the random number.

Rather than use setInterval, use setTimeout. That way you don't need to clear the timer each time.

Put magic numbers in one place and name them as constants.

You reset the start point each time delay is called (first two lines). Better to just let it keep going. It may also pay to stop the rendering after a fixed amount of points have been rendered.

##The rewrite.

This is just an example of the various points outlined above.

Also a few modifications

  • Automatically adjust number of points rendered to keep the GPU load steady.
  • Stop rendering after a fixed number of points rendered.
  • The starting points pA,pB,pC are in an array.
  • Magic numbers as constants.
  • Using a single render path to draw all points per render cycle.
  • Using a working point wPoint to hold coordinates rather than create a new point for each point rendered.

const ctx = canvas.getContext('2d');


const padding = 5;
const renderDelay = 200;
const maxTime = 2;  // time in ms allowed to render points.
const maxPointsToDraw = canvas.width * canvas.height * (1 / 3); 
const pointCountTune = 1.2; // factor to change point count by.

var pointsPerRender = 500; // points to render per render pass
var totalPoints = 0; // count of total points drawn
ctx.fillStyle = '#fc3';

const generateRand = () => Math.random() * 3 | 0;
const point = (x, y) => ({x, y});
const drawDot = p => ctx.rect(p.x, p.y, 1, 1);

const updateDot = (p, p1) => {
    p.x = p.x < p1.x ? p.x + (p1.x - p.x) / 2 : p1.x + (p.x - p1.x) / 2;
    p.y = p.y < p1.y ? p.y + (p1.y - p.y) / 2 : p1.y + (p.y - p1.y) / 2;
    return p;
}

const points = [
    point(canvas.width / 2, padding),
    point(padding, canvas.height - padding),
    point(canvas.width - padding, canvas.height - padding)
];
const wPoint = point(canvas.width / 4, canvas.height / 2); // working point


const renderPoints = iterations => {
    totalPoints += iterations;
    
    const now = performance.now(); 
    ctx.beginPath();
    while (iterations --) { drawDot(updateDot(wPoint, points[generateRand()])) }
    ctx.fill();
    const time = performance.now() - now;

    // use render time to tune number points to draw 
    if (time > maxTime) {
        pointsPerRender *= 1 / pointCountTune;
    } else if (time < maxTime) {
        pointsPerRender *= pointCountTune;
    }

    if (totalPoints < maxPointsToDraw) {
        setTimeout(renderPoints, renderDelay, pointsPerRender | 0);
    }
}
renderPoints(pointsPerRender);
<canvas id="canvas" width="500" height="500"></canvas>