Thursday, September 21, 2017

How to Publish Responsive Websites with Sketch and Launchpad

Anima have built two super-useful Sketch Plugins. Auto Layout helps designers create responsive layouts in Sketch, and Launchpad exports the responsive design as a near-finished HTML/CSS website with decent code quality. TL;DR — watch the video...

"Wait…another site builder? Really?"

Well, Launchpad is more of an HTML/CSS exporter with some impressive features. It's not your typical WYSIWYG editor, since you're actually doing the design work in Sketch, a top-notch user interface design tool. You still need a developer who can take the 4-star code output and turn it into a 5-star website, but it will nonetheless save you huge amounts of time. Here's what Launchpad can actually do:

  • Responsive design (if combined with Auto Layout)
  • Videos, links and forms
  • Font-family fallbacks
  • Publishing, hosting and domains
  • SEO (title, meta description, etc)
  • Social media meta tags (Open Graph, etc)
  • Version control
  • Google Analytics (or similar) integration
  • Keyboard-centric workflow (very Sketch-like!)

Here's what you need to do manually, with code, afterward:

  1. Insert custom meta tags, if any
  2. Insert any Schema markup, if needed
  3. Refine the adaptive/responsive qualities, if required
  4. Code any JavaScript needed
  5. Code any backend functionality
  6. Minification and other web perf tricks

Launchpad offers you the tools to build a static website, a foundation that you can build upon. It'll save you countless hours of your valuable time, but it won't take you to the finish line. This is a good thing because little code optimisations have a big impact on SEO and conversions, so these are the things you'll want to do manually.

Let's learn how to use it!

Make sure you've downloaded Launchpad first. Don't worry about Auto Layout, because it's automatically bundled into Launchpad now. We have Lots to cover, but I'll keep it brief!

Responsive Design with Sketch and Auto Layout

First, let's float a Group of layers/objects to the top-right corner of the parent container (which in this case is the Artboard itself). Open the "Pin" dropdown in the Auto Layout tab in the Inspector, and check both the top and right checkboxes (or click on the dots on the visual representation).

Also, ensure that the offset (from the Artboard) is "17px" on both sides (top and right), and hit the "W" checkbox to declare the Group as having a fixed-width (otherwise, when the container/Artboard is resized, the responsive object will be squashed up as if declared as being a % of the container).

For the HTML/CSS developer guys out there, "pinning" can mimic floated elements (float:left or float:right) or positioned elements (position:fixed or position:absolute) combined with top: right: bottom: or left:.

Responsive design with Auto Layout

Here's how it looks when resized (notice how the other elements are getting squashed up, but our pinned elements are remaining fixed to the top-right corner of the Artboard):

Responsive testing with Sketch and Launchpad

What else can Auto Layout do?

Pinning is the tip of the iceberg. Auto Layout also helps you:

  • Align objects vertically/horizontally
  • Declare an objects' width (and min/max-width) in % or px
  • Define an offset in % or px
  • Rapidly switch between "Portrait" and "Landscape" for testing
  • Switch to another Artboard Preset for testing in other devices
  • Navigate using a visual diagram or traditional checkbox UI
  • Create "Stacks", the Sketch equivalent of flexbox

As mentioned above, these layout options translate to CSS when exported with Launchpad (yes, even the flexbox/Stack settings). Have a play around with it. It's super-straightforward, so you won't have any trouble learning how to align objects or switch between the different device Artboards and orientations.

Links

Each Artboard is basically a webpage, so linking up screens is easy.

Let's set the homepage first.

Set Homepage

Just underneath the Launchpad heading in the Inspector, click the icon and select the "Set as Home" option. Pretty simple stuff so far—we'll work up to the complex stuff.

Set homepage in Launchpad

Create Link

Now select a layer on the canvas (which is to be a link to another Artboard/webpage), and click the Create Link icon (which resembles two Artboards that are linked by a line).

Next, click on the desired destination Artboard to establish the link (you may have to zoom out if the Artboard isn't visible, like in the screenshot below). Alternatively, you can choose the "EXTERNAL LINK" or "SET AS HOME" options, which link to external websites and whatever the homepage Artboard is, respectively.

Create link in Launchpad

Videos

Video has various uses, but since they're not something we'd typically include on all websites (because they do take a while to load), it's easy to forget their HTML markup.

Besides, some videos use the <video> tag, whereas others, like YouTube videos, are embeddable using an <iframe>. Depending on where you're embedding the video from, there are additional options like "Auto Play", "Loop", "No Controls" and "Cover". YouTube videos are quite restrictive, so Loop is the only customisable option; however, if you used a service like Giphy, you could convert and embed YouTube videos (or upload your own) as GIFs and HTML5 videos, depending on the sort of functionality you need to offer (HTML5 video, for example, would be embeddable as a background).

Embed videos by select on a shape on the canvas, then by clicking on the box icon in the Inspector, choosing "Video Player", then pasting the video URL into the field.

Embed video in Launchpad

Forms

Forms are broken down into two sections: the various input fields and the submit buttons. We'll start with input fields.

Hit the box icon once more, then "Forms", then "Text Input".

Done, simple! When converted to a static website, this element will be an input field (<input type="text" value="value">).

Create input field in Launchpad

Next, submit buttons—repeat the steps, but select "Submit Button" this time. Now it's important to bare in mind that Launchpad does not create dynamic websites (as mentioned earlier), so JavaScript functionality is disabled. Form functionality is catered towards contact forms, hence the first customisable option is "Email to"—this is where the form data (as specified in the text layer/input field) will be sent to.

You can also specify two Artboards where the user may be sent to upon making a mistake in the form, or successfully completing it. Naturally, you'll be responsible for coding up the form validation after Launchpad has exported the website; as discussed, Launchpad delivers the barebones HTML/CSS, so it's up to you (or a developer) to take this to the finish line.

Create submit button in Launchpad

Hover Effects

… icon → "Hover Effects".

So this feature is pretty much about CSS transitions. What I like about this feature is that there are a range of transitions that you can click-and-apply (move left, move right, …, rotate, grow, shrink, shadow, …), and the code output will automatically display in the edit-field for you to customise to your liking.

For basic transitions like background-color animations, you can write your own CSS in this field. Either way, you'll end this step by choosing the easing animation (ease-in-out, ease-in, ease-out, ease and linear) and animation duration.

Create CSS transitions in Launchpad

Fixed Positioning

… icon → "Fixed Position" does exactly what you'd assume it does. It defines fixed components (position:fixed in CSS) such as fixed headers, fixed footers, scroll-to-top buttons, live chat widgets, and other types of always-visible elements.

Create fixed elements in Launchpad

Widgets

Widgets are where things become a little more interesting (… icon → "Widgets"). Straight away you'll notice that the following widgets are available to embed into your site:

  • Crisp.im (live chat)
  • Usersnap (collect user feedback)
  • Juicer.io (social media feeds)
  • Gumroad (embeddable buy buttons)
  • HubSpot (inbound marketing)
  • Marketo (marketing automation)
  • Mailchimp (for collecting subscribers)
  • Google Analytics (website analytics)
  • Google Maps (embeddable maps)
  • Statcounter (alternative to Google Analytics)
  • Pinterest (embed Pinboards)
  • Open Table (table reservation widget)
  • Zendesk (customer support)
  • More coming soon!

Continue reading %How to Publish Responsive Websites with Sketch and Launchpad%


by Daniel Schwarz via SitePoint

Beautiful Interactions

Long-scrolling One Pager featuring on-trend colorful gradients and drop shadows for digital studio ’Beautiful Interactions’.

Full Review | Direct Link


by Rob Hope @robhope via One Page Love

An Introduction to ETS Tables in Elixir

When crafting an Elixir program, you often need to share a state. For example, in one of my previous articles I showed how to code a server to perform various calculations and keep the result in memory (and later we've seen how to make this server bullet-proof with the help of supervisors). There is a problem, however: if you have a single process that takes care of the state and many other processes that access it, the performance may be seriously affected. This is simply because the process can serve only one request at a time. 

However, there are ways to overcome this problem, and today we are going to talk about one of them. Meet Erlang Term Storage tables or simply ETS tables, a fast in-memory storage that can host tuples of arbitrary data. As the name implies, these tables were initially introduced in Erlang but, as with any other Erlang module, we can easily use them in Elixir as well.

In this article you will:

  • Learn how to create ETS tables and options available upon creation.
  • Learn how to perform read, write, delete and some other operations.
  • See ETS tables in action.
  • Learn about disk-based ETS tables and how they differ from in-memory tables.
  • See how to convert ETS and DETS back and forth.

All code examples work with both Elixir 1.4 and 1.5, which was recently released.

Introduction to ETS Tables

As I mentioned earlier, ETS tables are in-memory storage that contain tuples of data (called rows). Multiple processes may access the table by its id or a name represented as an atom and perform read, write, delete and other operations. ETS tables are created by a separate process, so if this process is terminated, the table is destroyed. However, there is no automatic garbage collection mechanism, so the table may hang out in the memory for quite some time.

Data in the ETS table are represented by a tuple {:key, value1, value2, valuen}. You can easily look up the data by its key or insert a new row, but by default there can't be two rows with the same key. Key-based operations are very fast, but if for some reason you need to produce a list from an ETS table and, say, perform complex manipulations of the data, that's possible too.

What's more, there are disk-based ETS tables available that store their contents in a file. Of course, they operate slower, but this way you get a simple file storage without any hassle. On top of that, in-memory ETS can be easily converted to disk-based and vice versa.

So, I think it's time to start our journey and see how the ETS tables are created!

Creating an ETS Table

To create an ETS table, employ the new/2 function. As long as we are using an Erlang module, its name should be written as an atom:

Note that until recently you could only create up to 1,400 tables per BEAM instance, but this is not the case anymore—you are only limited to the amount of available memory.

The first argument passed to the new function is the table's name (alias), whereas the second one contains a list of options. The cool_table variable now contains a number that identifies the table in the system:

You may now use this variable to perform subsequent operations to the table (read and write data, for example).

Available Options

Let's talk about the options that you may specify when creating a table. The first (and somewhat strange) thing to note is that by default you cannot use the table's alias in any way, and basically it has no effect. But still, the alias must be passed upon the table's creation.

To be able to access the table by its alias, you must provide a :named_table option like this:

By the way, if you'd like to rename the table, it can be done using the rename/2 function:

Next, as already mentioned, a table cannot contain multiple rows with the same key, and this is dictated by the type. There are four possible table types:

  • :set—that's the default one. It means that you can't have multiple rows with exactly the same keys. The rows are not being re-ordered in any particular manner.
  • :ordered_set—the same as :set, but the rows are ordered by the terms.
  • :bag—multiple rows may have the same key, but the rows still cannot be fully identical.
  • :duplicate_bag—rows can be fully identical.

There is one thing worth mentioning regarding the :ordered_set tables. As Erlang's documentation says, these tables treat keys as equal when they compare equal, not only when they match. What does that mean?

Two terms in Erlang match only if they have the same value and the same type. So integer 1 matches only another integer 1, but not float 1.0 as they have different types. Two terms are compare equal, however, if either they have the same value and type or if both of them are numerics and extend to the same value. This means that 1 and 1.0 are compare equal.

To provide the table's type, simply add an element to the list of options:

Another interesting option that you can pass is :compressed. It means that the data inside the table (but not the keys) will be—guess what—stored in a compact form. Of course, the operations that are executed upon the table will become slower.

Next up, you can control which element in the tuple should be used as the key. By default, the first element (position 1) is used, but this can be changed easily:

Now the second elements in the tuples will be treated as the keys.

The last but not the least option controls the table's access rights. These rights dictate what processes are able to access the table:

  • :public—any process can perform any operation to the table.
  • :protected—the default value. Only the owner process can write to the table, but all the processes can read.
  • :private—only the owner process can access the table.

So, to make a table private, you would write:

Alright, enough talking about options—let's see some common operations that you can perform to the tables!

Write Operations

In order to read something from the table, you first need to write some data there, so let's start with the latter operation. Use the insert/2 function to put data into the table:

You may also pass a list of tuples like this:

Note that if the table has a type of :set and a new key matches an existing one, the old data will be overwritten. Similarly, if a table has a type of :ordered_set and a new key compares equal to the old one, the data will be overwritten, so pay attention to this.

The insert operation (even with multiple tuples at once) is guaranteed to be atomic and isolated, which means that either everything is stored in the table or nothing at all. Also, other processes won't be able to see the intermediate result of the operation. All in all, this is pretty similar to SQL transactions.

If you are concerned about duplicating keys or do not want to overwrite your data by mistake, use the insert_new/2 function instead. It is similar to insert/2 but will never insert duplicating keys and will instead return false. This is the case for the :bag and :duplicate_bag tables as well:

If you provide a list of tuples, each key will be checked, and the operation will be cancelled even if one of the keys is duplicated.

Read Operations

Great, now we have some data in our table—how do we fetch them? The easiest way is to perform lookup by a key:

Remember that for the :ordered_set table, the key should compare equal to the provided value. For all other table types, it should match. Also, if a table is a :bag or an :ordered_bag, the lookup/2 function may return a list with multiple elements:

Instead of fetching a list, you may grab an element in the desired position using the lookup_element/3 function:

In this code, we are getting the row under the key :number and then taking the element in the second position. It also works perfectly with :bag or :duplicate_bag:

If you would like to simply check if some key is present in the table, use member/2, which returns either true or false:

You may also get the first or the last key in a table by using first/1 and last/1 respectively:

On top of that, it is possible to determine the previous or the next key based on the provided one. If such a key cannot be found, :"$end_of_table" will be returned:

Note, however, that the table traversal using functions like first, next, last or prev is not isolated. It means that a process may remove or add more data to the table while you are iterating over it. One way to overcome this issue is by using safe_fixtable/2, which fixes the table and ensures that each element will be fetched only once. The table remains fixed unless the process releases it:

Lastly, if you'd like to find an element in the table and remove it, employ the take/2 function:

Delete Operations

Okay, so now let's say you no longer need the table and wish to get rid of it. Use delete/1 for that:

Of course, you may delete a row (or multiple rows) by its key as well:

To clear out the entire table, utilize delete_all_objects/1:

And, lastly, to find and remove a specific object, use delete_object/2:

Converting the Table

An ETS table can be converted to a list anytime by using the tab2list/1 function:

Remember, however, that fetching the data from the table by the keys is a very fast operation, and you should stick to it if possible.

You may also dump your table to a file using tab2file/2:

Note that the second argument should be a charlist (a single-quoted string).

There are a handful of other operations available that can be applied to the ETS tables, and of course we are not going to discuss them all. I really recommend skimming through the Erlang documentation on ETS to learn more.

Persisting the State With ETS

To summarize the facts that we have learned so far, let's modify a simple program that I have presented in my article about GenServer. This is a module called CalcServer that allows you to perform various calculations by sending requests to the server or fetching the result:

Currently our server doesn't support all mathematical operations, but you may extend it as needed. Also, my other article explains how to convert this module to an application and take advantage of supervisors to take care of the server crashes.

What I'd like to do now is add another feature: the ability to log all the mathematical operations that were performed along with the passed argument. These operations will be stored in an ETS table so that we will be able to fetch it later.

First of all, modify the init function so that a new named private table with a type of :duplicate_bag is created. We are using :duplicate_bag because two identical operations with the same argument may be performed:

Now tweak the handle_cast callback so that it logs the requested operation, prepares a formula, and then performs the actual computation:

Here is the prepare_and_log private function:

We are logging the operation right away (the corresponding function will be presented in a moment). Then return the appropriate function or nil if we don't know how to handle the operation.

As for the log function, we should either support a tuple (containing both the operation's name and the argument) or an atom (containing only the operation's name, for example, :sqrt):

Next, the calculate function, which either returns a proper result or a stop message:

Finally, let's present a new interface function to fetch all the performed operations by their type:

Handle the call:

And perform the actual lookup:

Now test everything:

The result is correct because we have performed two :add operations with the arguments 1 and 2. Of course, you may further extend this program as you see fit. Still, don't abuse ETS tables, and employ them when it is really going to boost the performance—in many cases, using immutables is a better solution.

Disk ETS

Before wrapping up this article, I wanted to say a couple of words about disk-based ETS tables or simply DETS

DETS are pretty similar to ETS: they use tables to store various data in the form of tuples. The difference, as you've guessed, is that they rely on file storage instead of memory and have fewer features. DETS have functions similar to the ones we discussed above, but some operations are performed a bit differently.

To open a table, you need to use either open_file/1 or open_file/2—there is no new/2 function like in the :ets module. Since we don't have any existing table yet, let's stick to open_file/2, which is going to create a new file for us:

The filename is equal to the table's name by default, but this can be changed. The second argument passed to the open_file is the list of options written in the form of tuples. There are a handful of available options like :access or :auto_save. For instance, to change a filename, use the following option:

Note that there is also a :type option that may have one of the following values:

  • :set
  • :bag
  • :duplicate_bag

These types are the same as for the ETS. Note that DETS cannot have a type of :ordered_set.

There is no :named_table option, so you can always use the table's name to access it.

Another thing worth mentioning is that the DETS tables must be properly closed:

If you don't do this, the table will be repaired the next time it is opened.

You perform read and write operations just like you did with ETS:

Bear in mind, though, that DETS are slower than ETS because Elixir will need to access the disk which, of course, takes more time.

Note that you may convert ETS and DETS tables back and forth with ease. For example, let's use to_ets/2 and copy the contents of our DETS table in-memory:

Copy the ETS's contents to DETS using to_dets/2:

To sum up, disk-based ETS is a simple way to store contents in the file, but this module is slightly less powerful than ETS, and the operations are slower as well.

Conclusion

In this article, we have talked about ETS and disk-based ETS tables that allow us to store arbitrary terms in memory and in files respectively. We have seen how to create such tables, what the available types are, how to perform read and write operations, how to destroy tables, and how to convert them to other types. You may find more information about ETS in the Elixir guide and on the Erlang official page.

Once again, don't overuse ETS tables, and try to stick with immutables if possible. In some cases, however, ETS may be a nice performance boost, so knowing about this solution is helpful in any case. 

Hopefully, you've enjoyed this article. As always, thank you for staying with me, and see you really soon!


by Ilya Bodrov via Envato Tuts+ Code

Create Interactive Charts Using Plotly.js, Part 4: Bubble and Dot Charts

So far in the series, you have learned how to create line charts and bar charts in Plotly.js. As I mentioned in the introductory tutorial of the series, Plotly.js is not limited to just a few chart types. There are more than 20 different kinds of charts that you can create using the library. Each of these chart types has its own set of customization options as well as attributes that are common to multiple charts.

In this tutorial, you will learn how to create bubble and dot plot charts in Plotly.js. Both these chart types use the same scatter traces that we used while creating line charts. The important difference this time is that the mode attribute will be set to markers.

Creating Bubble Charts in Plotly.js

Bubble charts are used to display three dimensions of data on a chart. The data associated with every entity is plotted using bubbles or disks, where the position of a disk on the x-y axis marks its x-y values, and the area of a disk is used to plot the value of the third data point. Bubble charts are a variation of scatter charts. For this reason, it makes sense to set the type attribute to scatter while creating a bubble chart.

There are a few things that you should remember while creating bubble charts. First, the third value of a given data point is represented by the area of the bubble and not its radius. The radius is actually proportional to the square root of the actual value. Second, you can only use them to plot positive values. This makes sense because the area of a bubble cannot be negative or zero.

Now, let's create our first bubble chart by setting the mode attribute to markers. All the attributes that control the appearance of bubbles in the chart are present under the marker object. The size attribute of the marker object can be used to specify a size for the bubbles as the third data point. This attribute can either be a number or an array of numbers. When creating bubble charts, it would be very rare for all the entities to have the same value for their third data point. So you will generally set the size attribute as an array.

The opacity of all the bubbles can be controlled using the opacity attribute. Just like size, this attribute also accepts values as a number or an array or numbers with values between 0 and 1. In the case of line charts, the default value of opacity for different bubbles or disks was 1. In the case of bubble charts, the default value of opacity becomes 0.7.

Another very useful attribute that you can use to accurately create bubble charts is the sizemode parameter. This attribute determines if the value specified in the size attribute should be considered the area of a bubble or its diameter. The default value for sizemode is diameter. However, if you are creating bubble charts, it makes more sense to set the value of sizemode to area. This way, you won't have to do any calculations to determine the right bubble size for a value yourself. You can use the following code to create a bubble chart using the parameters we just discussed.

Right now, every bubble has the same color. The color of individual bubbles or the whole trace can be changed at once using the color attribute.

Another way to set the color of different bubbles is using color bars. In such cases, the bubble color is determined based on the numeric value specified in the array that you passed to the color attribute of marker object. This color bar can act as the fourth data point when plotting a chart. 

For example, let's say you are plotting a bubble chart that shows the location and area of different parks in a large city. A bubble chart would be perfect in this situation. However, the tree density of each park or the average number of people that visit each park can be different. If the color of each bubble is specified as a numerical value, it will be possible to assign a different color to individual bubbles to plot the value of the fourth data point.

In our example, the color corresponding to different magnitudes of tree density can be specified using the colorscale attribute. When using this attribute, you are required to at least specify a mapping for the lowest (0) as well as highest (1) values. An example of a valid colorscale value is [[0, 'rgb(0, 0, 0)'], [1, 'rgb(0, 255, 0)']]. You also have the option to use a palette name string as a colorscale value. Greys, YlGnBu, Greens, YlOrRd, Bluered, RdBu, Reds, Blues, Picnic, Rainbow, Portland, Jet, Hot, Blackbody, Earth, Electric, and Viridis are all considered valid values.

You can specify the lowest numerical color value to which the lowest color scale value should be mapped using the cmin attribute. Similarly, you can also specify the highest color value to which the highest color scale value should be mapped using the cmax attribute. It is possible to reverse the color mapping by setting the value of the reversescale parameter to true. In this case, the lowest color will be mapped to the highest value, and the highest color will be mapped to the lowest value.

The colorbar object provides a lot of parameters that can be used to control its appearance. The width of the color bar created by Plotly.js can be controlled using the thickness parameter. The thickness is specified in pixels, and its default value is 30. The length of the color bar, excluding the padding on both ends, can be specified using the len attribute. The x and y position of the color bar can be set with the help of the x and y parameters. The position is specified in terms of plot fractions, and its valid value can lie anywhere between -2 and 3. The default value for x is 1.02, and the default value for y is 0.5. The x and y padding of the color bar can be controlled similarly using the xpad and ypad parameters. You can assign a title to the color bar using the title attribute. The position of that title can be specified with respect to the color bar using the titleside parameter. Valid values for this parameter are top, bottom, and right. The default value is top.

The following code will create a bubble chart where the darkness of the green color is mapped to the tree density in that park.

Creating a Dot Plot in Plotly.js

A dot plot is a chart that is used to plot points on a very simple scale. You should keep in mind that dot plots are only suitable for a small amount of data. Plotting a large number of points will make the chart very cluttered. Just like bubble charts, a dot plot also requires you to set the type attribute to scatter and the mode attribute to markers. Since dot plots also use markers to plot a point, all the customization options for them are also available under the marker object.

The following code creates a dot plot that shows the marks obtained by top two students in an exam every year. I have also used some other attributes related to the legend and the x-axis to change the overall appearance of our plot.

We have already covered the different attributes of the marker object in the previous section. This time, I have made some changes in the layout of the chart. Using the title attribute to assign a title to your chart will make it more informative by quickly letting the viewers know what the chart is about. I have also changed the appearance of the x-axis line to make it stand out from other lines. As you can see, the width and color of the ticks can be controlled using the tickcolor and tickwidth attributes.

The position of the legend can be specified using the x and y attributes. Both these numbers accept a value between -2 and 3. The position is specified in terms of fractions. The anchor point for the x and y positions can be specified using the xanchor and yanchor attributes. These two attributes determine the points which should be used as a reference to measure the distance specified by the x and y attributes. In the above example, the 0.5 distance of the x attribute is measured from the center of the legend because xanchor has been set to center.

Final Thoughts

This tutorial showed you how to create bubble charts and dot plots in Plotly.js using the attributes of the same marker object. You also learned how to add extra information to your bubble charts using color bars and set the color scale of those bars according to your own requirements. 

I have tried to cover almost all the marker attributes that you might have to use in your projects. If you need to know more about creating bubble and dot plot charts, you can head to the marker reference section of the Plotly.js website. In the next tutorial, you will learn how to create pie and gauge charts in Plotly.js.

If you have any questions related to this tutorial, feel free to let me know in the comments.


by Monty Shokeen via Envato Tuts+ Code

WhatsApp Tricks that EVERYONE should be using! [video]

Whatsapp Tricks / Hacks in 2017 - Everyone should be trying these Whatsapp tips, tricks and hidden features on Android. This includes other Android Apps that improve Whatsapp.

[ This is a content summary only. Visit our website http://ift.tt/1b4YgHQ for full links, other content, and more! ]

by Web Desk via Digital Information World

Kotlin From Scratch: Advanced Functions

How to Use Facebook Audience Optimization for Better Organic Exposure

Want to increase your Facebook news feed exposure? Looking for a solution that doesn’t involve ads? In this article, you’ll discover how to improve your organic visibility via Facebook’s Audience Optimization feature. Why Use Organic Post Targeting? Facebook gives businesses access to a large global audience, but the platform is becoming increasingly saturated with branded [...]

This post How to Use Facebook Audience Optimization for Better Organic Exposure first appeared on .
- Your Guide to the Social Media Jungle


by Anja Skrba via