Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canvas size issue when html attribute and css style width & height differs. #184

Open
cdaein opened this issue Jun 10, 2022 · 4 comments
Open

Comments

@cdaein
Copy link

cdaein commented Jun 10, 2022

Hi,
I'm trying to use pts.js with canvas-sketch, which provides its own canvas and context.

When I use it with the CanvasForm object only, there is no problem.

But when I add CanvasSpace supplying the existing canvas, there is a canvas sizing issue.

I think this happens when <canvas> width & height html attribute is different from width & height css style value. canvas-sketch automatically resizes the canvas css w&h according to the current browser window size.

I haven't found a way to update pts.js code accordingly. If anyone has a suggestion, I'd appreciate it.

Here is my sample code to reproduce the problem:

const canvasSketch = require("canvas-sketch");
const { CanvasSpace, CanvasForm, Pt } = require("pts");

const sketch = ({ canvas, context: ctx }) => {
  const space = new CanvasSpace(canvas); // adding space object causes the issue
  const form = new CanvasForm(ctx);

  return {
    render({ width, height, playhead }) {
      ctx.fillStyle = "#aaa";
      ctx.fillRect(0, 0, width, height);

      const center = new Pt([width / 2, height / 2]);
      const diam = Math.sin(playhead * Math.PI * 2) * 100 + 200;
      form.strokeOnly("#ff0", 12).point(center, diam, "circle");
    },
  };
};

const settings = {
  dimensions: [1400, 1400], // try a big value to reproduce the problem
  animate: true,
  duration: 4,
};

canvasSketch(sketch, settings);
@williamngan
Copy link
Owner

Hi @cdaein - yes, the css styles and width/height attributes differ to support different pixel density screens automatically. Eg, if you're using a 2x retina screen, the canvas' actual size will be double of the width & height.

I'm not familiar with canvas-sketch, but here are a couple suggestions --

  1. If you already have the <canvas> set up via canvas-sketch, you may not need to create another CanvasSpace. You can pass the rendering context directly to CanvasForm, eg new CanvasForm( ctx )

  2. If you are looking for a way to generate high-quality prints, you can try node-pts-canvas. Note that this is experimental and may not work 100%.

Hope this helps!

@cdaein
Copy link
Author

cdaein commented Jun 11, 2022

Thank you for the response, @williamngan !
As you suggested, I am just using CanvasForm although I wish I can use convenience methods and properties that come with CanvasSpace. If only there is a way to modify my canvas to do that...

Also when using new CanvasForm(ctx), it seems that the gradient is not supported?
I was recreating one of your demos - CanvasForm.gradient, and the gradient does not work properly.

I get an error:

Uncaught TypeError: Cannot read properties of undefined (reading 'ctx')
    at get ctx [as ctx] (dist.js:3146:26)
    at dist.js:3209:33
    at dist.js:5283:13
    at dist.js:5288:3

Sample code below. This time, I am using pts-starter-kit and do not have any other dependency.

import { CanvasForm, Pt, Bound, Create, Circle } from "pts";

// prepare canvas
const canvas = document.createElement("canvas");
canvas.width = 600;
canvas.height = 600;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");

const form = new CanvasForm(ctx);

// recreate CanvasSpace properties for demonstration
const center = new Pt(canvas.width / 2, canvas.height / 2);
const size = new Pt(canvas.width, canvas.height);
const innerBound = new Bound(new Pt(), size);

// simulate mouse pointer
const pointer = new Pt(100, 100);

let scale = center.$subtract(pointer).divide(center).abs();
let bound = new Bound(new Pt(), size.$add(0, size.y * scale.y));
let cells = Create.gridCells(bound, 21, 30);
let offy = (bound.height - innerBound.height) / 2;
let cy = 1 - Math.abs(center.y - pointer.y) / center.y;

let radial = form.gradient([
  [0.2, `rgba(${70 * cy}, 0, ${255 * cy})`],
  [0.6, `rgba(${205 * cy}, 0, ${30 * cy})`],
  [0.95, `rgba(${255 * cy}, ${220 * cy}, 0)`],
]);

// radial gradient seems to have an issue with 'ctx'
form
  .fill(
    radial(
      Circle.fromCenter(pointer, center.y / 2),
      Circle.fromCenter(pointer, size.y * 1.5)
    )
  )
  .rect(innerBound);

for (let i = 0, len = cells.length; i < len; i++) {
  let grad = form.gradient(["rgba(255,255,255,1)", "rgba(255,255,255,0)"]);
  form
    .fillOnly(i % 2 === 0 ? grad(cells[i]) : "rgba(0,0,0,0)")
    .rect(cells[i].subtract(0, offy));
}

@williamngan
Copy link
Owner

Thanks for the report! I will take a look soon.

This is a common enough use case, so maybe we should create a CustomCanvasSpace or something similar for this type of use case.

@cdaein
Copy link
Author

cdaein commented Jun 14, 2022

Thank you for looking into this.
the gradient issue is now fixed with 0.10.12 as mentioned in the other issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants