MarvinKlein1508 / SignaturePad

A simple to use blazor component to draw custom signatures.
MIT License
72 stars 12 forks source link

Image as Background #20

Closed gle4711 closed 8 months ago

gle4711 commented 10 months ago

How can I set an image as background?

dblood2 commented 8 months ago

+1 for being able to set an image as background.

@MarvinKlein1508: I was considering giving this a shot myself, but wanted to be sure it's not something that's already being worked on. I don't see any open Pull Requests, so probably not. I have a use-case for background image for when my users perform a vehicle inspection. I load an image of the vehicle (a wireframe) and show top, left, right, back, etc. The user then marks their scratches and dings on the image.

How I'm using it would require the height and width to be variable which (on just a quick peek) I don't see in the component, but that should be easy enough to implement. Please let me know if it's something that you're already considering. If not, I'll be happy to share if I decide to attempt these additions. I've been using the Syncfusion control which is just awful and getting worse IMHO.

Well done - thanks, Danny

MarvinKlein1508 commented 8 months ago

Feel free to create a PR. I was not working on this since you can manipulate the entire component through it's CSS class.

Do you need the image on the generated signature as well?

dblood2 commented 8 months ago

Yes, for my use case, I need to save the background image along with the "signature" as base64. The image is resized and uploaded to AzureBlobStorage. It's displayed in a report later in the process.

I'll give it a try when I find time and let you know how I make out. My JScript is a bit rusty since making the move to Blazor, but I see how you've implemented background color. Is it okay if I throw a question out now and then?

My apologies to @gle4711 if it appears that I've highjacked your issue. We seem to have a common goal though.

MarvinKlein1508 commented 8 months ago

@dblood2 sure. I try to help if I can. I was never good at JavaScript as well. Blazor is my treasure :)

dblood2 commented 8 months ago

Spent a little time on this today and have it working - I think. I'll create a pull request so you can have a look. My only caveat (other than a professed lack of JavaScript prowess) is that I'm normally the only developer on my projects. I've been writing code since 1985 (high school), but rarely in an environment with multiple developers. The changes that I've made work for my use case. Don't feel obligated to include my code in the application if you find it unworthy or too specific.

A few thoughts: I found that both BackgroundColor and BackgroundImage didn't appear until the user clicked inside the SignaturePad (or clicked the Clear Signature button. I tried adding a call to programmatically clear the control in the constructor - didn't work. I tried a bunch of things that didn't work. Moving the code to set the src of the image (canvas) in the setImage function to after the call to img.onload() seemed to do the trick.

Then, I created a new function called setBackgroundImage which gets called in the constructor with an empty string as the parameter. Inside this new function is where the options "_config" is checked for a background image. I'm not sure that's the best way, but it works. If there's no BackgroundImage specified, setBackgroundImage does nothing. The reason I'm calling it only in the constructor is because it's just the base image (the starting point) for me. From there, setImage() is proper for both the background and the user's drawing.

I played around with CSS, trying to change the size of the canvas, but doing it that way changed the aspect ratio of the image (stretched it) and I got some strange results when drawing. The cursor didn't line up with where the lines were being drawn. Then, I realized that the canvas needed to be sized to the image dimensions using the height and width parameters of the canvas element (not style). That made everything work as intended. But, then it only truly worked after a refresh, meaning that the image didn't resize on the initial load of the page.

What I found was that the image wasn't finished loading. Without the image being fully loaded, I couldn't get the height and width to set the canvas. It's a little kludgy, but I found that calling location.reload() to refresh the page inside the initial call to setBackgroundImage (which only runs in the constructor) worked.

The only other thing worth mentioning, and I'm not sure how to get around it is that for my use case, I won't ever need a BackgroundColor. I use the SignaturePad blank (for actual signatures) and with a background image for the vehicle inspection. Because of this, I allowed BackgroundImage to trump BackgroundColor. I didn't spend a lot of time trying to figure out how to gracefully make the two work together, though I did try. In the end, I made it an either/or situation. If a BackgroundImage is specified, BackgroundColor does nothing - even if it's also specified. I know that's not great UX, but again I don't know what to do to make it better. It's perfectly possible to have both, but since the canvas gets sized to the background image, you'll never see the background color anyway if they both are specified in the options. Feel free to change the background image to something less specific. I used one of the images from my app.

And yes, I absolutely LOVE Blazor - mostly because I don't have to code any (much) JavaScript. Thanks again for the opportunity to pitch in. It's my first foray into contributing to an open source project.

MarvinKlein1508 commented 8 months ago

Spent a little time on this today and have it working - I think. I'll create a pull request so you can have a look.

Feel free to do so :)

I found that both BackgroundColor and BackgroundImage didn't appear until the user clicked inside the SignaturePad (or clicked the Clear Signature button.

I don't know your implementation but background color does work by default. In my code this is achieved in the setImage function:

if (this._config.backgroundColor != null && this._config.backgroundColor != "") {
    ctx.fillStyle = this._config.backgroundColor;
    ctx.fillRect(0, 0, this._element.width, this._element.height);
}

Thie results in this without doing anything more: grafik

It should be basically the same logic for images. In context of canvas it should be using the drawImage function. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

The only important part here is to check if a background color is specified since the image will overrite any background color. Think about it like layers in an image editing program.

I played around with CSS, trying to change the size of the canvas, but doing it that way changed the aspect ratio of the image (stretched it) and I got some strange results when drawing.

You can also specify the aspect-ration with css. Not sure though if this would help in your case.

I will provide a better way of defining the size for the element in a future update. Usually what I do is rely on my parent div's size because the signature pad is set to 100% by default and on mobile the size doesn't change really.

dblood2 commented 8 months ago

@MarvinKlein1508 - I was expecting to be able to create a pull request from within the issue, but the option doesn't exist. Do you create a new branch for the dev, or am I allowed to do that? Sorry, just don't want to mess anything up.

MarvinKlein1508 commented 8 months ago

You can create a PR from your forked branch

dblood2 commented 8 months ago

You can create a PR from your forked branch Understood - thank you.

I stupidly tried to run the WASM Demo, then found that I was missing a .Net version. I downloaded and installed the latest version, 7.0.13, and now I'm in hell trying to get the Blazor Server Demos to run.

I'll uninstall that .Net version tomorrow and start over. There's really not that many changes to the project, and based on your earlier post, my changes aren't going to be as global as I thought. Still, I want to get a legit pull request done - even if you don't include it.

I appreciate your patience and the help along the way. Old dogs and new tricks...story of my life.

MarvinKlein1508 commented 8 months ago

I'm in hell trying to get the Blazor Server Demos to run.

this sound to me that you are calling some JavaScript when you shouldn't.

dblood2 commented 8 months ago

It's a problem with one of the analyzer assemblies. Here's the error:

The analyzer assembly 'C:\Program Files\dotnet\sdk\7.0.403\Sdks\Microsoft.NET.Sdk.Razor\source-generators\Microsoft.NET.Sdk.Razor.SourceGenerators.dll' references version '4.7.0.0' of the compiler, which is newer than the currently running version '4.6.0.0'.

dblood2 commented 8 months ago

This happened immediately following the update to .Net Core. I'm assuming they are related since the WASM demos now run and the Server Demos don't. I'm going to delete my local repo - I hadn't pushed any changes yet - and just re-clone the forked project. If YOUR code doesn't run, it's got to be the new version of .Net that I installed.

MarvinKlein1508 commented 8 months ago

yes. You'll need both .NET 6 & .NET 7 installed. I've added the WebAssembly preview later on that's why it's on .NET 7.

I'm bringing all of them to .NEt 8 when it ships next month :)

dblood2 commented 8 months ago

Uninstalled .Net 7 and was able to run the Blazor Server Demo again.

I only added the BG Image Demo for the Blazor Server Tests project. I was able to create the pull request [#23]. Please let me know what you think.

MarvinKlein1508 commented 8 months ago

Done in V7.5.0