r/graphic_design - Software for layouting catalogue items for different aspect ratios?
Strategy

Software for layouting catalogue items for different aspect …


Hi everyone. If this post doesn’t exactly fit the sub, I’d be glad if you point me to the right community.

I have an always-updating list of events that I need to bundle up from time to time into a visual brochure/flyer. The caveat is variance:

  • Often times I need to switch between aspect ratios. 1:1 for social media, 1:1.294 for printing, etc.

  • Number of events can vary (4 or 5 per page)

  • Icons and text is different across all events

  • Some key shapes need to remain intact (for example, ornamental borders)

r/graphic_design - Software for layouting catalogue items for different aspect ratios?

Square layout (trimmed the irrelevant stuff)

r/graphic_design - Software for layouting catalogue items for different aspect ratios?

Print layout – 4 items

r/graphic_design - Software for layouting catalogue items for different aspect ratios?

Print layout – 5 items

I’ve been manually readjusting rectangles in Illustrator (that’s what I used for the initial design), which to say the least is very painful.

I’ve been wondering if there is a piece of software that can allow me to define the rules for vector elements’ placement and scale, as well as simplify filling them with content (instead of manualy typing everything).

I’ve taken a look at InDesign, but it doesn’t seem like it checks either of these boxes, let alone all of them at once. I’m tempted to just use HTML, CSS and JS to build a flexible layout, but it feels like screwing phillips screws with flat screwdriver. You can do that of course, but it feels wacky.

Does anyone has something that can help me here?



Source link

Screenshot of this bug
Strategy

fit-content and fit-content() – QuirksBlog


fit-content and fit-content() – QuirksBlog






fit-content and fit-content()

Today we will look at fit-content and fit-content(), which are special values for width and grid definitions. It’s … complicated — not as a concept, but in its practical application.

[ Would you like to improve your CSS? You can hire me as a
CSS coach. ]

min- and max-content

Before looking at fit-content we have to briefly review two other special width values: min-content and max-content. You need those in order to understand fit-content.

Normally (i.e. with width: auto defined or implied) a box will take as much horizontal space as it can. You can change the horizontal space by giving width a specifc value, but you can also order the browser to determine it from the box’s contents. That’s what min-content and max-content do.

Try them below.

min-content and max-content

width: auto: as much as possible

width: max-content

width: min-content

width: max-content with a long text that runs the danger of disappearing right out of the browser window if it continues for much longer

  • min-content means: the minimal width the box needs to contain its contents. In practice this means that browsers see which bit of content is widest and set the width of the box to that value. The widest bit of content is the longest word in a text, or the widest image or video or other asset.
  • max-content means: the width the box needs to contain all of its contents. In the case of text this means that all text is placed on one line and the box becomes as wide as necessary to contain that entire line. In general this is not a desirable effect. The largest bit of content may also be an image or video other asset; in that case browsers use this width to determine the box’s width.

If you use hyphens: auto or something similar, the browser will break the words at the correct hyphenation points before determining the minimal width. (I turned off hyphenation in the examples.)

Quick Chromia/Android rabbit hole

All Chromium-based browsers on Android (tested in Chrome (v90), Samsung Internet (v87), and Edge (v77)) break off the ‘width: max-content’ text in the example above at the dash, and thus take the ‘width: max-‘ as the max-content, provided the page does NOT have a meta viewport. No other browser does this — and that includes Chrome on Mac.

Screenshot of this bug

Also, Chromia on Android make the font-size a tad smaller when you resize the boxes below the maximum possible width. I will ignore both bugs because this article is about fit-content, and not about these rabbit holes.

These bugs do NOT occur in UC (based on Chromium 78). Seems UC is taking its own decisions here, and is impervious to these particular bugs.

fit-content

Now that we understand these values we also understand fit-content. It is essentially a shorthand for the following:

box {
	width: auto;
	min-width: min-content;
	max-width: max-content;
}

Thus the box sizes with its containing box, but to a minimum of min-content and to a maximum of max-content.

fit-content as width, min-width, and max-width

width: fit-content: trying to find my fit

min-width: fit-content

max-width: fit-content

I’m not sure if this effect is useful outside a grid or flexbox context, but it’s here if you need it.

fit-content as min- or max-width

You can also use fit-content as a min-width or max-width value; see the example above. The first means that the width of the box varies between min-content and auto, while the second means it varies between 0 and max-content.

I find this fairly useless and potentially confusing. What you really mean is min-width: min-content or max-width: max-content. If that’s what you mean, say so. Your CSS will be clearer if you do.

So I believe that it would be better not to use fit-content for min-width or max-width; but only for width.

-moz-

Unfortunately, while fit-content works in all other browsers, Firefox still needs a vendor prefix. So the final code becomes:

box {
	width: -moz-fit-content;
	width: fit-content;
}

(These prefixes get harder and harder to defend as time goes by. fit-content has perfectly fine cross-browser support, so I don’t see why Firefox doesn’t just go over to the regular variant.)

fit-content in flexbox and grid: nope

fit-content does not work in flexbox and grid. In the example below the centre box has width: fit-content; it does not work. If it worked the middle box would have a width of max-content; i.e. as small as it needs to be to contain its text.

Flexbox with fit-content

Test content

fit-content

Test content

The final example on this page has a test where you can see grid doesn’t understand this keyword, either.

Note that grid and flex items have min-width: min-content by default, as you can see in the example above.

fit-content()

Let’s go to the more complex part: fit-content(). Although it’s supposed to work for a normal width, it doesn’t.

fit-content and fit-content() as width

width: fit-content: trying to find my fit

width: fit-content(200px)

Grid

You can use fit-content(value) in grid templates, like:

1fr fit-content(200px) 1fr
Grid with fit-content(200px)

Test content

fit-content(200px)

Test content

It means

1fr min(max-content-size, max(min-content, 200px)) 1fr

The max() argument becomes min-content or 200 pixels, whichever is larger. This is then compared to the maximum content size, which is the actual width available due to the constraints of the grid, but with a maximum of max-content. So the real formula is more like this one, where available-size is the available width in the grid:

1fr min(min(max-content,available-size), max(min-content, 200px)) 1fr

Some syntactic notes:

  • We’re talking fit-content() the function here. fit-content the keyword does not work in grid definitions.
  • Here Firefox does not need -moz-. Go figure.
  • fit-content() needs an argument; an empty function does not work. Also, an argument in fr units is invalid.
  • MDN mentions a value fit-content(stretch). It does not work anywhere, and isn’t referred to anywhere else. I assume it comes from an older version of the spec.

I tested most of these things in the following example, where you can also try the bits of syntax that do not work — maybe they’ll start working later.

And that’s fit-content and fit-content() for you. It’s useful in some situations.

Below you can play around with fit-content() in a grid.

Grid with controls

Set grid-template-columns: to

Test content

fit-content() with some more text

[ Would you like to improve your CSS? You can hire me as a
CSS coach. ]



Source link

Can We Create a "Resize Hack" With Container Queries?
Strategy

Can We Create a “Resize Hack” With Container Queries?


If you follow new developments in CSS, you’ve likely heard of the impending arrival of container queries. We’re going to look at the basics here, but if you’d like another look, check out Una’s “Next Gen CSS: @container” article. After we have a poke at the basics ourselves, we’re going to build something super fun with them: a fresh take on the classic CSS meme featuring Peter Griffin fussing with window blinds. 😉

So, what is a container query? It’s… exactly that. Much like we have media queries for querying things such as the viewport size, a container query allows us to query the size of a container. Based on that, we can then apply different styles to the children of said container.

What does it look like? Well, the exact standards are being worked out. Currently, though, it’s something like this:

.container {
  contain: layout size;
  /* Or... */
  contain: layout inline-size;
}

@container (min-width: 768px) {
  .child { background: hotpink; }
}

The layout keyword turns on layout-containment for an element. inline-size allows users to be more specific about containment. This currently means we can only query the container’s width. With size, we are able to query the container’s height.

Again, we things could still change. At the time of writing, the only way to use container queries (without a polyfill) is behind a flag in Chrome Canary (chrome://flags). I would definitely recommend having a quick read through the drafts over on csswg.org.

The easiest way to start playing would be to whip up a couple quick demos that sport a resizable container element.

Try changing the contain values (in Chrome Canary) and see how the demos respond. These demo uses contain: layout size which doesn’t restrict the axis. When both the height and width of the containers meet certain thresholds, the shirt sizing adjusts in the first demo. The second demo shows how the axes can work individually instead, where the beard changes color, but only when adjusting the horizontal axis.

@container (min-width: 400px) and (min-height: 400px) {
  .t-shirt__container {
    --size: "L";
    --scale: 2;
  }
}

That’s what you need to know to about container queries for now. It’s really just a few new lines of CSS.

The only thing is: most demos for container queries I’ve seen so far use a pretty standard “card” example to demonstrate the concept. Don’t get me wrong, because cards are a great use case for container queries. A card component is practically the poster child of container queries. Consider a generic card design and how it could get affected when used in different layouts. This is a common problem. Many of us have worked on projects where we wind up making various card variations, all catering to the different layouts that use them.

But cards don‘t inspire much to start playing with container queries. I want to see them pushed to greater limits to do interesting things. I‘ve played with them a little in that t-shirt sizing demo. And I was going to wait until there was better browser support until I started digging in further (I’m a Brave user currently). But then Bramus shared there was a container query polyfill!

And this got me thinking about ways to “hack” container queries.

⚠️ Spoiler alert: My hack didn’t work. It did momentarily, or at least I thought it did. But, this was actually a blessing because it prompted more conversation around container queries.

What was my idea? I wanted to create something sort of like the “Checkbox Hack” but for container queries.

<div class="container">
  <div class="container__resizer"></div>
  <div class="container__fixed-content"></div>
</div>

The idea is that you could have a container with a resizable element inside it, and then another element that gets fixed positioning outside of the container. Resizing containers could trigger container queries and restyle the fixed elements.

.container {
  contain: layout size;
}

.container__resize {
  resize: vertical;
  overflow: hidden;
  width: 200px;
  min-height: 100px;
  max-height: 500px;
}

.container__fixed-content {
  position: fixed;
  left: 200%;
  top: 0;
  background: red;
}

@container(min-height: 300px) {
  .container__fixed-content {
    background: blue;
  }
}

Try resizing the red box in this demo. It will change the color of the purple box.

Can we debunk a classic CSS meme with container queries?

Seeing this work excited me a bunch. Finally, an opportunity to create a version of the Peter Griffin CSS meme with CSS and debunk it!

You’ve probably seen the meme. It’s a knock on the Cascade and how difficult it is to manage it. I created the demo using [email protected]… with my own little touches, of course. 😅

Moving the cord handle, resizes an element which in turn affects the container size. Different container breakpoints would update a CSS variable, --open, from 0 to 1, where 1 is equal to an “open” and 0 is equal to a “closed” state.

@container (min-height: 54px) {
  .blinds__blinds {
    --open: 0.1;
  }
}
@media --css-container and (min-height: 54px) {
  .blinds__blinds {
    --open: 0.1;
  }
}
@container (min-height: 58px) {
  .blinds__blinds {
    --open: 0.2;
  }
}
@media --css-container and (min-height: 58px) {
  .blinds__blinds {
    --open: 0.2;
  }
}
@container (min-height: 62px) {
  .blinds__blinds {
    --open: 0.3;
  }
}
@media --css-container and (min-height: 62px) {
  .blinds__blinds {
    --open: 0.3;
  }
}

But…. as I mentioned, this hack isn’t possible.

What’s great here is that it prompted conversation around how container queries work. It also highlighted a bug with the container query polyfill which is now fixed. I would love to see this “hack” work though.

Miriam Suzanne has been creating some fantastic content around container queries. The capabilities have been changing a bunch. That’s the risk of living on the bleeding edge. One of her latest articles sums up the current status.

Although my original demo/hack didn’t work, we can still kinda use a “resize” hack to create those blinds. Again, we can query height if we use contain: layout size. Side note: it’s interesting how we’re currently unable to use contain to query a container’s height based on resizing its child elements.

Anyway. Consider this demo:

The arrow rotates as the container is resized. The trick here is to use a container query to update a scoped CSS custom property.

.container {
  contain: layout size;
}

.arrow {
  transform: rotate(var(--rotate, 0deg));
}

@container(min-height: 200px) {
  .arrow {
    --rotate: 90deg;
  }
}

We‘ve kinda got a container query trick here then. The drawback with not being able to use the first hack concept is that we can’t go completely 3D. Overflow hidden will stop that. We also need the cord to go beneath the window which means the windowsill would get in the way.

But, we can almost get there.

This demo uses a preprocessor to generate the container query steps. At each step, a scoped custom property gets updated. This reveals Peter and opens the blinds.

The trick here is to scale up the container to make the resize handle bigger. Then I scale down the content to fit back where it’s meant to.


This fun demo “debunking the meme” isn’t 100% there yet, but, we’re getting closer. Container queries are an exciting prospect. And it’ll be interesting to see how they change as browser support evolves. It’ll also be exciting to see how people push the limits with them or use them in different ways.

Who know? The “Resize Hack” might fit in nicely alongside the infamous “Checkbox Hack” one day.





Source link

Create a Console Application
Strategy

Advanced C# Programming (Part 1)


Introduction

In this session, we discuss on below points in C# programming using Visual Studio. These points are,

  1. The Basic Structure of A C# Program.
  2. What Is Namespace?
  3. Purpose of The Main Method.

Step 1: Create a console application:

Create a Console Application

Step 2: Open the Program.cs file and the content will be shown as below.

Here I will remove unwanted namespace declaration along with other lines of code as shown below. Make sure to compare these code blocks.

Step 3: Here I need to show a sample message to the end-user.

Here console is the class to read and write from and to the console and here I used the method called WriteLine() to show a sample message on the console window. So, to run the console application just use the ctrl+f5 key combination. You will get a message as shown below.

WriteLine() Method

Code Description

Here the namespace declaration is used that is system namespace.

This line tells that the rest of the code that we used here these are present inside that system’s namespace.  A namespace is used to organize your code and is a collection of classes, interfaces, structs, enums, and delegates. A namespace is a collection of classes. A namespace can contain other namespaces.

Namespace: System.Configuration

If you omit the using System, declaration, then you have to use the fully qualified name of the Console class as below otherwise we get a compile time error that the name ‘Console’ does not exist in the current context.

Compile Time Error

Here we can show the same message without using declaration as shown below:

But we need to avoid the above approach because instead of using system keyword every time inside code we need to system namespace declaration and we can access the classed, methods using system namespace as described earlier. That helps us less typing code and avoid complexity.

Another more important thing is class. Here class name is Program. Whatever we write code inside class block here only.

The next one is a function or method called Main(). It is the entry point of our console application. A function will have access modifiers, static modifiers, return types, method parameters, method names, etc.

Here return type is void and access modifier is Public and no method parameter passed inside brackets. The name of the function is Main. This function tells the program execution from starting curly brace and print the message then end at another curly brace. The below image will show the step-by-step execution of the Main method.

Main Method Execution

Check Main Method Is The Entry Point

Here I need to create another method inside the same class called Main1.

Let’s check which method will execute first and print the message. The Main method will execute first and print the message but the Main1 method will not execute.

But I want to print the message of the Main1 method. To do so, I need to call the Main1 method inside the Main method as shown below. So, that first the Main method will execute, then the Main1 method.

Now run this program and check the output as shown below. It prints both messages.

Running Program

Every console application should have a Main method. The program starts executing from the Main method.

Summary

In this write-up, we have learned the below details,

  1. The basic structure of a C# program.
  2. What is namespace?
  3. Purpose of the Main method.

Thank You and Stay Tuned For More!



Source link

Harvard Gallery Screenshot
Strategy

Running Concurrent Requests With Async/Await and Promise.all


Introduction

In this article, I’d like to touch on async, await, and Promise.all in JavaScript. First, I’ll talk about concurrency vs. parallelism and why we will be targeting parallelism in this article. Then, I’ll talk about how to use async and await to implement a parallel algorithm in serial and how to make it work in parallel by using Promise.all. Finally, I’ll create an example project using Salesforce’s Lightning Web Components where I will build an art gallery using Harvard’s Art Gallery API.

Concurrency vs. Parallelism

I want to quickly touch on the difference between concurrency and parallelism. You can relate concurrency to how a single-threaded CPU processes multiple tasks. Single-threaded CPUs emulate parallelism by switching between processes quickly enough that it seems like multiple things are happening at the same time. Parallelism is when a CPU has multiple cores and can actually run two tasks at the exact same time. Another great example is this:

Concurrency is two lines of customers ordering from a single cashier (lines take turns ordering); Parallelism is two lines of customers ordering from two cashiers (each line gets its own cashier). [1]

Knowing this difference helps us consider what options we have from an algorithmic standpoint. Our goal is to make these HTTP requests in parallel. Due to some limitations in JavaScript implementation and browser variability, we don’t actually get to determine if our algorithm will be run concurrently or in parallel. Luckily, I don’t need to change our algorithm at all. The underlying JavaScript event loop will make it seem like the code is running in parallel, which is good enough for this article!

Async/Await in Serial

In order to understand this parallel algorithm, I’ll first use async and await to build a serial algorithm. If you write this code in an IDE, you’ll likely get a notification saying that using await in a loop is a missed optimization opportunity — and your IDE would be correct.

(async () => {
    const urls = [
        "https://example.com/posts/1/",
        "https://example.com/posts/1/tags/",
    ];
    
    const data = [];
  for (url of urls) {
    await fetch(url)
      .then((response) => response.json())
      .then((jsonResponse) => data.push(jsonResponse));
  }

  console.log(data);
})();

One reason that you might implement an algorithm like this is if you need to get the data from two different URLs, then blend that data together to create your final object. In the code above, you can imagine that we are gathering some data about a post, then grabbing the data about the posts tags, and finally merging that data into the object you’d actually use later on.

While this code will work, you might notice that we await on each fetch. You’ll see something like:

  • Start to fetch post one.
  • Wait for fetch post one to complete.
  • Get post one response.
  • Start to fetch post one tags.
  • Wait for post one tags to complete.
  • Get post one tags response.

The problem is we’re waiting serially for each network request to complete before starting the next request. There’s no need for this: Computers are perfectly capable of executing more than one network request at the same time.

So how can we make this algorithm better?

Async/Await in Parallel

The easiest way to make this algorithm faster is to remove the await keyword before the fetch command. This will tell JavaScript to start the execution of all the requests in parallel. But in order to pause execution and wait for all of the promises to return, we need to await something. We’ll use Promise.all to do just that.

When we use await Promise.all, JavaScript will wait for the entire array of promises passed to Promise.all to resolve. Only then will it return all the results at the same time. A rewrite looks like this:

(async () => {
    const urls = [
        "https://example.com/posts/1/",
        "https://example.com/posts/1/tags/",
    ];
    
  const promises = urls.map((url) =>
    fetch(url).then((response) => response.json())
  );

  const data = await Promise.all(promises);

  console.log(data);
})();

This code will map each URL into a promise and then await for all of those promises to complete. Now when we pass the await Promise.all portion of the code, we can be sure that both fetch requests have resolved and the responses are in the data array in the correct position. So data[0] will be our post data and data[1] will be our tags data.

An Example

Now that we have all the necessary building blocks to implement our pre-fetched image gallery, let’s build it.

Below is a screenshot of the app I built for this article, and here is the link to the documentation about the Harvard Art Museum API docs [2]. You’ll need to apply for your own API key if you’d like to follow along. The process seemed pretty automatic to me since you just fill out a Google Form and then receive your API key in your email instantly.

Harvard Gallery Screenshot

It doesn’t look like much, but as you navigate through the gallery, it pre-fetches the next pages of data automatically. That way, the user viewing the gallery shouldn’t see any loading time for the actual data. The images are only loaded when they are displayed on the page. And while those do load after the fact, the actual data for the page is loaded instantly since it is cached in the component. Finally, as a challenge to myself, I’m using Salesforce’s Lightning Web Components for this project a completely new technology to me. Let’s get into building the component.

Here are some of the resources that I used while learning about Lightning Web Components. If you’d like to follow along, then you’ll at least need to set up your local dev environment and create a “hello world” Lightning Web Component.

Setup A Local Development Environment [3]

Create a Hello World Lightning Web Component [4]

LWC Sample Gallery [5]

LWC Component Reference [6]

Alright, now that your environment is set up and you’ve created your first LWC, let’s get started. By the way, all the code for this article can be found at my GitHub repo [7].

A quick aside: Lightning Web Components are a little more limited than components you might be used to if you are coming from a React background. For example, you can’t use JavaScript expressions in component properties, i.e., the image src, in the following example:

<template for:each={records} for:item="record">
    <img src={record.images[0].baseimageurl}>
</template>

The reason for that is when you force all of your code to happen in the JavaScript files rather than in the HTML template files, your code becomes much easier to test. So let’s chalk this up to “it’s better for testing” and move on with our lives.

In order to create this gallery, we’ll need to build two components. The first component is for displaying each gallery image, and the second component is for pre-fetching and pagination.

The first component is the simpler of the two. In VSCode, execute the command SFDX: Create Lightning Web Component and name the component harvardArtMuseumGalleryItem. This will create three files for us: an HTML, JavaScript, and XML file. This component will not need any changes to the XML file since the item itself isn’t visible in any Salesforce admin pages.

Next, change the contents of the HTML file to the following:

# force-app/main/default/lwc/harvardArtMuseumGalleryItem/harvardArtMuseumGalleryItem.html

<template>
    <div class="gallery-item" style={backgroundStyle}></div>
    {title}
</template>

Note that in this HTML file, the style property is set to {backgroundStyle} which is a function in our JavaScript file, so let’s work on that one.

Change the contents of the JS file to the following:

# force-app/main/default/lwc/harvardArtMuseumGalleryItem/harvardArtMuseumGalleryItem.js

import { LightningElement, api } from 'lwc';

export default class HarvardArtMuseumGalleryItem extends LightningElement {
    @api
    record;

    get image() {
        if (this.record.images && this.record.images.length > 0) {
            return this.record.images[0].baseimageurl;
        }

        return "";
    }

    get title() {
        return this.record.title;
    }

    get backgroundStyle() {
        return `background-image:url('${this.image}');`
    }
}

There are a few things to notice here. First, the record property is decorated with @api which allows us to assign to this property from other components. Keep an eye out for this record property on the main gallery component. Also, since we can’t have JavaScript expressions in our HTML files, I’ve also brought the background image inline CSS into the JavaScript file. This allows me to use string interpolation with the image. The image function is nothing special as it is just an easy way for me to get the first image URL from the record that we received from the Harvard Art Gallery API.

Our final step of this component is to add a CSS file that wasn’t created for us automatically. So create harvardArtMuseumGalleryItem.css in the harvardArtMuseumGalleryItem directory. You don’t need to tell the application to use this file as it is included automatically just by its existence.

Change the contents of your newly created CSS file to the following:

# force-app/main/default/lwc/harvardArtMuseumGalleryItem/harvardArtMuseumGalleryItem.css

.gallery-item {
    height: 150px;
    width: 100%;
    background-size: cover;
}

Now that our busy work is out of the way, we can get to the actual gallery.

Run SFDX: Create Lightning Web Component in VSCode again and name the component harvardArtMuseumGallery. This will, once again, generate our HTML, JavaScript, and XML files. We need to pay close attention to the XML file this time. The XML file is what tells Salesforce where our component is allowed to be located as well as how we will store our API key in the component.

# force-app/main/default/lwc/harvardArtMuseumGallery/harvardArtMuseumGallery.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="<http://soap.sforce.com/2006/04/metadata>">
    <apiVersion>51.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__HomePage">
            <property name="harvardApiKey" type="String" default=""></property>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

There are three key things to pay attention to in this XML file. The first is isExposed which will allow our component to be found in the Salesforce admin. The second is the target which says which areas of the Salesforce site our component can be used. This one says that we are allowing our component to be displayed on HomePage type pages. Finally, the targetConfigs section will display a text box when adding the component. There, we can paste our API key (as seen in the following screenshot). You can find more information about this XML file here [8].Example of Entering the API Key Into the Salesforce UI

Next, let’s take care of the HTML and CSS files.

# force-app/main/default/lwc/harvardArtMuseumGallery/harvardArtMuseumGallery.html

<template>
    <lightning-card title="HelloWorld" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
          <h1>Harvard Gallery</h1>
          <div class="gallery-container">
            <template for:each={records} for:item="record">
              <div key={record.index} class="row">
                <template for:each={record.value} for:item="item">
                  <c-harvard-art-museum-gallery-item if:true={item} key={item.id} record={item}></c-harvard-art-museum-gallery-item>
                </template>
              </div>
            </template>
          </div>
          <div class="pagination-container">
            <button type="button" onclick={previousPage}>&lt;</button>
            <span class="current-page">
              {currentPage}
            </span>
            <button type="button" onclick={nextPage}>&gt;</button>
          </div>
        </div>
      </lightning-card>
</template>

Most of this is standard HTML with some custom components. The line I want you to pay attention to most is the <c-harvard-art-museum-gallery-item> tag and its record property. You’ll remember that this is the property we decorated with @api in the gallery item JavaScript file. The @api decoration allows us to pass in the record through this property.

Next, onto the CSS file:

# force-app/main/default/lwc/harvardArtMuseumGallery/harvardArtMuseumGallery.css

h1 {
  font-size: 2em;
  font-weight: bolder;
  margin-bottom: .5em;
}

.gallery-container .row {
  display: flex;
}

c-harvard-art-museum-gallery-item {
  margin: 1em;
  flex-grow: 1;
  width: calc(25% - 2em);
}

.pagination-container {
  text-align: center;
}

.pagination-container .current-page {
  display: inline-block;
  margin: 0 .5em;
}

I’ve saved the most interesting for last! The JavaScript file includes our pre-fetching logic and page-rolling algorithm.

# force-app/main/default/lwc/harvardArtMuseumGallery/harvardArtMuseumGallery.js

import { LightningElement, api } from "lwc";

const BASE_URL =
  "<https://api.harvardartmuseums.org/object?apikey=$1&size=8&hasimage=1&page=$2>";

export default class HarvardArtMuseumGallery extends LightningElement {
  @api harvardApiKey;

  error;
  records;
  currentPage = 1;
  pagesCache = [];

  chunkArray(array, size) {
    let result = [];
    for (let value of array) {
      let lastArray = result[result.length - 1];
      if (!lastArray || lastArray.length === size) {
        result.push([value]);
      } else {
        lastArray.push(value);
      }
    }

    return result.map((item, index) => ({ value: item, index: index }));
  }

  nextPage() {
    this.currentPage++;
    this.changePage(this.currentPage);
  }

  previousPage() {
    if (this.currentPage > 1) {
      this.currentPage--;
      this.changePage(this.currentPage);
    }
  }

  connectedCallback() {
    this.changePage(1);
  }

  async changePage(page) {
    let lowerBound = ((page - 3) < 0) ? 0 : page - 3;
    const upperBound = page + 3;

    // Cache the extra pages
    const promises = [];
    for (let i = lowerBound; i <= upperBound; i++) {
      promises.push(this.getRecords(i));
    }

    Promise.all(promises).then(() => console.log('finished caching pages'));

    // Now this.pages has all the data for the current page and the next/previous pages
    // The idea is that we will start the previous promises in order to prefrech the pages
    // and here we will wait for the current page to either be delivered from the cache or
    // the api call
    this.records = await this.getRecords(page);
  }

  async getRecords(page) {
    if (page in this.pagesCache) {
      return Promise.resolve(this.pagesCache[page]);
    }

    const url = BASE_URL.replace("$1", this.harvardApiKey).replace("$2", page);
    return fetch(url)
      .then((response) => {
        if (!response.ok) {
          this.error = response;
        }

        return response.json();
      })
      .then((responseJson) => {
        this.pagesCache[page] = this.chunkArray(responseJson.records, 4);
        return this.pagesCache[page];
      })
      .catch((errorResponse) => {
        this.error = errorResponse;
      });
  }
}

Notice that we are decorating the harvardApiKey with @api. This is how the targetConfig property from our XML file will be injected into our component. Most of the code in this file facilitates changing pages and chunking the response so that we get rows of four gallery items. Pay attention to changePage as well as getRecords: this is where the magic happens. First, notice that changePage calculates a range of pages from whatever the current requested page is. If the current requested page is five, then we will cache all pages from two until page eight. We then loop over the pages and create a promise for each page.

Originally, I was thinking that we’d need to await on the Promise.all in order to avoid loading a page twice. But then I realized it is a low cost to pay in order to not wait for all of the pages to be returned from the API. So the current algorithm is as follows:

  1. User requests page five.
  2. Bounds are calculated as page two through page eight, and promises are created for those requests.
  3. Since we aren’t waiting for the promises to return, we will again request page five and make an extra API request (but this only happens for pages that aren’t in the cache).
  4. So let’s say that the user progresses to page six.
  5. Bounds are calculated as pages three through nine, and promises are created for those requests.
  6. Since we already have pages two through eight in the cache, and since we didn’t await those promises, page six will immediately load from the cache while the promise for page nine is being fulfilled (since it is the only page missing from the cache).

Conclusion

And there you have it! We’ve explored concurrency and parallelism. We learned how to build an async/await flow in serial (which you should never do). We then upgraded our serial flow to be in parallel and learned how to wait for all the promises to resolve before continuing. Finally, we’ve built a Lightning Web Component for the Harvard Art Museum using async/await and Promise.all. (Although in this case, we didn’t need the Promise.all since the algorithm works better if we don’t wait for all the promises to resolve before continuing on.)

Thanks for reading and feel free to leave any comments and questions below.

Citations:

[1] https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism

[2] https://github.com/harvardartmuseums/api-docs

[3] https://trailhead.salesforce.com/content/learn/projects/quick-start-lightning-web-components/set-up-salesforce-dx

[4] https://trailhead.salesforce.com/content/learn/projects/quick-start-lightning-web-components/create-a-hello-world-lightning-web-component

[5] https://trailhead.salesforce.com/sample-gallery

[6] https://developer.salesforce.com/docs/component-library/overview/components

[7] https://github.com/bloveless/AsyncAwaitPromiseAllLWC

[8] https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningcomponentbundle.htm



Source link

Columns vs. Rows
Strategy

Getting Started With C# DataFrame and XPlot.Ploty


For the Python programming language, Pandas is an efficient and popular data analysis tool, especially its Dataframe, used to manipulate and display data. For the .NET programming languages, we can use Deedle or Microsoft.Data.Analysis package available in NuGet which also provides a DataFrame class used to manipulate, transform, and display data.

This example focuses on Microsoft.Data.Analysis package by demonstrating some basic features of the DataFrame class in Jupyter Notebook.

It also uses the XPlot.Plotly package which is F# data visualization package to plot charts for the data in the Dataframe. The source code is available on GitHub.

Prerequisite

To run examples in this article, please refer to this Using .NET Core in Jupyter Notebook article for setting up Jupyter Notebook to support the .NET programming languages.

Install the Package

The Microsoft.Data.Analysis package is available in Nuget so the dotnet-interactive #r magic command can be used to install the package from NuGet.

Run the below command to install Microsoft.Data.Analysis package version 0.4.0.

#r "nuget:Microsoft.available Data.Analysis,0.4.0"

Refer the Namespaces

This article uses classes from the following four packages. Therefore, it uses the using statement to refer to those packages.

  • XPlot.Plotly: A cross-platform data visualization package for the F# and .NET programming languages
  • Microsoft.Data.Analysis: An easy-to-use and high-performance libraries for data analysis and transformation
  • System.Linq: Classes and interfaces that support queries that use Language-Integrated Query
  • Microsoft.AspNetCore.Html: Types for manipulating HTML content
using XPlot.Plotly;
using Microsoft.Data.Analysis;
using System.Linq;
using Microsoft.AspNetCore.Html;

Render a DataFrame as an HTML Table

By default, a DataFrame is rendered as an HTML table with one row and two columns (Columns and Rows).

Columns vs. Rows

This can be overridden by registering the custom formatter for the DataFrame. The below code registers custom formatters for the Dataframe and DataFrameRow to render the data in an HTML table. 

Custom Formatting

It only displays the first 100 rows. This can be changed by modifying the value of the take variable. 

Formatter<DataFrame>.Register((df, writer) =>
{
    var headers = new List<IHtmlContent>();
    headers.Add(th(i("index")));
    headers.AddRange(df.Columns.Select(c => (IHtmlContent) th(c.Name)));
    var rows = new List<List<IHtmlContent>>();
    var take = 100;
    for (var i = 0; i < Math.Min(take, df.Rows.Count); i++)
    {
        var cells = new List<IHtmlContent>();
        cells.Add(td(i));
        foreach (var obj in df.Rows[i])
        {
            cells.Add(td(obj));
        }
        rows.Add(cells);
    } 
    var t = table(
        thead(
            headers),
        tbody(
            rows.Select(
                r => tr(r))));
    writer.Write(t);    
    writer.Write(df.Rows.Count + " x "+df.Columns.Count);
}, "text/html");
 
Formatter<DataFrameRow>.Register((dataFrameRow, writer) =>
{
    var cells = new List<IHtmlContent>();
    cells.Add(td(i));
    foreach (var obj in dataFrameRow)
    {
        cells.Add(td(obj));
    }
    var t = table(
        tbody(
            cells));
    writer.Write(t);
}, "text/html");

Create the DataFrame

DataFrameColumn

A DataFrame can be created by passing the list of DataFrameColumn objects to the DataFrame’s constructor.

public DataFrame(params DataFrameColumn[] columns);
public DataFrame(IEnumerable<DataFrameColumn> columns);

The following code creates a DataFrame that has 200 rows and 2 columns. The first column contains dates and the second column contains random integer numbers. It calls the PrimitiveDataFrameColumn constructor to create the DataFrameColumn instances.

var start = new DateTime(2009,1,1);
Random rand = new Random();
var numDataPoint = 200; 

PrimitiveDataFrameColumn<DateTime> date = new PrimitiveDataFrameColumn<DateTime>("Date", 
    Enumerable.Range(0, numDataPoint)
          .Select(offset => start.AddDays(offset))
          .ToList()); 
PrimitiveDataFrameColumn<int> data = new PrimitiveDataFrameColumn<int>("Data",
    Enumerable.Range(0, numDataPoint)
                        .Select(r => rand.Next(100))
                        .ToList()); 
var df = new DataFrame(date, data);
df

CSV File

The DataFrame can also be created from a CSV file by calling the DataFrame.LoadCsv static method.

The following code creates a DataFrame from the ohcldata.csv file. This file is downloaded from 5.30. Example – Basic OHLC (Open, High, Low, Close) Financial Plot website. This file contains the daily Open, High, Low, Close financial data.

var df1 = DataFrame.LoadCsv("ohlcdata.csv");
df1

Then, the Info method can be used to generate a summary of each column in the DataFrame. 

Access the DataFrame

Access Data by Indices

A row index and column index can be used to access the specific data in the DataFrame. The index is zero-based numbering.

The below code access data in the first row and the second column.

Out[7]: 11; First Row, Second Column

After that, a new value can be assigned to the DataFrame.

The below code increases the data in the first row and the second column by 10.

df[0,1] = int.Parse(df[0,1].ToString()) + 10;
df.Head(10)

Out[8]: Chart; Increase Data by 10

Access Row Data

The entire row can be accessed by using a row index. The index is zero-based numbering.

The below code accesses the tenth row in the DataFrame.

The column index can also be used to access the specific column in the row.

The below accesses the fourth column in the tenth row.

Then, the new value can also be assigned to the column.

The below code assigns 50000000 to the sixth column.

df1.Rows[9][5] = 50000000f;
df1.Head(10)

Out[11]: Chart; Access Row Data

Access Column Data

The entire column can be accessed by using a column name or index. The index is zero-based numbering.

The below code accesses the column named Data (the second column) in the DataFrame.

//df.Columns["Data"] or df.Columns[1]
df.Columns["Data"]  

Out[12]: Chart; Access Column Data

The data in the column can be changed by using the DataFrame’s overloaded operators.

The below code increases all data in the column by ten.

 df.Columns["Data"]= df.Columns["Data"]+10;
 df

Out[13]: Chart; Increase All Data By 10

Insert Data

Add a New Column

The DataFrame maintains a list of DataFrameColumns in the DataFrameColumnCollection. A new column can be added to the DataFrameColumnCollection.

The below code adds a new integer column to the DataFrame.

df.Columns.Add(new PrimitiveDataFrameColumn<int>("Data1", df.Rows.Count()));
df

Out [14]: Chart; Add a New Column

The data in the new column is set to null.

The following code fills null values in the new column (Data1) with 10.

df.Columns["Data1"].FillNulls(10, true);
df

Out[15]: Chart; Fill Null Values

Append a New Row

The Append method can be used to append new rows to the DataFrame.

The following code creates a list of KeyValuePair instances and then adds it to the DataFrame.

df.Append(new List<KeyValuePair<string, object>>() { 
    new KeyValuePair<string, object>("Date", DateTime.Now),
    new KeyValuePair<string, object>("Data", 12),
    new KeyValuePair<string, object>("Data1", 50)
}, true);
df.Tail(10)

Out [16]: Chart; Append a New Row

Manipulate the DataFrame

Sort the DataFrame

The OrderBy or OrderByDescending method can be used to order the DataFrame by a specified column.

The following code sorts the DataFrame by the column named Data.

Out [17]:Chart; Sort DataFrame

Group the DataFrame

The GroupBy method can be used to group the rows of the DataFrame by unique values in the column.

The following code groups the DataFrame by the column named Data and then counts the number of values in each group.

var groupByData = df.GroupBy("Data");
groupByData.Count().OrderBy("Data")

Out[18]: Chart; Group the DataFrame

Filter the DataFrame

The Filter method can be used to filter the DataFrame by row indices or boolean values.

The following code filters the DataFrame by returning rows that have the values in the column named Data greater than fifty.

df.Filter(df.Columns["Data"].ElementwiseGreaterThan(50))

Out[19]: Chart; Filter the DataFrame

Merge the DataFrame

The Merge method can be used to merge two DataFrames with a database-style join.

The following code joins two DataFrames by using the Date column contained in both DataFrames. First, it converts the data type in the Date column of the df1 from the string type to the DataTime type. Then, it calls the Merge method to join the DataFrames.

df1.Columns["Date"] = new PrimitiveDataFrameColumn<DateTime>("Date", 
    df1.Columns["Date"]
                .Cast<object>()
                .ToList()
                .Select(x => DateTime.ParseExact(x.ToString(), "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture))
                .Cast<DateTime>());               

df1.Merge<DateTime>(df, "Date", "Date")

Out[20]: Chart; Merge the DataFrame

Plot Charts by Using XPlot.Ploty

XPlot.Ploty is a cross-platform data visualization package for the F# and .NET programming languages. It is based on Plotly which is the popular JavaScript charting library.

The following examples demonstrate how to use XPlot.Ploty to plot charts by using the data in the DataFrame.

Line Chart

The following code plots a line chart from the Open column in the DataFrame.

var chart1 = Chart.Plot(
    new Graph.Scatter
    {
        x = df1.Columns["Date"],
        y = df1.Columns["Open"],        
        mode = "lines+markers"
    }
);
var chart1_layout = new Layout.Layout{
    title="Open Price",
    xaxis =new Graph.Xaxis{
        title = "Date"
        },
    yaxis =new Graph.Yaxis{
    title = "Price (USD)"
        }           
    };
chart1.WithLayout(chart1_layout);
chart1

Line Chart Example

Line Chart With Mulitple Lines

The following code plots the Open, and Close columns in a line chart.

var chart2_list = new List<Graph.Scatter> 
{
    new Graph.Scatter
    {
         x = df1.Columns["Date"],
        y = df1.Columns["Open"],
        name="Open",
        mode = "lines"
    },
    new Graph.Scatter    
    {       
        x = df1.Columns["Date"],
        y = df1.Columns["Close"],
        name="Close",
        mode = "lines"
    }
    
};
 
var chart2 = Chart.Plot(
    chart2_list
);
 
var chart2_layout = new Layout.Layout{
    title="Open and Close Price",
    xaxis =new Graph.Xaxis{
        title = "Date"
        },
    yaxis =new Graph.Yaxis{
    title = "Price (USD)"
        }           
    };
chart2.WithLayout(chart2_layout);
chart2

Multiple Line Chart Example

Bar Chart

The following code plots a bar chart from the Volume column in the DataFrame.

var chart3 = Chart.Plot(

    new Graph.Bar
    {
        x = df1.Columns["Date"],
        y = df1.Columns["Volume"],        
        marker = new Graph.Marker{color = "rgb(0, 0, 109)"}
    }
);
var chart3_layout = new Layout.Layout{
    title="Volume",
    xaxis =new Graph.Xaxis{
        title = "Date"
        },
    yaxis =new Graph.Yaxis{
    title = "Unit"
        }           
    };
chart3.WithLayout(chart3_layout);
chart3

Bar Chart Example

Candlestick Chart

The following code plots a candlestick chart from the Open, High, Low, Close columns in the DataFrame.

var chart4 = Chart.Candlestick(df1.OrderBy("Date").Rows.Select(row => new Tuple<string, double, double, double, double>(
                 ((DateTime)row[0]).ToString("yyyy-MM-dd"),
                 double.Parse(row[1].ToString()),
                 double.Parse(row[2].ToString()),
                 double.Parse(row[3].ToString()),
                 double.Parse(row[4].ToString())
                )));
chart4.WithLayout(new Layout.Layout{
    title="OHLC",
    xaxis =new Graph.Xaxis{
        title = "Date"
        },
    yaxis =new Graph.Yaxis{
    title = "Price (USD)"
        }           
    });
chart4

Candlestick Chart

References

  1. Phplot.sourceforge.net. n.d. 5.30. Example – Basic OHLC (Open, High, Low, Close) Financial Plot. [online] Available at: http://phplot.sourceforge.net/phplotdocs/ex-ohlcbasic.html [Accessed 6 May 2021].
  2. Bluemountaincapital.github.io. n.d. Deedle: Exploratory data library for .NET. [online] Available at: https://bluemountaincapital.github.io/Deedle/ [Accessed 6 May 2021].
  3. Govindarajan, P., 2019. An Introduction to DataFrame | .NET Blog. [online] .NET Blog. Available at: https://devblogs.microsoft.com/dotnet/an-introduction-to-dataframe/ [Accessed 6 May 2021].
  4. Sequeira, J., 2020. dotnet/interactive: Magic Commands. [online] GitHub. Available at: https://github.com/dotnet/interactive/blob/main/docs/magic-commands.md [Accessed 6 May 2021].
  5. Winnington, E., 2019. Eric Winnington – Tips and tricks for C# Jupyter notebook. [online] Ewinnington.github.io. Available at: https://ewinnington.github.io/posts/jupyter-tips-csharp [Accessed 6 May 2021].
  6. Fslab.org. n.d. XPlot – F# Data Visualization Package. [online] Available at: https://fslab.org/XPlot/index.html [Accessed 6 May 2021].
  7. Phuriphanvichai, J., 2021. Using .NET Core in Jupyter Notebook | Refinitiv Developers. [online] Developers.refinitiv.com. Available at: https://developers.refinitiv.com/en/article-catalog/article/using–net-core-in-jupyter-notebook.html [Accessed 10 May 2021].



Source link

Install Python Setup
Strategy

Using .NET Core in Jupyter Notebook


Jupyter Notebook is an open-source web application that allows you to create and share documents that contain live code, equations, visualizations, and narrative text. It can be used as a tool for interactively developing and presenting data science projects. Mostly, it is used with Python and R which are scripting languages. However, it can also be used with compiled languages, such as .NET programming languages, Go, and Julia. For a list of supported programming languages, please refer to the Jupyter kernels page in GitHub.

This article explains steps to set up Jupyter Notebook for .NET Core programming languages on Windows 10.  It is based on the .NET Notebooks Preview 2 that supports C#, F#, and PowerShell. This article also provides few C# examples that demonstrate how to use DataFrame and Charts.

Microsoft .NET Core

.NET Core is an open-source and cross-platform software framework that can run on various operating systems, such as Windows, Linux, and macOS. It is a project of the .NET Foundation and released under the MIT and Apache 2 licenses.

The first version (.NET Core 1.0) was released on June 27, 2016. At the time of this writing, the current version is .NET 5.0 released on November 10, 2020. In .NET 5.0, the “Core” has been dropped from the name to emphasize that this is the main implementation of .NET going forward and it supports more types of applications and more platforms than .NET Core or .NET Framework.

Currently, Microsoft supports the .NET Core 2.1, .NET Core 3.1, and .NET 5.

Next, I will demonstrate steps to set up Jupyter Notebook for .NET Core 3.1 on Windows 10.

Steps to Setup Jupyter Notebook for .NET

1. Install Python

Python packages are available on the Python website. It supports many operating systems, such as Windows, Linux/Unix, and Mac OS X.

Download the Windows version and then install it on the machine. In this article, Python 3.9.4 64bit is used. You need to verify the installation path or choose the Add Python 3.9 to PATH option to add the Python installation path to the PATH environment variable. However, the Add Python 3.9 to PATH option may introduce the version conflicts among the installed Python versions. If you have multiple versions of Python installed on the machine, please be cautious of this option.

Install Python Setup

After installing, open the Windows Command Prompt to verify the version of Python (python –version). 

Administrator: Command Prompt

You may install different Python Distributions, such as Anaconda. Please refer to the Anaconda website for more information.

2. Install Jupyter Notebook

Jupyter Notebook can be installed with the pip command. Open the Windows Command Prompt and use the following commands to install Jupyter Notebook.

python -m pip install --upgrade pip  
python -m pip install jupyter

Install Jupyter Notebook

Then, run ‘Jupyter notebook’ from the Windows Command Prompt to start the Jupyter Notebook. 

Running Jupyter Notebook

At this time, the Jupyter Notebook only supports Python 3.

For different Python distributions, please refer to the distribution websites regarding how to install Jupyter Notebook.

3. Install .NET Core 3.1

You can download .NET Core 3.1 from the .NET Core website.

Install .NET Core 3.1

After the installation was successful, run the ‘dotnet ––version‘ command in the command prompt to verify the version of .NET Core.

dotnet --version Verification

4. Install dotnet-interactive Kernel

.NET on the Jupyter Notebook relies on the Microsoft.dotnet-interactive package which is a command-line tool for interactive programming with C#, F#, and PowerShell, including support for Jupyter Notebooks.

Run the following command in the command prompt to install Microsoft.dotnet-interactive.

dotnet tool install --global Microsoft.dotnet-interactive --version 1.0.155302

Installing dotnet-interactive Kernel

The versions higher than 1.0.155302 are for NET 5.0.

Then, run the following command to add dotnet-interactive to the Jupyter Notebook.

dotnet interactive jupyter install

Install Jupyer into dotnet

Finally, run ‘jupyter notebook’ via the Windows Command Prompt. Now, the Jupyter Notebook supports C#, F#, and PowerShell programming languages. 

Jupyter Supports Additional Languages Now

C# Examples

You can refer to the following examples that show how to use C# in Jupyter Notebook.

  1. Getting Started with C# DataFrame and XPlot.Plotly: This example demonstrates how to use DataFrame in Microsoft.Data.Analysis package and XPlot.Plotly library to plot charts.
  2. Getting Started with Eikon Data API .NET in Jupyter Notebook: This example demonstrates how to use Refinitiv .NET Eikon Data API on Jupyter Notebook to retrieve the latest data, historical data, symbology, and news. It uses the EikonDataApi package to retrieve data from Eikon and uses XPlot.Plotly package to draw charts.

References

1.  En.wikipedia.org. 2016. .NET Core – Wikipedia. [online] Available at: <https://en.wikipedia.org/wiki/.NET_Core> [Accessed 28 April 2021].
2. Microsoft. n.d. .NET Core and .NET 5 official support policy. [online] Available at: <https://dotnet.microsoft.com/platform/support/policy/dotnet-core> [Accessed 28 April 2021].
3. Docs.microsoft.com. n.d. .NET introduction and overview. [online] Available at: <https://docs.microsoft.com/en-us/dotnet/core/introduction> [Accessed 28 April 2021].
4. Python.org. 2021. Download Python. [online] Available at: <https://www.python.org/downloads/> [Accessed 28 April 2021].
5. Nuget.org. n.d. Microsoft.dotnet-interactive 1.0.221505. [online] Available at: <https://www.nuget.org/packages/Microsoft.dotnet-interactive/> [Accessed 28 April 2021].
6. Naggaga, M., 2020. .NET Interactive is here! | .NET Notebooks Preview 2 | .NET Blog. [online] .NET Blog. Available at: <https://devblogs.microsoft.com/dotnet/net-interactive-is-here-net-notebooks-preview-2/> [Accessed 28 April 2021].
7. Docs.microsoft.com. n.d. What’s new in .NET 5. [online] Available at: <https://docs.microsoft.com/en-us/dotnet/core/dotnet-five> [Accessed 28 April 2021].



Source link

Packages in Top-Level Directory
Strategy

Avoid Project Failure With Custom Flutter Packages


Leading a successful Flutter application development project often results from the strong organization of the application architecture.  Using Flutter packages is an excellent way to group your application files and functional sections into reusable components that make team collaboration easier. This tutorial will take you through all the steps needed to create a custom package for your next Flutter project.

A complete step-by-step video and full code are also available.

Overview

Before explaining how to create a custom package, let’s review why Flutter developers need to use packages and how custom packages are used.  The goal of the package is to isolate reusable functionality and make it easily accessible to other parts of your application. There can be multiple custom packages for a single application.

For example, we can create a custom package to handle HTTP network API connections for different buttons to display the results to different screens.   A good way to organize your code is to isolate all the connection functionality into a new directory called, connection.  The connection directory becomes the connection package. You can also create another package for animation and organize your custom animations in that package.   Each package you create is put into a common directory called packages.

Once the code is isolated in a package, you can make the package accessible to your application in your main project pubspec.yaml application configuration file. The syntax of the pubspec.yaml file differs slightly depending on how you distribute your package.

Once the package is made available to the application using pubspec.yaml, each file that uses the package imports the package using the syntax import 'package:name/file.dart`;

Let’s illustrate the process with examples, starting with the pubspec.yaml configuration.

3 Types of Package Dependency Configuration Formats 

There are three strategies for building and distributing your custom Flutter package:

  1. Publish to pub.dev;
  2. Publish to a GitHub or equivalent as a standalone repository;
  3. Store the package within your main project repository.

1. pub.dev

If you publish the package to pub.dev, you can access it from pubspec.yaml, under dependencies. As my library is not on pub.dev, I’ll show the syntax with the HTTP package.

2. Remote Git Server

In most cases, you don’t need to make your package accessible to a wide group of people.  In these cases, you can access the library from the network with the syntax below.

In the example above, the package name is theta. The package is available on GitHub under the main branch.

3. Packages Folder of Your Project

You can also store the package within your main application project folder.  If the package name is theta, then store it in the main project directory under packages/theta.

If the package is stored locally, the pubspec.yaml syntax is as follows.

Using a Custom Package

In all three methods, you import your custom package into your application to use it.

Application Code

Custom Package Code

To illustrate what part of the code is from the package, I’ll include a short snippet of the library. 

In the example above, the section Camera.info is a static getter located in the package at theta/lib/src/protocols.dart

Once the package is created, it is easy to access all the classes and methods in your package.

Recommendation on Distribution Strategy

You should start by putting your package inside of your application repository packages directory and only use the package for your one application initially.  Once the application and package are stable, you can then distribute it on GitHub for other members of your team or organization to use directly from their pubspec.yaml file. 

After you make the package accessible to other groups and they start to use it, you will need to spend more time with package version management.

Creating a Package

Create a new project.  I called my project theta_api_intro_tutorial.

Create a folder called, packages, in the main project top-level directory.

Packages in Top-Level Directory

Change into the directory and create a new package. In this example, my package is called, theta_connection.

flutter create --template=package theta_connection

When you create a package with flutter create, it will automatically create another set of lib, pubspec.yaml, and README.md files.

Under the newly created lib directory, there is the main theta_connection.dart file that functions as the central connection point for the rest of the files in your package.

Delete the example code from both theta_connection.dart and test/theta_connection.dartfiles.

library theta_connection

part of

Create a new file to hold the first method of your new package.  I’ve called my file protocols/test_hello.dart.

The key learning point for this file is to learn how to include part of '../theta_connection.dart' to the top of the file. This is the connection point from each file in your package to the main package file and will later allow your application to access the method.

test_hello.dart

part

In addition to connecting the file with the method to theta_connection.dart, you also need to add a connection from theta_connection.dart to protocols/test_hello.dart

part 'protocols/test_hello.dart'

Congratulations, you’ve just created a custom package!

Review of Steps

  1. Create a package with flutter create --template=package name.
  2. Create a new file for your package functionality and link it to the main package file with part of.
  3. In the main package file, link to the new file with part.

Using Your New Package

In the pubspec.yaml file in your main project directory, add the path for your new package.

path:packages/theta_connection

 Import the package in main.dart and use it by calling the method hello().

hello() Method

When you press the button, you should see ‘Hello, world’ in the console.
Hello World in Console

Expanding Your Package

Using this technique, you can add additional directories and files to each new directory.  You can also create different packages for different types of functionality.

As your application grows, you will need to manage the state of your application.  My previous article, Flutter 2.0 State Management Introduction with Provider 5.0, explains how to manage the state of your Flutter application with the provider. 

Summary

Strong organization of your application architecture is the key to a successful project.  Failure to manage fundamental areas such as functionality and state can lead to delays and in some cases unfinished projects.  Effective use of the standard Flutter package system is a great tool to organize your application architecture.  To keep development simple, place your packages inside of your main application repository to reduce the complexity of version management for your package.  By reducing the complexity of package version management, you increase the chances that you and your team will uses packages, putting everyone on the path to a successful project launch.



Source link

How to Approach Your Next Full Stack Project for Better Resu...
Strategy

How to Approach Your Next Full Stack Project for Better Resu…


Are you a full stack developer? If you are, it goes without saying that you are an efficient multitasker and a true master of your niche. But have you ever asked yourself if your web development techniques have scope for betterment? Could your project planning use more efficiency to better your results?

If you said yes to both, read to find out how you can approach your next full stack project to yield great results.

Which part of the product do you usually start working on? No matter how simple or complex your application is, the ideal way to approach any project is to plan your process right; breaking your project down into components will help you separate the tasks and avoid chaos.

Follow these steps to get better results for your next full stack project:

Define the Scope of Your Project

Scope acts as your road map and is the path you tread during the course of your project. Make sure that your project scope is neither too narrow nor too small and is strictly objective-oriented. 

Try to answer the following questions while you define your scope:

  • Are you planning to build both the front-end and back-end of the application?
  • Do you have to account for user authentication?
  • Would you be using external APIs (Application Programming Interfaces)?

Choose Your Database

Yes, you can build a software application without a database. But such applications will certainly end up having very limited functionality. A database is indispensable to store all the data of your application, especially if it is a dynamic web application; not to mention the applications that demand data from the users.  Most applications require the personal information of users such as their contact details. This makes databases an inevitable part of software development. 

Ask yourself these questions when you decide on which database to use:

  • What database will suit you the best?
  • What models will you require to finish your project?
  • If you stick to a relational database, how will you define the relationships between various models?
  • If you pick MongoDB, do you have a cluster at your disposal to put your collection in?

Plan Your API Endpoints

Make sure you have a fair understanding of why you need an API and how your users will find them helpful. This should give you an idea of how to go about planning your API endpoints. Since APIs work on requests and responses, the overall performance depends on how effective the communication points or endpoints are; this is why endpoint planning is of paramount importance.  

Here are some key questions that you should address:

  • What technologies are you planning to integrate with the API?
  • Who is your target audience?
  • Which product or service do you want the user to work with?
  • How many endpoints will be public or protected?
  • Will you use API to handle all the queries?

Build Your Backend

Here are some pro tips to build your backend effectively:

  • Choose the right language and framework for your application. Make sure you are comfortable using them.
  • Do not forget to implement user authorization. For user authentication and authorization, use Session Tokens, OAuth, JSON Web Tokens, etc.
  • Set up notification microservice that provides push notifications, emails, and SMS to users. Use separate channels for sending transactional and promotional SMS. 
  • Create a base model that you can later use for every other model in the database.
  • Set up asynchronous communication so that users do not have to waste their time as the application sends out welcome emails.

Test Your Backend 

Back-end testing is referred to the testing of the database, the server, and the APIs. It helps you fix bugs quickly and avoid deadlocks. With effective back-end testing, you can make sure you don’t incur data loss or and address all performance issues. Data Factory, TOAD, and phpMyAdmin are some of the best back-end testing tools.

  • Use white-box testing instead of back-box testing.
  • Use realistic data instead of mock data to spot bugs and to reduce cost.
  • Focus on effective team communication.

Build Your Frontend

    Here are some tips to build frontend like a pro:        

  • Use professional graphic tools to get a full picture of your application. Rather than sticking to designing from your code, launch graphic programs to see how your product will look.
  • Research well on typography, good fonts can complement the design; try different combinations till you find the right match.
  • Give due consideration to design relationships and hierarchy.
  • Build rapport with your designers; this will help you get quality feedback and enhance your product’s quality.

Test Your Frontend 

Frontend testing gives the boost you need to deploy your product. This phase is also helpful in determining your browser and OS. 

Here are some useful tips to test your front-end:

  • Use a headless browser for faster testing.
  • Separate your test cases so that identifying and fixing bugs becomes easy.
  • Make reusable test scripts.
  • Be consistent with your naming convention in test scripts.
  • Use your time, resources, and budget wisely.

Do Your Final User Testing 

User testing is a fundamental part of the UX design process. Here are some points to consider. Here are some tips for you to perform user testing efficiently:

  • Do not procrastinate on your testing. The earlier you do it, the easier it will be to fix issues.
  • Investigate if the users can complete tasks such as purchasing a product successfully.
  • Find out if the users are satisfied with the product; identify areas of improvement.
  • Prioritize your tasks in your testing checklist; set a goal for each of them.
  • Make sure that the people who participate in your test represent your target audience.

If you are a full stack developer, you always have proactive control over the quality of the end product. With the suggestions and tips mentioned in the article, you can now easily get desired results as well.



Source link

Binary Demo
Strategy

What Are Floating-point Numbers? – DZone Web Dev


(originally posted to the BaseClass newsletter.)

Why Should I Care?

Have you ever wanted to know:

  • Why 0.1 + 0.3 does not always equal 0.4?
  • How we store non-integer numbers in binary?

In 5 Minutes or Less:

You may be familiar with how we represent a number in binary.

Each bit represents a power of 2, and by combining them we can produce every whole number:

Binary Demo

But what happens when we need to represent something that isn’t an integer, like 2.5?

Let’s split the 8 bits in half.

We’ll use the ‘left’ half to represent the number before the decimal point (2 in our example), and the ‘right’ half to represent the fraction after the decimal point (0.5, or ½ in this case).

In this system, 2.5 would be represented as 0 0 1 0 1 0 0 0:

2.5 Represented in Binary

We can represent fractions now, but we’ve lost a lot of range.

We can’t represent 16.0 in this format, for example. There just aren’t enough bits on the left of the point.

We could just keep adding more bits to store larger numbers, but this format is still quite limited.

Sometimes we want to store very large numbers, in which case we’d like more bits on the left. Other times, we’d like to store very small fractions, in which case we would need fewer bits on the left and more precision on the right.

This is what floating-point is; a way of storing numbers that allows the point to move to represent a larger range of values.

The standard for float values is called ‘IEEE 754’, which defines both 32 and 64-bit floating-point (or ‘float’) values.

Each 32 or 64-bit float is split into 3 sections.

  • The first bit represents the ‘sign’; 0 for a positive number, or 1 for a negative number.
  • The next 8 bits are called the ‘Exponent.’
  • The final 23 bits are the ‘Mantissa.’

We use these 3 values in a formula, which gives us the number that the float represents:

Represented in 32-bit

You don’t need to understand this formula, just know that this way of storing numbers means we can represent a much larger range.

By making the ‘exponent’ value larger or smaller we can represent very small fractions or very large numbers.

That’s why it’s called ‘floating-point,’ it doesn’t have a fixed point like our original example. Instead, the point ‘floats’, or moves, depending on the size of the ‘exponent.’

Rounding Errors

There are some numbers we can’t represent exactly using our standard decimal system.

For example, we can’t represent ⅓ exactly in decimal:

⅓ = 0.3333333...

This is also true of some numbers in binary; they cannot be represented exactly.

For example, let’s try to represent 0.1 in binary.

Again, the values after the decimal point represent the fractions:

0.1 in Binary

This is very close to 0.1 – and it’s the best we can do in this example – but it is not exactly 0.1.

The fact that our point can ‘move’ means that we can add more precision to this fraction if we like, but the fact remains that we just cannot represent some numbers exactly in binary.

This can lead to some interesting rounding errors.

If you try to calculate 0.2 + 0.1 in JavaScript, you’ll get an answer of 0.30000000000000004:

0.1 + 0.2 in JavaScript

This is very close to the correct answer, but it’s not exactly the correct answer.

With this in mind, we usually compare floating-point numbers by checking the difference between them.

For example, instead of checking whether two numbers are equal, we would check that the difference between them is very small.

Math.abs(result1 - result2) < 0.001

This is a simplified example, of course. In reality, you would choose a tolerance appropriate to the calculation you are doing.

Want to Know More?

Check out these links:



Source link