Results show

function

Github code address



The project address is separate for the functions in the artboard. If you want to know a function, you can directly open the corresponding file to view the effect.

How do I set the canvas background

So the first thing we’re going to think about is

  • Set the CSS background color directly to the Canvas element.
  • Use Fill/fillRect to fill the palette.

Canvas sets the CSS background

There are some limitations to this approach

  1. When we use fillRect on the artboard, we can no longer change the color through CSS.
    • The canvas itself is transparent and the background color can be set by CSS. When a color layer is added to the canvas, the original background color cannot be seen.
  2. Our CSS can not use partial printing effect. Similar to the following image

Canvas use fillRect

With these limitations with CSS, we use canvas to draw a real background layer.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(0.0.150.100);
Copy the code

The code above can indeed be filled with the corresponding color on the canvas.

Question 1

But if you have something already drawn on your artboard, if you use fillRect it overwrites what you drew before. This is because the CanvasRenderingContext2D. GlobalCompositeOperation default is the source – over

  • Source-over needs to set and shape new shapes on top of the existing canvas content
  • Destination-over is interpreted as: New shapes are drawn behind the existing canvas content

The background we draw should be behind the existing layer. So we can be set to CTX. GlobalCompositeOperation = ‘destination – over’

Updates to both backgrounds are shown below. Source-overs are overlays of the already drawn content. Destination-over is drawn after.

Question 2

Using the above method, it is really possible to draw a background layer behind the existing content. But what happens when we want to change the background color again?

When we update the background again, we draw it after the existing content, so we can’t see what we drew.

The solution

First, let’s look at an API

The CanvasRenderingContext2D.drawImage() method of the Canvas 2D API provides different ways to draw an image onto the canvas.

  • Images include HTMLImageElement, HTMLCanvasElement, SVGImageElement, HTMLVideoElement, etc.

So we use two canvas to change the background. They divide their work, one as the content layer and one as the background layer. Use the background layer CanvasRenderingContext2D. DrawImage () will render content layer on the background layer.

Artboard imports images for editing

How to import and draw a local image onto the artboard

The FileRender API is used to read local image files through the FileReader.

The FileReader object allows a Web application to asynchronously read the contents of a File (or raw data buffer) stored on the user’s computer, using a File or Blob object to specify which File or data to read.

The File object can be a FileList object returned by the user after selecting a File on an <input> element, or a DataTransfer object generated by a drag-and-drop operation.

  1. Use FileReader to read the address of the blob file to base64,
  2. Get the address in the load event and assign it to the IMG element to get an IMG object. (Here you can define the width and height operation of the picture)
  3. Once we have the image we can use drawImage to draw the image to the canvas.
/** * Read the input element to select the file into Base64 address, Img element * @param blob File object * @param width specifies the image width */ export function blobToImg (blob: blob) {return new Promise((resolve, reject) => { let reader = new FileReader() reader.addEventListener('load', () => { let img = new Image() img.src = reader.result as string img.addEventListener('load', () => { resolve(img) } ) }) reader.readAsDataURL(blob) }) }Copy the code

Drag and stretch the image

Operating box

The action box is used to determine what action to take.

  • Stretch in all directions as you land in eight small rectangles in different directions.
  • Move when falling on the picture

Use new Path2D() to create controller enclosure paths (rectangular and corner controller enclosures) and store these paths. Then use ctx.isPointinPath (x,y) to check whether the current point is in the correct frame.

Moving pictures

DrawImage (img,x,y,w,h) is used to draw the local image to the canvas. All we need to think about when we move the picture is the x and y positions. W and H do not need to be changed, so when we move the mousemove event will listen for the coordinate position change value and then redraw the image to the new coordinate.

Drawing pictures

Stretching in eight directions is considered a little differently. For example,

  • The only thing we need to think about when we stretch the top rightw,hThe transformation. Because the starting position doesn’t change.
  • When I stretch the upper left corner,x,y,w,hThere will be transformations.
  • .

In general, stretching is to change the values of X, Y, W and H, and then re-render the image according to these values.

Text input effect

Simulation of the cursor

Analog cursor is the process of drawing a cursor-like rectangle at the mouse click point and then making the rectangle disappear -> appear -> disappear. Let’s look at two apis.

CanvasRenderingContext2D. GetImageData () returns a ImageData object, used to describe the canvas area implied pixel data, this area through the rectangles represent, the starting point for sw for (sx, sy), wide, high for sh.

CanvasRenderingContext2D. PutImageData () is a 2 d Canvas API data from existing ImageData draws a bitmap object. If a drawn rectangle is provided, only the pixels of that rectangle are drawn. This method is not affected by the canvas transformation matrix.

  1. Use getImageData to store all pixels on the current artboard. (This is equivalent to saving a snapshot of the current canvas).
  2. Draw cursor rectangle
  3. Use putImageData to apply the previously saved snapshot to the canvas. (Equivalent to returning to the screen of step 1)
  4. Repeat steps 2,3. Realize cursor flashing effect.

Wrap text

CanvasRenderingContext2D.fillText(text, x, y [, maxWidth]);
Copy the code

FillText draws text to a specified position, but does not wrap. There’s another thing you need to know if you want to implement line wrapping.

SVG forginObject elements wrap with text

Using the foreignObject tag in SVG allows you to embed XHTML elements directly inside SVG. When the specified width is exceeded, the XHML element itself is wrapped.

<svg xmlns="http://www.w3.org/2000/svg"> <foreignObject width="120" height="50"> <body xmlns="http://www.w3.org/1999/xhtml"> <p style="font-size:12px; margin:0;" Word-wrap: break-word! Important; </p> </body> </foreignObject> </svg>Copy the code

The SVG forginObject element generates images

  1. Concatenate HTML tags into the body:<svg xmlns="http://www.w3.org/2000/svg"><body><p style="width:100px"></p></body><foreignObject><body></body></foreignObject></svg>In the format.
  2. Create an IMG element assign the address of step 1 to the IMG element.
  3. Use drawImage to position the image on the canvas
  4. You can use it if you want to save the imagecanvas.toDataURL()orcanvas.toBlob()Export the image again.

Canvas input text wraps automatically.

export async function autoWrapText(width:number,height:number,value:string,font="16px sans-serif") :Promise<HTMLImageElement>{
  const { fontColor } = store.state
 // The color used here cannot be hex, as in #000
  const path = 'data:image/svg+xml; charset=utf-8,
      + width +'" height="'+ height +'">+ font +'; word-break: break-word; color:'+fontColor+'" >'+value+'</body></foreignObject></svg>';
  return  await loadImgSize(path,width,height)
}
Copy the code
function loadImgSize(path:string,width:number,height:number) :Promise<HTMLImageElement> {
  return new Promise(res= >{
    const img = new Image()
    img.width = width 
    img.height = height
    img.onload = function () {
      res(img)
    }
    img.src = path
  })
}
Copy the code
  1. Listen for keyboard events to determine the current input or function keys (if you want to do special functions).
  2. Record the current mouse position in mousedown, and calculate the distance from the right side of the Canvas board as remain variable. Set the width of the SVG foreignObject tag to Remain.
  3. Create the IMG tag. Concatenate the addressdata:image/svg+xml...format
  4. Draw img to canvas using drawImage.

Front-end image compression before uploading

Benefits of front-end compression

  • Due to the small size of the uploaded image, the upload speed is fast and the interaction is smooth. In addition, the risk of upload failure caused by network exceptions is greatly reduced.
  • The most important experience improvement: the cost of reprocessing images is omitted.

process

Image(local selection or path) -> canvas compression (using ctx.drawimage (img,0,0,w,h)) -> image (using canvas.todataurl (), canvas.toblob ()) to re-export the image.

Use ctx.drawImage to specify w,h is scaled back to canvas, and the image is exported for compression.

More functions viewLot code

reference

SVG introduction and screenshots and other applications MDN