1597043220

# JavaScript Problem Solvers: Rotate Image Matrix

It’s been a while since I’ve written a blog about a technical problem I’ve solved. The truth is I haven’t been grinding on HackerRank or LeetCode as much as I used to, and all of my time has been spent working on projects.

That changed this week. Today’s problem took me a long time to solve, longer than I’d like to admit, but provided a great opportunity to shake out the cobwebs and get back on that LeetCode grind. The solution I came up with meets the O(1) space complexity requirement, and runs in O(n * log n) time complexity (I think).

I’d also like to mention that I found CodeSignal recently, and I have been enjoying it so far. I only just started their Interview Practice track, but the UI is a step up from LeetCode/HackerRank, their feature sets and test cases are solid, and the amount of information given for each problem has been good. Check it out if you need a change of scenery.

So, let’s get solving.

## THE PROBLEM

Here is a link to the problem on Code Signal

``````You are given an n x n 2D matrix that represents an image. Rotate the image by 90 degrees (clockwise).

Note: Try to solve this task in-place (with O(1) additional memory), since this is what you’ll be asked to do during an interview.
Constraints:
1 ≤ a.length ≤ 100
a[i].length = a.length
1 ≤ a[i][j] ≤ 104
Input/Output:
[execution time limit] 4 seconds (js)
[input] array.array.integer a
[output] array.array.integer
``````

## THE TESTS

``````Test #1
Input:
[[1]]

Output:
[[1]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #2
Input:
[[1,2,3],
[4,5,6],
[7,8,9]]

Output:
[[7,4,1],
[8,5,2],
[9,6,3]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #3
Input:
[[6,3,1,7],
[8,2,4,5],
[1,6,2,9],
[5,7,3,4]]

Output:
[[5,1,8,6],
[7,6,2,3],
[3,2,4,1],
[4,9,5,7]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #4
Input:
[[10,9,6,3,7],
[6,10,2,9,7],
[7,6,3,8,2],
[8,9,7,9,9],
[6,8,6,8,2]]

Output:
[[6,8,7,6,10],
[8,9,6,10,9],
[6,7,3,2,6],
[8,9,8,9,3],
[2,9,2,7,7]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #5
Input:
[[40,12,15,37,33,11,45,13,25,3],
[37,35,15,43,23,12,22,29,46,43],
[44,19,15,12,30,2,45,7,47,6],
[48,4,40,10,16,22,18,36,27,48],
[45,17,36,28,47,46,8,4,17,3],
[14,9,33,1,6,31,7,38,25,17],
[31,9,17,11,29,42,38,10,48,6],
[12,13,42,3,47,24,28,22,3,47],
[38,23,26,3,23,27,14,40,15,22],
[8,46,20,21,35,4,36,18,32,3]]

Output:
[[8,38,12,31,14,45,48,44,37,40],
[46,23,13,9,9,17,4,19,35,12],
[20,26,42,17,33,36,40,15,15,15],
[21,3,3,11,1,28,10,12,43,37],
[35,23,47,29,6,47,16,30,23,33],
[4,27,24,42,31,46,22,2,12,11],
[36,14,28,38,7,8,18,45,22,45],
[18,40,22,10,38,4,36,7,29,13],
[32,15,3,48,25,17,27,47,46,25],
[3,22,47,6,17,3,48,6,43,3]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``````

#austin-smith #programming #codesignal #rotate-image-matrix #javascript

1653123600

## EasyMDE - Markdown Editor

This repository is a fork of SimpleMDE, made by Sparksuite. Go to the dedicated section for more information.

A drop-in JavaScript text area replacement for writing beautiful and understandable Markdown. EasyMDE allows users who may be less experienced with Markdown to use familiar toolbar buttons and shortcuts.

In addition, the syntax is rendered while editing to clearly show the expected result. Headings are larger, emphasized words are italicized, links are underlined, etc.

EasyMDE also features both built-in auto saving and spell checking. The editor is entirely customizable, from theming to toolbar buttons and javascript hooks.

Try the demo

## Install EasyMDE

Via npm:

``````npm install easymde
``````

Via the UNPKG CDN:

``````<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">
<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
``````

Or jsDelivr:

``````<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css">
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
``````

## How to use

After installing and/or importing the module, you can load EasyMDE onto the first `textarea` element on the web page:

``````<textarea></textarea>
<script>
const easyMDE = new EasyMDE();
</script>
``````

Alternatively you can select a specific `textarea`, via JavaScript:

``````<textarea id="my-text-area"></textarea>
<script>
const easyMDE = new EasyMDE({element: document.getElementById('my-text-area')});
</script>
``````

### Editor functions

Use `easyMDE.value()` to get the content of the editor:

``````<script>
easyMDE.value();
</script>
``````

Use `easyMDE.value(val)` to set the content of the editor:

``````<script>
easyMDE.value('New input for **EasyMDE**');
</script>
``````

## Configuration

### Options list

• autoDownloadFontAwesome: If set to `true`, force downloads Font Awesome (used for icons). If set to `false`, prevents downloading. Defaults to `undefined`, which will intelligently check whether Font Awesome has already been included, then download accordingly.
• autofocus: If set to `true`, focuses the editor automatically. Defaults to `false`.
• autosave: Saves the text that's being written and will load it back in the future. It will forget the text when the form it's contained in is submitted.
• enabled: If set to `true`, saves the text automatically. Defaults to `false`.
• delay: Delay between saves, in milliseconds. Defaults to `10000` (10 seconds).
• submit_delay: Delay before assuming that submit of the form failed and saving the text, in milliseconds. Defaults to `autosave.delay` or `10000` (10 seconds).
• uniqueId: You must set a unique string identifier so that EasyMDE can autosave. Something that separates this from other instances of EasyMDE elsewhere on your website.
• timeFormat: Set DateTimeFormat. More information see DateTimeFormat instances. Default `locale: en-US, format: hour:minute`.
• text: Set text for autosave.
• autoRefresh: Useful, when initializing the editor in a hidden DOM node. If set to `{ delay: 300 }`, it will check every 300 ms if the editor is visible and if positive, call CodeMirror's `refresh()`.
• blockStyles: Customize how certain buttons that style blocks of text behave.
• bold: Can be set to `**` or `__`. Defaults to `**`.
• code: Can be set to ````` or `~~~`. Defaults to `````.
• italic: Can be set to `*` or `_`. Defaults to `*`.
• unorderedListStyle: can be `*`, `-` or `+`. Defaults to `*`.
• scrollbarStyle: Chooses a scrollbar implementation. The default is "native", showing native scrollbars. The core library also provides the "null" style, which completely hides the scrollbars. Addons can implement additional scrollbar models.
• element: The DOM element for the `textarea` element to use. Defaults to the first `textarea` element on the page.
• forceSync: If set to `true`, force text changes made in EasyMDE to be immediately stored in original text area. Defaults to `false`.
• hideIcons: An array of icon names to hide. Can be used to hide specific icons shown by default without completely customizing the toolbar.
• indentWithTabs: If set to `false`, indent using spaces instead of tabs. Defaults to `true`.
• initialValue: If set, will customize the initial value of the editor.
• previewImagesInEditor: - EasyMDE will show preview of images, `false` by default, preview for images will appear only for images on separate lines.
• imagesPreviewHandler: - A custom function for handling the preview of images. Takes the parsed string between the parantheses of the image markdown `![]( )` as argument and returns a string that serves as the `src` attribute of the `<img>` tag in the preview. Enables dynamic previewing of images in the frontend without having to upload them to a server, allows copy-pasting of images to the editor with preview.
• insertTexts: Customize how certain buttons that insert text behave. Takes an array with two elements. The first element will be the text inserted before the cursor or highlight, and the second element will be inserted after. For example, this is the default link value: `["[", "](http://)"]`.
• horizontalRule
• image
• table
• lineNumbers: If set to `true`, enables line numbers in the editor.
• lineWrapping: If set to `false`, disable line wrapping. Defaults to `true`.
• minHeight: Sets the minimum height for the composition area, before it starts auto-growing. Should be a string containing a valid CSS value like `"500px"`. Defaults to `"300px"`.
• maxHeight: Sets fixed height for the composition area. `minHeight` option will be ignored. Should be a string containing a valid CSS value like `"500px"`. Defaults to `undefined`.
• onToggleFullScreen: A function that gets called when the editor's full screen mode is toggled. The function will be passed a boolean as parameter, `true` when the editor is currently going into full screen mode, or `false`.
• parsingConfig: Adjust settings for parsing the Markdown during editing (not previewing).
• allowAtxHeaderWithoutSpace: If set to `true`, will render headers without a space after the `#`. Defaults to `false`.
• strikethrough: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`.
• underscoresBreakWords: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`.
• overlayMode: Pass a custom codemirror overlay mode to parse and style the Markdown during editing.
• mode: A codemirror mode object.
• combine: If set to `false`, will replace CSS classes returned by the default Markdown mode. Otherwise the classes returned by the custom mode will be combined with the classes returned by the default mode. Defaults to `true`.
• placeholder: If set, displays a custom placeholder message.
• previewClass: A string or array of strings that will be applied to the preview screen when activated. Defaults to `"editor-preview"`.
• previewRender: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
• promptURLs: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`.
• promptTexts: Customize the text used to prompt for URLs.
• image: The text to use when prompting for an image's URL. Defaults to `URL of the image:`.
• link: The text to use when prompting for a link's URL. Defaults to `URL for the link:`.
• uploadImage: If set to `true`, enables the image upload functionality, which can be triggered by drag and drop, copy-paste and through the browse-file window (opened when the user click on the upload-image icon). Defaults to `false`.
• imageMaxSize: Maximum image size in bytes, checked before upload (note: never trust client, always check the image size at server-side). Defaults to `1024 * 1024 * 2` (2 MB).
• imageAccept: A comma-separated list of mime-types used to check image type before upload (note: never trust client, always check file types at server-side). Defaults to `image/png, image/jpeg`.
• imageUploadFunction: A custom function for handling the image upload. Using this function will render the options `imageMaxSize`, `imageAccept`, `imageUploadEndpoint` and `imageCSRFToken` ineffective.
• The function gets a file and `onSuccess` and `onError` callback functions as parameters. `onSuccess(imageUrl: string)` and `onError(errorMessage: string)`
• imageUploadEndpoint: The endpoint where the images data will be sent, via an asynchronous POST request. The server is supposed to save this image, and return a JSON response.
• if the request was successfully processed (HTTP 200 OK): `{"data": {"filePath": "<filePath>"}}` where filePath is the path of the image (absolute if `imagePathAbsolute` is set to true, relative if otherwise);
• otherwise: `{"error": "<errorCode>"}`, where errorCode can be `noFileGiven` (HTTP 400 Bad Request), `typeNotAllowed` (HTTP 415 Unsupported Media Type), `fileTooLarge` (HTTP 413 Payload Too Large) or `importError` (see errorMessages below). If errorCode is not one of the errorMessages, it is alerted unchanged to the user. This allows for server-side error messages. No default value.
• imagePathAbsolute: If set to `true`, will treat `imageUrl` from `imageUploadFunction` and filePath returned from `imageUploadEndpoint` as an absolute rather than relative path, i.e. not prepend `window.location.origin` to it.
• imageCSRFToken: CSRF token to include with AJAX call to upload image. For various instances like Django, Spring and Laravel.
• imageCSRFName: CSRF token filed name to include with AJAX call to upload image, applied when `imageCSRFToken` has value, defaults to `csrfmiddlewaretoken`.
• imageCSRFHeader: If set to `true`, passing CSRF token via header. Defaults to `false`, which pass CSRF through request body.
• imageTexts: Texts displayed to the user (mainly on the status bar) for the import image feature, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
• sbInit: Status message displayed initially if `uploadImage` is set to `true`. Defaults to `Attach files by drag and dropping or pasting from clipboard.`.
• sbOnDragEnter: Status message displayed when the user drags a file to the text area. Defaults to `Drop image to upload it.`.
• sbOnDrop: Status message displayed when the user drops a file in the text area. Defaults to `Uploading images #images_names#`.
• sbProgress: Status message displayed to show uploading progress. Defaults to `Uploading #file_name#: #progress#%`.
• sbOnUploaded: Status message displayed when the image has been uploaded. Defaults to `Uploaded #image_name#`.
• sizeUnits: A comma-separated list of units used to display messages with human-readable file sizes. Defaults to `B, KB, MB` (example: `218 KB`). You can use `B,KB,MB` instead if you prefer without whitespaces (`218KB`).
• errorMessages: Errors displayed to the user, using the `errorCallback` option, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
• noFileGiven: The server did not receive any file from the user. Defaults to `You must select a file.`.
• typeNotAllowed: The user send a file type which doesn't match the `imageAccept` list, or the server returned this error code. Defaults to `This image type is not allowed.`.
• fileTooLarge: The size of the image being imported is bigger than the `imageMaxSize`, or if the server returned this error code. Defaults to `Image #image_name# is too big (#image_size#).\nMaximum file size is #image_max_size#.`.
• importError: An unexpected error occurred when uploading the image. Defaults to `Something went wrong when uploading the image #image_name#.`.
• errorCallback: A callback function used to define how to display an error message. Defaults to `(errorMessage) => alert(errorMessage)`.
• renderingConfig: Adjust settings for parsing the Markdown during previewing (not editing).
• codeSyntaxHighlighting: If set to `true`, will highlight using highlight.js. Defaults to `false`. To use this feature you must include highlight.js on your page or pass in using the `hljs` option. For example, include the script and the CSS files like:
`<script src="https://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>`
`<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">`
• hljs: An injectible instance of highlight.js. If you don't want to rely on the global namespace (`window.hljs`), you can provide an instance here. Defaults to `undefined`.
• markedOptions: Set the internal Markdown renderer's options. Other `renderingConfig` options will take precedence.
• singleLineBreaks: If set to `false`, disable parsing GitHub Flavored Markdown (GFM) single line breaks. Defaults to `true`.
• sanitizerFunction: Custom function for sanitizing the HTML output of Markdown renderer.
• shortcuts: Keyboard shortcuts associated with this instance. Defaults to the array of shortcuts.
• showIcons: An array of icon names to show. Can be used to show specific icons hidden by default without completely customizing the toolbar.
• spellChecker: If set to `false`, disable the spell checker. Defaults to `true`. Optionally pass a CodeMirrorSpellChecker-compliant function.
• inputStyle: `textarea` or `contenteditable`. Defaults to `textarea` for desktop and `contenteditable` for mobile. `contenteditable` option is necessary to enable nativeSpellcheck.
• nativeSpellcheck: If set to `false`, disable native spell checker. Defaults to `true`.
• sideBySideFullscreen: If set to `false`, allows side-by-side editing without going into fullscreen. Defaults to `true`.
• status: If set to `false`, hide the status bar. Defaults to the array of built-in status bar items.
• Optionally, you can set an array of status bar items to include, and in what order. You can even define your own custom status bar items.
• styleSelectedText: If set to `false`, remove the `CodeMirror-selectedtext` class from selected lines. Defaults to `true`.
• syncSideBySidePreviewScroll: If set to `false`, disable syncing scroll in side by side mode. Defaults to `true`.
• tabSize: If set, customize the tab size. Defaults to `2`.
• theme: Override the theme. Defaults to `easymde`.
• toolbar: If set to `false`, hide the toolbar. Defaults to the array of icons.
• toolbarTips: If set to `false`, disable toolbar button tips. Defaults to `true`.
• direction: `rtl` or `ltr`. Changes text direction to support right-to-left languages. Defaults to `ltr`.

### Options example

Most options demonstrate the non-default behavior:

``````const editor = new EasyMDE({
autofocus: true,
autosave: {
enabled: true,
uniqueId: "MyUniqueID",
delay: 1000,
submit_delay: 5000,
timeFormat: {
locale: 'en-US',
format: {
year: 'numeric',
month: 'long',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
},
},
text: "Autosaved: "
},
blockStyles: {
bold: "__",
italic: "_",
},
unorderedListStyle: "-",
element: document.getElementById("MyID"),
forceSync: true,
indentWithTabs: false,
initialValue: "Hello world!",
insertTexts: {
horizontalRule: ["", "\n\n-----\n\n"],
image: ["![](http://", ")"],
table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text     | Text      | Text     |\n\n"],
},
lineWrapping: false,
minHeight: "500px",
parsingConfig: {
strikethrough: false,
underscoresBreakWords: true,
},
placeholder: "Type here...",

previewClass: "my-custom-styling",
previewClass: ["my-custom-styling", "more-custom-styling"],

previewRender: (plainText) => customMarkdownParser(plainText), // Returns HTML from a custom parser
previewRender: (plainText, preview) => { // Async method
setTimeout(() => {
preview.innerHTML = customMarkdownParser(plainText);
}, 250);

},
promptURLs: true,
promptTexts: {
image: "Custom prompt for URL:",
link: "Custom prompt for URL:",
},
renderingConfig: {
singleLineBreaks: false,
codeSyntaxHighlighting: true,
sanitizerFunction: (renderedHTML) => {
// Using DOMPurify and only allowing <b> tags
return DOMPurify.sanitize(renderedHTML, {ALLOWED_TAGS: ['b']})
},
},
shortcuts: {
drawTable: "Cmd-Alt-T"
},
showIcons: ["code", "table"],
spellChecker: false,
status: false,
status: ["autosave", "lines", "words", "cursor"], // Optional usage
status: ["autosave", "lines", "words", "cursor", {
className: "keystrokes",
defaultValue: (el) => {
el.setAttribute('data-keystrokes', 0);
},
onUpdate: (el) => {
const keystrokes = Number(el.getAttribute('data-keystrokes')) + 1;
el.innerHTML = `\${keystrokes} Keystrokes`;
el.setAttribute('data-keystrokes', keystrokes);
},
}], // Another optional usage, with a custom status bar item that counts keystrokes
styleSelectedText: false,
sideBySideFullscreen: false,
syncSideBySidePreviewScroll: false,
tabSize: 4,
toolbar: false,
toolbarTips: false,
});
``````

### Toolbar icons

Below are the built-in toolbar icons (only some of which are enabled by default), which can be reorganized however you like. "Name" is the name of the icon, referenced in the JavaScript. "Action" is either a function or a URL to open. "Class" is the class given to the icon. "Tooltip" is the small tooltip that appears via the `title=""` attribute. Note that shortcut hints are added automatically and reflect the specified action if it has a key bind assigned to it (i.e. with the value of `action` set to `bold` and that of `tooltip` set to `Bold`, the final text the user will see would be "Bold (Ctrl-B)").

Additionally, you can add a separator between any icons by adding `"|"` to the toolbar array.

### Toolbar customization

Customize the toolbar using the `toolbar` option.

Only the order of existing buttons:

``````const easyMDE = new EasyMDE({
toolbar: ["bold", "italic", "heading", "|", "quote"]
});
``````

All information and/or add your own icons

``````const easyMDE = new EasyMDE({
toolbar: [
{
name: "bold",
action: EasyMDE.toggleBold,
className: "fa fa-bold",
title: "Bold",
},
"italics", // shortcut to pre-made button
{
name: "custom",
action: (editor) => {
},
className: "fa fa-star",
title: "Custom Button",
attributes: { // for custom attributes
id: "custom-id",
"data-value": "custom value" // HTML5 data-* attributes need to be enclosed in quotation marks ("") because of the dash (-) in its name.
}
},
"|" // Separator
// [, ...]
]
});
``````

Put some buttons on dropdown menu

``````const easyMDE = new EasyMDE({
toolbar: [{
},
"|",
{
name: "others",
className: "fa fa-blind",
title: "others buttons",
children: [
{
name: "image",
action: EasyMDE.drawImage,
className: "fa fa-picture-o",
title: "Image",
},
{
name: "quote",
action: EasyMDE.toggleBlockquote,
className: "fa fa-percent",
title: "Quote",
},
{
}
]
},
// [, ...]
]
});
``````

### Keyboard shortcuts

EasyMDE comes with an array of predefined keyboard shortcuts, but they can be altered with a configuration option. The list of default ones is as follows:

Here is how you can change a few, while leaving others untouched:

``````const editor = new EasyMDE({
shortcuts: {
"toggleOrderedList": "Ctrl-Alt-K", // alter the shortcut for toggleOrderedList
"toggleCodeBlock": null, // unbind Ctrl-Alt-C
"drawTable": "Cmd-Alt-T", // bind Cmd-Alt-T to drawTable action, which doesn't come with a default shortcut
}
});
``````

Shortcuts are automatically converted between platforms. If you define a shortcut as "Cmd-B", on PC that shortcut will be changed to "Ctrl-B". Conversely, a shortcut defined as "Ctrl-B" will become "Cmd-B" for Mac users.

The list of actions that can be bound is the same as the list of built-in actions available for toolbar buttons.

### Event handling

You can catch the following list of events: https://codemirror.net/doc/manual.html#events

``````const easyMDE = new EasyMDE();
easyMDE.codemirror.on("change", () => {
console.log(easyMDE.value());
});
``````

### Removing EasyMDE from text area

You can revert to the initial text area by calling the `toTextArea` method. Note that this clears up the autosave (if enabled) associated with it. The text area will retain any text from the destroyed EasyMDE instance.

``````const easyMDE = new EasyMDE();
// ...
easyMDE.toTextArea();
easyMDE = null;
``````

If you need to remove registered event listeners (when the editor is not needed anymore), call `easyMDE.cleanup()`.

### Useful methods

The following self-explanatory methods may be of use while developing with EasyMDE.

``````const easyMDE = new EasyMDE();
easyMDE.isPreviewActive(); // returns boolean
easyMDE.isSideBySideActive(); // returns boolean
easyMDE.isFullscreenActive(); // returns boolean
easyMDE.clearAutosavedValue(); // no returned value
``````

## How it works

EasyMDE is a continuation of SimpleMDE.

SimpleMDE began as an improvement of lepture's Editor project, but has now taken on an identity of its own. It is bundled with CodeMirror and depends on Font Awesome.

CodeMirror is the backbone of the project and parses much of the Markdown syntax as it's being written. This allows us to add styles to the Markdown that's being written. Additionally, a toolbar and status bar have been added to the top and bottom, respectively. Previews are rendered by Marked using GitHub Flavored Markdown (GFM).

## SimpleMDE fork

I originally made this fork to implement FontAwesome 5 compatibility into SimpleMDE. When that was done I submitted a pull request, which has not been accepted yet. This, and the project being inactive since May 2017, triggered me to make more changes and try to put new life into the project.

Changes include:

• FontAwesome 5 compatibility
• Guide button works when editor is in preview mode
• Links are now `https://` by default
• Small styling changes
• Support for Node 8 and beyond
• Lots of refactored code
• Links in preview will open in a new tab by default
• TypeScript support

My intention is to continue development on this project, improving it and keeping it alive.

## Hacking EasyMDE

You may want to edit this library to adapt its behavior to your needs. This can be done in some quick steps:

1. Follow the prerequisites and installation instructions in the contribution guide;
2. Do your changes;
3. Run `gulp` command, which will generate files: `dist/easymde.min.css` and `dist/easymde.min.js`;
4. Copy-paste those files to your code base, and you are done.

## Contributing

Want to contribute to EasyMDE? Thank you! We have a contribution guide just for you!

Author: Ionaru
Source Code: https://github.com/Ionaru/easy-markdown-editor

1679035563

## How to Add Splash Screen in Android and iOS with Flutter

When your app is opened, there is a brief time while the native app loads Flutter. By default, during this time, the native app displays a white splash screen. This package automatically generates iOS, Android, and Web-native code for customizing this native splash screen background color and splash image. Supports dark mode, full screen, and platform-specific options.

## What's New

[BETA] Support for flavors is in beta. Currently only Android and iOS are supported. See instructions below.

You can now keep the splash screen up while your app initializes! No need for a secondary splash screen anymore. Just use the `preserve` and `remove` methods together to remove the splash screen after your initialization is complete. See details below.

## Usage

Would you prefer a video tutorial instead? Check out Johannes Milke's tutorial.

First, add `flutter_native_splash` as a dependency in your pubspec.yaml file.

``````dependencies:
flutter_native_splash: ^2.2.19
``````

Don't forget to `flutter pub get`.

### 1. Setting the splash screen

Customize the following settings and add to your project's `pubspec.yaml` file or place in a new file in your root project folder named `flutter_native_splash.yaml`.

``````flutter_native_splash:
# This package generates native code to customize Flutter's default white native splash screen
# with background color and splash image.
# Customize the parameters below, and run the following command in the terminal:
# flutter pub run flutter_native_splash:create
# To restore Flutter's default white splash screen, run the following command in the terminal:
# flutter pub run flutter_native_splash:remove

# color or background_image is the only required parameter.  Use color to set the background
# of your splash screen to a solid color.  Use background_image to set the background of your
# splash screen to a png image.  This is useful for gradients. The image will be stretch to the
# size of the app. Only one parameter can be used, color and background_image cannot both be set.
color: "#42a5f5"
#background_image: "assets/background.png"

# Optional parameters are listed below.  To enable a parameter, uncomment the line by removing
# the leading # character.

# The image parameter allows you to specify an image used in the splash screen.  It must be a
# png file and should be sized for 4x pixel density.
#image: assets/splash.png

# The branding property allows you to specify an image used as branding in the splash screen.
# It must be a png file. It is supported for Android, iOS and the Web.  For Android 12,
# see the Android 12 section below.
#branding: assets/dart.png

# To position the branding image at the bottom of the screen you can use bottom, bottomRight,
# and bottomLeft. The default values is bottom if not specified or specified something else.
#branding_mode: bottom

# The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background
# and image when the device is in dark mode. If they are not specified, the app will use the
# parameters from above. If the image_dark parameter is specified, color_dark or
# background_image_dark must be specified.  color_dark and background_image_dark cannot both be
# set.
#color_dark: "#042a49"
#background_image_dark: "assets/dark-background.png"
#image_dark: assets/splash-invert.png
#branding_dark: assets/dart_dark.png

# Android 12 handles the splash screen differently than previous versions.  Please visit
# https://developer.android.com/guide/topics/ui/splash-screen
# Following are Android 12 specific parameter.
android_12:
# The image parameter sets the splash screen icon image.  If this parameter is not specified,
# the app's launcher icon will be used instead.
# Please note that the splash screen will be clipped to a circle on the center of the screen.
# App icon with an icon background: This should be 960×960 pixels, and fit within a circle
# 640 pixels in diameter.
# App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle
# 768 pixels in diameter.
#image: assets/android12splash.png

# Splash screen background color.
#color: "#42a5f5"

# App icon background color.
#icon_background_color: "#111111"

# The branding property allows you to specify an image used as branding in the splash screen.
#branding: assets/dart.png

# The image_dark, color_dark, icon_background_color_dark, and branding_dark set values that
# apply when the device is in dark mode. If they are not specified, the app will use the
# parameters from above.
#image_dark: assets/android12splash-invert.png
#color_dark: "#042a49"
#icon_background_color_dark: "#eeeeee"

# The android, ios and web parameters can be used to disable generating a splash screen on a given
# platform.
#android: false
#ios: false
#web: false

# Platform specific images can be specified with the following parameters, which will override
# the respective parameter.  You may specify all, selected, or none of these parameters:
#color_android: "#42a5f5"
#color_dark_android: "#042a49"
#color_ios: "#42a5f5"
#color_dark_ios: "#042a49"
#color_web: "#42a5f5"
#color_dark_web: "#042a49"
#image_android: assets/splash-android.png
#image_dark_android: assets/splash-invert-android.png
#image_ios: assets/splash-ios.png
#image_dark_ios: assets/splash-invert-ios.png
#image_web: assets/splash-web.png
#image_dark_web: assets/splash-invert-web.png
#background_image_android: "assets/background-android.png"
#background_image_dark_android: "assets/dark-background-android.png"
#background_image_ios: "assets/background-ios.png"
#background_image_dark_ios: "assets/dark-background-ios.png"
#background_image_web: "assets/background-web.png"
#background_image_dark_web: "assets/dark-background-web.png"
#branding_android: assets/brand-android.png
#branding_dark_android: assets/dart_dark-android.png
#branding_ios: assets/brand-ios.png
#branding_dark_ios: assets/dart_dark-ios.png

# The position of the splash image can be set with android_gravity, ios_content_mode, and
# web_image_mode parameters.  All default to center.
#
# android_gravity can be one of the following Android Gravity (see
# https://developer.android.com/reference/android/view/Gravity): bottom, center,
# center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal,
# fill_vertical, left, right, start, or top.
#android_gravity: center
#
# ios_content_mode can be one of the following iOS UIView.ContentMode (see
# https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill,
# scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight,
# bottomLeft, or bottomRight.
#ios_content_mode: center
#
# web_image_mode can be one of the following modes: center, contain, stretch, and cover.
#web_image_mode: center

# The screen orientation can be set in Android with the android_screen_orientation parameter.
# Valid parameters can be found here:
# https://developer.android.com/guide/topics/manifest/activity-element#screen
#android_screen_orientation: sensorLandscape

# To hide the notification bar, use the fullscreen parameter.  Has no effect in web since web
# has no notification bar.  Defaults to false.
# NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads.
#       To show the notification bar, add the following code to your Flutter app:
#       WidgetsFlutterBinding.ensureInitialized();
#       SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]);
#fullscreen: true

# If you have changed the name(s) of your info.plist file(s), you can specify the filename(s)
# with the info_plist_files parameter.  Remove only the # characters in the three lines below,
# do not remove any spaces:
#info_plist_files:
#  - 'ios/Runner/Info-Debug.plist'
#  - 'ios/Runner/Info-Release.plist'
``````

### 2. Run the package

After adding your settings, run the following command in the terminal:

``````flutter pub run flutter_native_splash:create
``````

When the package finishes running, your splash screen is ready.

To specify the YAML file location just add --path with the command in the terminal:

``````flutter pub run flutter_native_splash:create --path=path/to/my/file.yaml
``````

### 3. Set up app initialization (optional)

By default, the splash screen will be removed when Flutter has drawn the first frame. If you would like the splash screen to remain while your app initializes, you can use the `preserve()` and `remove()` methods together. Pass the `preserve()` method the value returned from `WidgetsFlutterBinding.ensureInitialized()` to keep the splash on screen. Later, when your app has initialized, make a call to `remove()` to remove the splash screen.

``````import 'package:flutter_native_splash/flutter_native_splash.dart';

void main() {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
runApp(const MyApp());
}

// whenever your initialization is completed, remove the splash screen:
FlutterNativeSplash.remove();
``````

NOTE: If you do not need to use the `preserve()` and `remove()` methods, you can place the `flutter_native_splash` dependency in the `dev_dependencies` section of `pubspec.yaml`.

### 4. Support the package (optional)

If you find this package useful, you can support it for free by giving it a thumbs up at the top of this page. Here's another option to support the package:

## Android 12+ Support

Android 12 has a new method of adding splash screens, which consists of a window background, icon, and the icon background. Note that a background image is not supported.

Be aware of the following considerations regarding these elements:

1: `image` parameter. By default, the launcher icon is used:

• App icon without an icon background, as shown on the left: This should be 1152×1152 pixels, and fit within a circle 768 pixels in diameter.
• App icon with an icon background, as shown on the right: This should be 960×960 pixels, and fit within a circle 640 pixels in diameter.

2: `icon_background_color` is optional, and is useful if you need more contrast between the icon and the window background.

3: One-third of the foreground is masked.

4: `color` the window background consists of a single opaque color.

PLEASE NOTE: The splash screen may not appear when you launch the app from Android Studio on API 31. However, it should appear when you launch by clicking on the launch icon in Android. This seems to be resolved in API 32+.

PLEASE NOTE: There are a number of reports that non-Google launchers do not display the launch image correctly. If the launch image does not display correctly, please try the Google launcher to confirm that this package is working.

PLEASE NOTE: The splash screen does not appear when you launch the app from a notification. Apparently this is the intended behavior on Android 12: core-splashscreen Icon not shown when cold launched from notification.

## Flavor Support

If you have a project setup that contains multiple flavors or environments, and you created more than one flavor this would be a feature for you.

Instead of maintaining multiple files and copy/pasting images, you can now, using this tool, create different splash screens for different environments.

### Pre-requirements

In order to use the new feature, and generate the desired splash images for you app, a couple of changes are required.

If you want to generate just one flavor and one file you would use either options as described in Step 1. But in order to setup the flavors, you will then be required to move all your setup values to the `flutter_native_splash.yaml` file, but with a prefix.

Let's assume for the rest of the setup that you have 3 different flavors, `Production`, `Acceptance`, `Development`.

First this you will need to do is to create a different setup file for all 3 flavors with a suffix like so:

``````flutter_native_splash-production.yaml
flutter_native_splash-acceptance.yaml
flutter_native_splash-development.yaml
``````

You would setup those 3 files the same way as you would the one, but with different assets depending on which environment you would be generating. For example (Note: these are just examples, you can use whatever setup you need for your project that is already supported by the package):

``````# flutter_native_splash-development.yaml
flutter_native_splash:
color: "#ffffff"
image: assets/logo-development.png
branding: assets/branding-development.png
color_dark: "#121212"
image_dark: assets/logo-development.png
branding_dark: assets/branding-development.png

android_12:
image: assets/logo-development.png
icon_background_color: "#ffffff"
image_dark: assets/logo-development.png
icon_background_color_dark: "#121212"

web: false

# flutter_native_splash-acceptance.yaml
flutter_native_splash:
color: "#ffffff"
image: assets/logo-acceptance.png
branding: assets/branding-acceptance.png
color_dark: "#121212"
image_dark: assets/logo-acceptance.png
branding_dark: assets/branding-acceptance.png

android_12:
image: assets/logo-acceptance.png
icon_background_color: "#ffffff"
image_dark: assets/logo-acceptance.png
icon_background_color_dark: "#121212"

web: false

# flutter_native_splash-production.yaml
flutter_native_splash:
color: "#ffffff"
image: assets/logo-production.png
branding: assets/branding-production.png
color_dark: "#121212"
image_dark: assets/logo-production.png
branding_dark: assets/branding-production.png

android_12:
image: assets/logo-production.png
icon_background_color: "#ffffff"
image_dark: assets/logo-production.png
icon_background_color_dark: "#121212"

web: false
``````

Great, now comes the fun part running the new command!

The new command is:

``````# If you have a flavor called production you would do this:
flutter pub run flutter_native_splash:create --flavor production

# For a flavor with a name staging you would provide it's name like so:
flutter pub run flutter_native_splash:create --flavor staging

# And if you have a local version for devs you could do that:
flutter pub run flutter_native_splash:create --flavor development
``````

### Android setup

You're done! No, really, Android doesn't need any additional setup.

Note: If it didn't work, please make sure that your flavors are named the same as your config files, otherwise the setup will not work.

### iOS setup

iOS is a bit tricky, so hang tight, it might look scary but most of the steps are just a single click, explained as much as possible to lower the possibility of mistakes.

When you run the new command, you will need to open xCode and follow the steps bellow:

Assumption

• In order for this setup to work, you would already have 3 different `schemes` setup; production, acceptance and development.

Preparation

• Open the iOS Flutter project in Xcode (open the Runner.xcworkspace)
• Find the newly created Storyboard files at the same location where the original is `{project root}/ios/Runner/Base.lproj`
• Select all of them and drag and drop into Xcode, directly to the left hand side where the current LaunchScreen.storyboard is located already
• After you drop your files there Xcode will ask you to link them, make sure you select 'Copy if needed'
• This part is done, you have linked the newly created storyboards in your project.

xCode

Xcode still doesn't know how to use them, so we need to specify for all the current flavors (schemes) which file to use and to use that value inside the Info.plist file.

• Open the iOS Flutter project in Xcode (open the Runner.xcworkspace)
• Click the Runner project in the top left corner (usually the first item in the list)
• In the middle part of the screen, on the left side, select the Runner target
• On the top part of the screen select Build Settings
• Make sure that 'All' and 'Combined' are selected
• Next to 'Combine' you have a '+' button, press it and select 'Add User-Defined Setting'
• Once you do that Xcode will create a new variable for you to name. Suggestion is to name it `LAUNCH_SCREEN_STORYBOARD`
• Once you do that, you will have the option to define a specific name for each flavor (scheme) that you have defined in the project. Make sure that you input the exact name of the LaunchScreen.storyboard that was created by this tool
• Example: If you have a flavor Development, there is a Storyboard created name LaunchScreenDevelopment.storyboard, please add that name (without the storyboard part) to the variable value next to the flavor value
• After you finish with that, you need to update Info.plist file to link the newly created variable so that it's used correctly
• Open the Info.plist file
• Find the entry called 'Launch screen interface file base name'
• The default value is 'LaunchScreen', change that to the variable name that you create previously. If you follow these steps exactly, it would be LAUNCH_SCREEN_STORYBOARD, so input this `\$(LAUNCH_SCREEN_STORYBOARD)`
• And your done!

Congrats you finished your setup for multiple flavors,

## FAQs

### I got the error "A splash screen was provided to Flutter, but this is deprecated."

This message is not related to this package but is related to a change in how Flutter handles splash screens in Flutter 2.5. It is caused by having the following code in your `android/app/src/main/AndroidManifest.xml`, which was included by default in previous versions of Flutter:

``````<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
``````

The solution is to remove the above code. Note that this will also remove the fade effect between the native splash screen and your app.

### Are animations/lottie/GIF images supported?

Not at this time. PRs are always welcome!

### I got the error AAPT: error: style attribute 'android:attr/windowSplashScreenBackground' not found

This attribute is only found in Android 12, so if you are getting this error, it means your project is not fully set up for Android 12. Did you update your app's build configuration?

## I see a flash of the wrong splash screen on iOS

This is caused by an iOS splash caching bug, which can be solved by uninstalling your app, powering off your device, power back on, and then try reinstalling.

## I see a white screen between splash screen and app

1. It may be caused by an iOS splash caching bug, which can be solved by uninstalling your app, powering off your device, power back on, and then try reinstalling.
2. It may be caused by the delay due to initialization in your app. To solve this, put any initialization code in the `removeAfter` method.

### Can I base light/dark mode on app settings?

No. This package creates a splash screen that is displayed before Flutter is loaded. Because of this, when the splash screen loads, internal app settings are not available to the splash screen. Unfortunately, this means that it is impossible to control light/dark settings of the splash from app settings.

Notes

If the splash screen was not updated correctly on iOS or if you experience a white screen before the splash screen, run `flutter clean` and recompile your app. If that does not solve the problem, delete your app, power down the device, power up the device, install and launch the app as per this StackOverflow thread.

This package modifies `launch_background.xml` and `styles.xml` files on Android, `LaunchScreen.storyboard` and `Info.plist` on iOS, and `index.html` on Web. If you have modified these files manually, this plugin may not work properly. Please open an issue if you find any bugs.

## How it works

### Android

• Your splash image will be resized to `mdpi`, `hdpi`, `xhdpi`, `xxhdpi` and `xxxhdpi` drawables.
• An `<item>` tag containing a `<bitmap>` for your splash image drawable will be added in `launch_background.xml`
• Background color will be added in `colors.xml` and referenced in `launch_background.xml`.
• Code for full screen mode toggle will be added in `styles.xml`.
• Dark mode variants are placed in `drawable-night`, `values-night`, etc. resource folders.

### iOS

• Your splash image will be resized to `@3x` and `@2x` images.
• Color and image properties will be inserted in `LaunchScreen.storyboard`.
• The background color is implemented by using a single-pixel png file and stretching it to fit the screen.
• Code for hidden status bar toggle will be added in `Info.plist`.

### Web

• A `web/splash` folder will be created for splash screen images and CSS files.
• Your splash image will be resized to `1x`, `2x`, `3x`, and `4x` sizes and placed in `web/splash/img`.
• The splash style sheet will be added to the app's `web/index.html`, as well as the HTML for the splash pictures.

## Acknowledgments

This package was originally created by Henrique Arthur and it is currently maintained by Jon Hanson.

## Bugs or Requests

If you encounter any problems feel free to open an issue. If you feel the library is missing a feature, please raise a ticket. Pull request are also welcome.

## Use this package as a library

### Depend on it

Run this command:

With Flutter:

`` \$ flutter pub add flutter_native_splash``

This will add a line like this to your package's pubspec.yaml (and run an implicit `flutter pub get`):

``````dependencies:
flutter_native_splash: ^2.2.19``````

Alternatively, your editor might support `flutter pub get`. Check the docs for your editor to learn more.

### Import it

Now in your Dart code, you can use:

``import 'package:flutter_native_splash/flutter_native_splash.dart';``

## example/lib/main.dart

``````import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';

void main() {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});

// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.

// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".

final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;

void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}

@override
void initState() {
super.initState();
initialization();
}

void initialization() async {
// This is where you can initialize the resources needed by your app while
// the splash screen is displayed.  Remove the following example because
// delaying the user experience is a bad design practice!
// ignore_for_file: avoid_print
await Future.delayed(const Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1));
print('go!');
FlutterNativeSplash.remove();
}

@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'\$_counter',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
``````

Author: jonbhanson
Official Website: https://github.com/jonbhanson/flutter_native_splash

1597043220

## JavaScript Problem Solvers: Rotate Image Matrix

It’s been a while since I’ve written a blog about a technical problem I’ve solved. The truth is I haven’t been grinding on HackerRank or LeetCode as much as I used to, and all of my time has been spent working on projects.

That changed this week. Today’s problem took me a long time to solve, longer than I’d like to admit, but provided a great opportunity to shake out the cobwebs and get back on that LeetCode grind. The solution I came up with meets the O(1) space complexity requirement, and runs in O(n * log n) time complexity (I think).

I’d also like to mention that I found CodeSignal recently, and I have been enjoying it so far. I only just started their Interview Practice track, but the UI is a step up from LeetCode/HackerRank, their feature sets and test cases are solid, and the amount of information given for each problem has been good. Check it out if you need a change of scenery.

So, let’s get solving.

## THE PROBLEM

Here is a link to the problem on Code Signal

``````You are given an n x n 2D matrix that represents an image. Rotate the image by 90 degrees (clockwise).

Note: Try to solve this task in-place (with O(1) additional memory), since this is what you’ll be asked to do during an interview.
Constraints:
1 ≤ a.length ≤ 100
a[i].length = a.length
1 ≤ a[i][j] ≤ 104
Input/Output:
[execution time limit] 4 seconds (js)
[input] array.array.integer a
[output] array.array.integer
``````

## THE TESTS

``````Test #1
Input:
[[1]]

Output:
[[1]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #2
Input:
[[1,2,3],
[4,5,6],
[7,8,9]]

Output:
[[7,4,1],
[8,5,2],
[9,6,3]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #3
Input:
[[6,3,1,7],
[8,2,4,5],
[1,6,2,9],
[5,7,3,4]]

Output:
[[5,1,8,6],
[7,6,2,3],
[3,2,4,1],
[4,9,5,7]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #4
Input:
[[10,9,6,3,7],
[6,10,2,9,7],
[7,6,3,8,2],
[8,9,7,9,9],
[6,8,6,8,2]]

Output:
[[6,8,7,6,10],
[8,9,6,10,9],
[6,7,3,2,6],
[8,9,8,9,3],
[2,9,2,7,7]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test #5
Input:
[[40,12,15,37,33,11,45,13,25,3],
[37,35,15,43,23,12,22,29,46,43],
[44,19,15,12,30,2,45,7,47,6],
[48,4,40,10,16,22,18,36,27,48],
[45,17,36,28,47,46,8,4,17,3],
[14,9,33,1,6,31,7,38,25,17],
[31,9,17,11,29,42,38,10,48,6],
[12,13,42,3,47,24,28,22,3,47],
[38,23,26,3,23,27,14,40,15,22],
[8,46,20,21,35,4,36,18,32,3]]

Output:
[[8,38,12,31,14,45,48,44,37,40],
[46,23,13,9,9,17,4,19,35,12],
[20,26,42,17,33,36,40,15,15,15],
[21,3,3,11,1,28,10,12,43,37],
[35,23,47,29,6,47,16,30,23,33],
[4,27,24,42,31,46,22,2,12,11],
[36,14,28,38,7,8,18,45,22,45],
[18,40,22,10,38,4,36,7,29,13],
[32,15,3,48,25,17,27,47,46,25],
[3,22,47,6,17,3,48,6,43,3]]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``````

#austin-smith #programming #codesignal #rotate-image-matrix #javascript

1671141060

## How to Image Cropping, Zooming, and Scaling with Angular & JavaScript

When building a web application there is a good chance you’re going to need to work with images eventually, even if it is something as simple as allowing a user to upload a profile image. In theory this is a simple task, but in reality, your website theme is probably anticipating images of a certain resolution or aspect ratio. If the user tries to upload an image that doesn’t meet your requirements, it might break your theme.

We’re going to see how to include image manipulation capabilities in your Angular application using the popular cropperjs JavaScript package.

To get an idea of what we’re going to accomplish, take a look at the following animated image:

In the above animation you’ll notice a source image which has a crop box. Altering the crop box will affect the image preview to the right of the source image. This image preview is an entirely new image that represents our manipulations and it can be downloaded as such.

## Create a New Angular Project for the Web

Before getting too involved with this tutorial, the assumption is that you’ve got the Angular CLI installed and configured. For context, I’m using Angular 8.0.2 in this example. If you’re using an older or newer version, things may vary slightly.

From the CLI, execute the following:

``````ng new image-cropper-example
``````

The above command will start the project creation process. When prompted, choose the defaults as we won’t be doing anything particularly fancy when it comes to Angular.

After the project has been created, navigate into the project and execute the following:

``````npm install cropperjs --save
``````

The above command will install our cropperjs JavaScript dependency. As a fun fact, jQuery is not a requirement for this example.

Installing the `cropperjs` package will only install the JavaScript side of things. We’ll still need the CSS for visualizing our image manipulation box within the source image.

Open the project’s src/index.html file and include the following:

``````<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Image Cropping Project</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<body>
<app-root></app-root>
</body>
</html>
``````

The only change made was in the cropper.min.css file that is now included. You can use it as part of the CDN or download it to be included directly within your project.

Before we get into the core code, let’s create a component to hold our image manipulation code:

``````ng g component ImageCropper
``````

The above command will create appropriate TypeScript, HTML, and CSS files for our new component. You’ll see how each of these are used in the next step.

## Manipulate Images with Simple JavaScript in the Browser

We’re going to do most of our development in the new component that we had just created, but before we do that, you might want to find an image to use. For this example, the image should be placed in the project’s src/assets directory.

Open the project’s src/app/image-cropper/image-cropper.component.css file and include the following CSS:

``````.img-container {
width: 640px;
height: 480px;
float: left;
}

.img-preview {
width: 200px;
height: 200px;
float: left;
margin-left: 10px;
}
``````

The above CSS is not critical to the success of our project, but it makes it a little more attractive to look at. Essentially we are defining the source canvas size and the destination image size.

Now open the project’s src/app/image-cropper/image-cropper.component.html file where we can add the markup for our component:

``````<div class="img-container">
<img #image [src]="imageSource" crossorigin>
</div>
<img [src]="imageDestination" class="img-preview">
``````

We’re getting a little ahead of ourselves here, but we have two `<img>` components, one for our source image and one for our destination image. Each component has a `src` variable that we’ll define later in our TypeScript. Notice that the source image has an `#image` attribute on it. This is a reference variable that we’ll use within the TypeScript, giving us access to the DOM element. Remember, we can’t just use query selectors in Angular like we can vanilla JavaScript.

With the component HTML out of the way, open the project’s src/app/image-cropper/image-cropper.component.ts file where we’ll do a bulk of the work:

``````import { Component, OnInit, ViewChild, Input, ElementRef } from '@angular/core';
import Cropper from "cropperjs";

@Component({
selector: 'image-cropper',
templateUrl: './image-croppper.component.html',
styleUrls: ['./image-croppper.component.css']
})
export class ImageCroppperComponent implements OnInit {

@ViewChild("image", { static: false })
public imageElement: ElementRef;

@Input("src")
public imageSource: string;

public imageDestination: string;
private cropper: Cropper;

public constructor() {
this.imageDestination = "";
}

public ngAfterViewInit() {
this.cropper = new Cropper(this.imageElement.nativeElement, {
zoomable: false,
scalable: false,
aspectRatio: 1,
crop: () => {
const canvas = this.cropper.getCroppedCanvas();
this.imageDestination = canvas.toDataURL("image/png");
}
});
}

public ngOnInit() { }

}
``````

The above code is complete, but we’re going to break it down to explain what is happening. It isn’t much, but it is still good to know.

At the top we are importing the `cropperjs` package that we had previously downloaded and installed.

Remember that `#image` reference from the HTML file? We’re accessing it through the `@ViewChild` and mapping it to a variable to be used within our TypeScript code. The `@Input` is referring to a possible attribute called `src` which we’ll see later.

Because we’re working with elements in the view, we need to wait until the view has initialized before we make any attempts. To do this we can make use of the `ngAfterViewInit` method. Inside the `ngAfterViewInit` method we initialize our `Cropper` using the entire `imageElement` that we obtained from the HTML. During the initialization process we can define a few options. There are quite a few to choose from, but for us, we’re going to disable zooming and scaling of our image. In other words we’re only going to allow moving and cropping. We’re also going to define a crop box with a square aspect ratio. None of these are required options. The important option is the `crop` method, one of many possible event methods. The `crop` method is triggered every time something happens to the crop box. This is important to us because we want to constantly update our preview image.

The preview image is created by getting the cropped canvas and exporting it to an image.

At this point in time our component is done, but not yet being used. To use it, open the project’s src/app/app.component.html file and include the following:

``````<image-cropper src="assets/angular.png"></image-cropper>
``````

Notice that we’re using `image-cropper` which is the `selector` value from the project’s src/app/image-cropper/image-cropper.component.ts file. We’re also using `src` which was the `@Input` that we defined in that same TypeScript file. The `src` should reference an image within our src/assets directory.

## Conclusion

You just saw how to add image manipulation functionality to your Angular web applications through the cropperjs package. If you’d like to upload these altered images, you might want to check out my previous tutorial titled, Upload Files to Node.js using Angular.

A video version of this tutorial can be found below.

Original article source at: https://www.thepolyglotdeveloper.com/

1675716120

## How to Drag and Drop File Upload with HTML CSS JavaScript

In this article you will know how to create Drag and Drop File Upload using HTML CSS and JavaScript. Earlier I have shared many more types of Drag and Drop elements and File Upload and Preview section. This is basically a drag and drop multiple file upload that I made with javascript.

Now it’s time to create JavaScript Drag and Drop File Upload. Here I have created the basic structure by html. I designed it with css and activated this Drag & Drop or Browse – File upload with javascript.

## Drag And Drop File Upload Javascript

Drag and drop file upload in JavaScript refers to the ability to select one or more files using the drag and drop gesture, and then upload those files to a server.

This feature is typically implemented using JavaScript event listeners, such as “dragover” and “drop,” that detect when a file is being dragged over a specific element on the page and when the file is dropped onto that element. Within this project () you can upload the image by selecting it and you can also upload it by drag and drop. Also here you can upload multiple images.

As you can see above this is a simple javascript drag and drop file upload project. Here I have created a small area or box. Inside that box is a button. You can select the image by clicking on that button or you can drag and drop the image into the box. Then the uploaded image can be seen in the preview box below.

## How To Make A Drag and Drop File Uploader With JavaScript

Now if you want to build(How To Make A Drag-and-Drop File Uploader With javascript) this project then follow the step by step tutorial below. Here I have given you the necessary explanation and source code. A bit more JavaScript is used here. But there is no reason to worry. I have explained each code step by step and tried to explain you completely why I used that line of code.

Besides, I have given a preview after each step. Which will help you to know what kind of result will be seen after using that code.

### Step 1: Basic Structure of Drag and Drop File Uploader

I have created the basic structure of this Drag and drop multiple file upload using the following html and css. All the information of that box can be seen. I used white for the background color of the box and some shadows around it.

``````<div class="container">

</div>``````
``````* {
margin: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
background-color: #a4b7e3;
}
.container {
background-color: #ffffff;
width: 60%;
min-width: 27.5em;
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
top: 50%;
box-shadow: 0 1.25em 3.43em rgba(0, 0, 0, 0.08);
}``````

### Step 2: Create a file upload button

Now an input button is created to upload the file. I have created this button using HTML’s input function. For uploading image only I used accept=”image/*” which basically will help to upload image file only.

``````<input type="file" id="upload-button" multiple accept="image/*" />
<i class="fa-solid fa-upload"></i>&nbsp; Choose Or Drop Photos
</label>``````
``````input[type="file"] {
display: none;
}
label {
display: block;
position: relative;
background-color: #025bee;
color: #ffffff;
font-size: 1.1em;
text-align: center;
width: 16em;
margin: 0 auto 1em auto;
cursor: pointer;
}``````

### Step 3: Create a place to preview the image

Now an area is created, in which the images can be viewed i.e. image preview area is created. How images are displayed is determined by css.

``````<div id="error"></div>
<div id="image-display"></div>``````
``````#image-display {
position: relative;
width: 90%;
margin: 0 auto;
display: flex;
justify-content: space-evenly;
gap: 1.25em;
flex-wrap: wrap;
}
#image-display figure {
width: 45%;
}
#image-display img {
width: 100%;
}
#image-display figcaption {
font-size: 0.8em;
text-align: center;
color: #5a5861;
}``````
``````.active {
border: 0.2em dashed #025bee;
}
#error {
text-align: center;
color: #ff3030;
}``````

### Step 4: Enable the drag and drop multiple files uploader

Now it’s time to implement this drag and drop multiple file uploader using javascript. Here I have given the necessary explanation, hope you will not have any difficulty in understanding.

These lines of code are assigning variables to different elements on a webpage by their ID to active Drag And Drop File Uploader in javascript. The variables are:

• `uploadButton` is assigned to the element with the ID “upload-button”
• `chosenImage` is assigned to the element with the ID “chosen-image”
• `fileName` is assigned to the element with the ID “file-name”
• `container` is assigned to the first element with the class “container”
• `error` is assigned to the element with the ID “error”
• `imageDisplay` is assigned to the element with the ID “image-display”

It appears that these variables will be used to manipulate these elements and their properties in later JavaScript code.

``````let uploadButton = document.getElementById("upload-button");
let chosenImage = document.getElementById("chosen-image");
let fileName = document.getElementById("file-name");
let container = document.querySelector(".container");
let error = document.getElementById("error");
let imageDisplay = document.getElementById("image-display");``````

This code defines a function `fileHandler()` that takes in three parameters: `file`, `name`, and `type`. The function checks if the file is of type image by checking the first part of the type string before “/” if it is not of type image it sets the innerText of the error element to “Please upload an image file” and returns false.

If the file is an image, it sets the innerText of the error element to an empty string and creates a new FileReader object, which reads the contents of the file as a Data URL.

When the file has been read, the `onloadend` event is triggered, at this point it creates an `imageContainer` element and an `img` element, sets the source of the `img` element to the result of the file reader, appends the `img` element to the `imageContainer` element, and then appends a `figcaption` element containing the file name to the `imageContainer` element. Finally, it appends the `imageContainer` element to the `imageDisplay` element.

``````const fileHandler = (file, name, type) => {
if (type.split("/")[0] !== "image") {
//File Type Error
error.innerText = "Please upload an image file";
return false;
}
error.innerText = "";
//image and file name
let imageContainer = document.createElement("figure");
let img = document.createElement("img");
imageContainer.appendChild(img);
imageContainer.innerHTML += `<figcaption>\${name}</figcaption>`;
imageDisplay.appendChild(imageContainer);
};
};``````

Now Drag and Drop File Upload project upload button should be activated. This code attaches an event listener to the `uploadButton` element that listens for a “change” event. When the event is fired, the function inside the event listener is executed. The function clears the content of the `imageDisplay` element by setting its innerHTML to an empty string.

Then it creates an array of the files from the `uploadButton` element, and for each file in that array, it calls the `fileHandler()` function and passes in the `file`, the `file.name`, and the `file.type` as the arguments.

This code is used to handle the event of a user selecting and uploading one or more image files, displaying each image file and its name on the page by calling the `fileHandler` function for each file.

``````//Upload Button
imageDisplay.innerHTML = "";
fileHandler(file, file.name, file.type);
});
});``````

Now you need to define what happens when you drag the file into the Simple javascript Drag and Drop File Upload box. This code attaches an event listener to the `container` element that listens for a “dragenter” event. When the event is fired, the function inside the event listener is executed. The function calls `preventDefault()` and `stopPropagation()` on the event object (`e`) to prevent the default browser behavior and stop the event from propagating.

Then it adds a class “active” to the `container` element’s classList. This code is probably used to handle the event of a user dragging an item over the `container` element, indicating that the container is a valid drop target.

The class “active” is added to the container which can be used to style it and give visual feedback that the container is active and ready to accept the dragged item.

``````container.addEventListener(
"dragenter",
(e) => {
e.preventDefault();
e.stopPropagation();
},
false
);``````

Now you need to determine what happens if you drag leave within the HTML drag drop upload area. This code attaches an event listener to the `container` element that listens for a “dragleave” event. When the event is fired, the function inside the event listener is executed. The function calls `preventDefault()` and `stopPropagation()` on the event object (`e`) to prevent the default browser behavior and stop the event from propagating.

Then it removes the class “active” from the `container` element’s classList. This code is probably used to handle the event of a user dragging an item out of the `container` element, indicating that the container is no longer a valid drop target.

The class “active” is removed from the container, it can be used to style it and give visual feedback that the container is no longer active and no longer ready to accept the dragged item.

``````container.addEventListener(
"dragleave",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.remove("active");
},
false
);``````

Upload files with Drag and Drop to determine what happens when dragover. This code attaches an event listener to the `container` element that listens for a “dragover” event. When the event is fired, the function inside the event listener is executed. The function calls `preventDefault()` and `stopPropagation()` on the event object (`e`) to prevent the default browser behavior and stop the event from propagating.

``````container.addEventListener(
"dragover",
(e) => {
e.preventDefault();
e.stopPropagation();
},
false
);``````

This code attaches an event listener to the `container` element that listens for a “drop” event. When the event is fired, the function inside the event listener is executed. The function calls `preventDefault()` and `stopPropagation()` on the event object (`e`) to prevent the default browser behavior and stop the event from propagating.

Then it removes the class “active” from the `container` element’s classList. It then creates a variable `draggedData` which holds the dataTransfer object of the event, which contains the data that was dropped onto the element. It then creates a variable `files` which holds the file object from the `draggedData` object. It clears the content of the `imageDisplay` element by setting its innerHTML to an empty string.

Then it creates an array of the files and for each file in that array, it calls the `fileHandler()` function and passes in the `file`, the `file.name`, and the `file.type` as the arguments. This code is used to handle the event of a user dropping one or more files on to the `container` element, which then calls the `fileHandler` function to display the image and its name on the page.

``````container.addEventListener(
"drop",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.remove("active");
let draggedData = e.dataTransfer;
let files = draggedData.files;
imageDisplay.innerHTML = "";
Array.from(files).forEach((file) => {
fileHandler(file, file.name, file.type);
});
},
false
);``````

Now it is determined that every time the page is loaded all the information contained in the Drag and Drop File Upload with HTML CSS JavaScript will be removed. This code assigns an anonymous function to the `onload` property of the `window` object, which is fired when the page has finished loading. The function sets the `innerText` of the `error` element to an empty string, effectively clearing any pre-existing text.

``````window.onload = () => {
error.innerText = "";
};``````

Hope you got to know from above tutorial how I created this project(Drag and Drop File Upload Using HTML,CSS & JavaScript). I have already shared many more JavaScript tutorials with you.

Be sure to comment how you liked this Drag and Drop File Upload JavaScript tutorial.

Original article source at: https://foolishdeveloper.com/