Collective #524

Inspirational Website of the Week: Kubikfoto³ A great design with wonderful details and smooth transitions. Our pick this week. Get inspired This content is sponsored via Syndicate Ads Website Builder Software With Your Branding This B2B platform fits designers, freelancers, agencies and anyone who Read more

Creating Your Own React Validation Library: The Basics (Part 1)

dreamt up by webguru in Uncategorized | Comments Off on Creating Your Own React Validation Library: The Basics (Part 1)

Creating Your Own React Validation Library: The Basics (Part 1)

Creating Your Own React Validation Library: The Basics (Part 1)

Kristofer Selbekk



I’ve always thought form validation libraries were pretty cool. I know, it’s a niche interest to have — but we use them so much! At least in my job — most of what I do is constructing more or less complex forms with validation rules that depend on earlier choices and paths. Understanding how a form validation library would work is paramount.

Last year, I wrote one such form validation library. I named it “Calidation”, and you can read the introductory blog post here. It’s a good library that offers a lot of flexibility and uses a slightly different approach than the other ones on the market. There are tons of other great libraries out there too, though — mine just worked well for our requirements.

Today, I’m going to show you how to write your very own validation library for React. We will go through the process step by step, and you’ll find CodeSandbox examples as we go along. By the end of this article, you will know how to write your own validation library, or at the very least have a deeper understanding of how other libraries implement “the magic of validation”.

  • Part 1: The Basics
  • Part 2: The Features
  • Part 3: The Experience

Step 1: Designing The API

The first step of creating any library is designing how it’s going to be used. It lays the foundation for a lot of the work to come, and in my opinion, it’s the single most important decision you’re going to make in your library.

It’s important to create an API that’s “easy to use”, and yet flexible enough to allow for future improvements and advanced use cases. We’ll try to hit both of these goals.

We’re going to create a custom hook that will accept a single configuration object. This will allow for future options to be passed without introducing breaking changes.

A Note On Hooks

Hooks is a pretty new way of writing React. If you’ve written React in the past, you might not recognize a few of these concepts. In that case, please have a look at the official documentation. It’s incredibly well written, and takes you through the basics you need to know.

We’re going to call our custom hook useValidation for now. Its usage might look something like this:

const config = {
  fields: {
    username: {
      isRequired: { message: 'Please fill out a username' },
    },
    password: {
      isRequired: { message: 'Please fill out a password' },
      isMinLength: { value: 6, message: 'Please make it more secure' }
    }
  },
  onSubmit: e => { /* handle submit */ }
};
const { getFieldProps, getFormProps, errors } = useValidation(config);

The config object accepts a fields prop, which sets up the validation rules for each field. In addition, it accepts a callback for when the form submits.

The fields object contains a key for each field we want to validate. Each field has its own config, where each key is a validator name, and each value is a configuration property for that validator. Another way of writing the same would be:

{
  fields: {
    fieldName: {
      oneValidator: { validatorRule: 'validator value' },
      anotherValidator: { errorMessage: 'something is not as it should' }
    }
  }
}

Our useValidation hook will return an object with a few properties — getFieldProps, getFormProps and errors. The two first functions are what Kent C. Dodds calls “prop getters” (see here for a great article on those), and is used to get the relevant props for a given form field or form tag. The errors prop is an object with any error messages, keyed per field.

This usage would look like this:

const config = { ... }; // like above
const LoginForm = props => {
  const { getFieldProps, getFormProps, errors } = useValidation(config);
  return (
    <form {...getFormProps()}>
      <label>
        Username<br/>
        <input {...getFieldProps('username')} />
        {errors.username && 
{errors.username}
} </label> <label> Password<br/> <input {...getFieldProps('password')} /> {errors.password &&
{errors.password}
} </label> <button type="submit">Submit my form</button> </form> ); };

Alrighty! So we’ve nailed the API.

Note that we’ve created a mock implementation of the useValidation hook as well. For now, it’s just returning an object with the objects and functions we require to be there, so we don’t break our sample implementation.

Storing The Form State 💾

The first thing we need to do is storing all of the form state in our custom hook. We need to remember the values of each field, any error messages and whether or not the form has been submitted. We’ll use the useReducer hook for this since it allows for the most flexibility (and less boilerplate). If you’ve ever used Redux, you’ll see some familiar concepts — and if not, we’ll explain as we go along! We’ll start off by writing a reducer, which is passed to the useReducer hook:

const initialState = {
  values: {},
  errors: {},
  submitted: false,
};

function validationReducer(state, action) {
  switch(action.type) {
    case 'change': 
      const values = { ...state.values, ...action.payload };
      return { 
        ...state, 
        values,
      };
    case 'submit': 
      return { ...state, submitted: true };
    default: 
      throw new Error('Unknown action type');
  }
}

What’s A Reducer? 🤔

A reducer is a function that accepts an object of values and an “action” and returns an augmented version of the values object.

Actions are plain JavaScript objects with a type property. We’re using a switch statement to handle each possible action type.

The “object of values” is often referred to as state, and in our case, it’s the state of our validation logic.

Our state consists of three pieces of data — values (the current values of our form fields), errors (the current set of error messages) and a flag isSubmitted indicating whether or not our form has been submitted at least once.

In order to store our form state, we need to implement a few parts of our useValidation hook. When we call our getFieldProps method, we need to return an object with the value of that field, a change-handler for when it changes, and a name prop to track which field is which.

function validationReducer(state, action) {
  // Like above
}

const initialState = { /* like above */ };

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);
  
  return {
    errors: state.errors,
    getFormProps: e => {},
    getFieldProps: fieldName => ({
      onChange: e => {
        if (!config.fields[fieldName]) {
          return;
        }
        dispatch({ 
          type: 'change', 
          payload: { [fieldName]: e.target.value } 
        });
      },
      name: fieldName,
      value: state.values[fieldName],
    }),
  };
};

The getFieldProps method now returns the props required for each field. When a change event is fired, we ensure that field is in our validation configuration, and then tell our reducer a change action took place. The reducer will handle the changes to the validation state.

Validating Our Form 📄

Our form validation library is looking good, but isn’t doing much in terms of validating our form values! Let’s fix that. 💪

We’re going to validate all fields on every change event. This might not sound very efficient, but in the real world applications I’ve come across, it isn’t really an issue.

Note, we’re not saying you have to show every error on every change. We’ll revisit how to show errors only when you submit or navigates away from a field, later in this article.

How To Pick Validator Functions

When it comes to validators, there are tons of libraries out there that implement all the validation methods you’d ever need. You can also write your own if you want. It’s a fun exercise!

For this project, we’re going to use a set of validators I wrote some time ago — calidators. These validators have the following API:

function isRequired(config) {
  return function(value) {
    if (value === '') {
      return config.message;
    } else {
      return null;
    }
  };
}

// or the same, but terser

const isRequired = config => value => 
    value === '' ? config.message : null;

In other words, each validator accepts a configuration object and returns a fully-configured validator. When that function is called with a value, it returns the message prop if the value is invalid, or null if it’s valid. You can look at how some of these validators are implemented by looking at the source code.

To access these validators, install the calidators package with npm install calidators.

Validate a single field

Remember the config we pass to our useValidation object? It looks like this:

{ 
  fields: {
    username: {
      isRequired: { message: 'Please fill out a username' },
    },
    password: {
      isRequired: { message: 'Please fill out a password' },
      isMinLength: { value: 6, message: 'Please make it more secure' }
    }
  },
  // more stuff
}

To simplify our implementation, let’s assume we only have a single field to validate. We’ll go through each key of the field’s configuration object, and run the validators one by one until we either find an error or are done validating.

import * as validators from 'calidators';

function validateField(fieldValue = '', fieldConfig) {
  for (let validatorName in fieldConfig) {
    const validatorConfig = fieldConfig[validatorName];
    const validator = validators[validatorName];
    const configuredValidator = validator(validatorConfig);
    const errorMessage = configuredValidator(fieldValue);

    if (errorMessage) {
      return errorMessage;
    }
  }
  return null;
}

Here, we’ve written a function validateField, which accepts the value to validate and the validator configs for that field. We loop through all of the validators, pass them the config for that validator, and run it. If we get an error message, we skip the rest of the validators and return. If not, we try the next validator.

Note: On validator APIs

If you choose different validators with different APIs (like the very popular validator.js), this part of your code might look a bit different. For brevity’s sake, however, we let that part be an exercise left to the reader.

Note: On for…in loops

Never used for...in loops before? That’s fine, this was my first time too! Basically, it iterates over the keys in an object. You can read more about them at MDN.

Validate all the fields

Now that we’ve validated one field, we should be able to validate all fields without too much trouble.

function validateField(fieldValue = '', fieldConfig) {
  // as before
}

function validateFields(fieldValues, fieldConfigs) {
  const errors = {};
  for (let fieldName in fieldConfigs) {
    const fieldConfig = fieldConfigs[fieldName];
    const fieldValue = fieldValues[fieldName];

    errors[fieldName] = validateField(fieldValue, fieldConfig);
  }
  return errors;
}

We’ve written a function validateFields that accepts all field values and the entire field config. We loop through each field name in the config and validate that field with its config object and value.

Next: Tell our reducer

Alrighty, so now we have this function that validates all of our stuff. Let’s pull it into the rest of our code!

First, we’re going to add a validate action handler to our validationReducer.

function validationReducer(state, action) {
  switch (action.type) {
    case 'change':
      // as before
    case 'submit':
      // as before
    case 'validate': 
      return { ...state, errors: action.payload };
    default:
      throw new Error('Unknown action type');
  }
}

Whenever we trigger the validate action, we replace the errors in our state with whatever was passed alongside the action.

Next up, we’re going to trigger our validation logic from a useEffect hook:

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);

  useEffect(() => {
    const errors = validateFields(state.fields, config.fields);
    dispatch({ type: 'validate', payload: errors });
  }, [state.fields, config.fields]);
  
  return {
    // as before
  };
};

This useEffect hook runs whenever either our state.fields or config.fields changes, in addition to on first mount.

Beware Of Bug 🐛

There’s a super subtle bug in the code above. We’ve specified that our useEffect hook should only re-run whenever the state.fields or config.fields change. Turns out, “change” doesn’t necessarily mean a change in value! useEffect uses Object.is to ensure equality between objects, which in turn uses reference equality. That is — if you pass a new object with the same content, it won’t be the same (since the object itself is new).

The state.fields are returned from useReducer, which guarantees us this reference equality, but our config is specified inline in our function component. That means the object is re-created on every render, which in turn will trigger the useEffect above!

To solve this, we need to use for the use-deep-compare-effect library by Kent C. Dodds. You install it with npm install use-deep-compare-effect, and replace your useEffect call with this instead. This makes sure we do a deep equality check instead of a reference equality check.

Your code will now look like this:

import useDeepCompareEffect from 'use-deep-compare-effect';

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);

  useDeepCompareEffect(() => {
    const errors = validateFields(state.fields, config.fields);
    dispatch({ type: 'validate', payload: errors });
  }, [state.fields, config.fields]);
  
  return {
    // as before
  };
};
A Note On useEffect

Turns out, useEffect is a pretty interesting function. Dan Abramov wrote a really nice, long article on the intricacies of useEffect if you’re interested in learning all there is about this hook.

Now things are starting to look like a validation library!

Handling Form Submission

The final piece of our basic form validation library is handling what happens when we submit the form. Right now, it reloads the page, and nothing happens. That’s not optimal. We want to prevent the default browser behavior when it comes to forms, and handle it ourselves instead. We place this logic inside the getFormProps prop getter function:

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);
  // as before
  return {
    getFormProps: () => ({
      onSubmit: e => {
        e.preventDefault();
        dispatch({ type: 'submit' });
        if (config.onSubmit) {
          config.onSubmit(state);
        }
      },
    }),
    // as before
  };
};

We change our getFormProps function to return an onSubmit function, that is triggered whenever the submit DOM event is triggered. We prevent the default browser behavior, dispatch an action to tell our reducer we submitted, and call the provided onSubmit callback with the entire state — if it’s provided.

Summary

We’re there! We’ve created a simple, usable and pretty cool validation library. There’s still tons of work to do before we can dominate the interwebs, though.

Stay tuned for Part 2 next week!

Smashing Editorial
(dm, il)

Source: Smashing Magazine, Creating Your Own React Validation Library: The Basics (Part 1)

Creating Your Own React Validation Library: The Basics (Part 1)

dreamt up by webguru in Uncategorized | Comments Off on Creating Your Own React Validation Library: The Basics (Part 1)

Creating Your Own React Validation Library: The Basics (Part 1)

Creating Your Own React Validation Library: The Basics (Part 1)

Kristofer Selbekk



I’ve always thought form validation libraries were pretty cool. I know, it’s a niche interest to have — but we use them so much! At least in my job — most of what I do is constructing more or less complex forms with validation rules that depend on earlier choices and paths. Understanding how a form validation library would work is paramount.

Last year, I wrote one such form validation library. I named it “Calidation”, and you can read the introductory blog post here. It’s a good library that offers a lot of flexibility and uses a slightly different approach than the other ones on the market. There are tons of other great libraries out there too, though — mine just worked well for our requirements.

Today, I’m going to show you how to write your very own validation library for React. We will go through the process step by step, and you’ll find CodeSandbox examples as we go along. By the end of this article, you will know how to write your own validation library, or at the very least have a deeper understanding of how other libraries implement “the magic of validation”.

  • Part 1: The Basics
  • Part 2: The Features
  • Part 3: The Experience

Step 1: Designing The API

The first step of creating any library is designing how it’s going to be used. It lays the foundation for a lot of the work to come, and in my opinion, it’s the single most important decision you’re going to make in your library.

It’s important to create an API that’s “easy to use”, and yet flexible enough to allow for future improvements and advanced use cases. We’ll try to hit both of these goals.

We’re going to create a custom hook that will accept a single configuration object. This will allow for future options to be passed without introducing breaking changes.

A Note On Hooks

Hooks is a pretty new way of writing React. If you’ve written React in the past, you might not recognize a few of these concepts. In that case, please have a look at the official documentation. It’s incredibly well written, and takes you through the basics you need to know.

We’re going to call our custom hook useValidation for now. Its usage might look something like this:

const config = {
  fields: {
    username: {
      isRequired: { message: 'Please fill out a username' },
    },
    password: {
      isRequired: { message: 'Please fill out a password' },
      isMinLength: { value: 6, message: 'Please make it more secure' }
    }
  },
  onSubmit: e => { /* handle submit */ }
};
const { getFieldProps, getFormProps, errors } = useValidation(config);

The config object accepts a fields prop, which sets up the validation rules for each field. In addition, it accepts a callback for when the form submits.

The fields object contains a key for each field we want to validate. Each field has its own config, where each key is a validator name, and each value is a configuration property for that validator. Another way of writing the same would be:

{
  fields: {
    fieldName: {
      oneValidator: { validatorRule: 'validator value' },
      anotherValidator: { errorMessage: 'something is not as it should' }
    }
  }
}

Our useValidation hook will return an object with a few properties — getFieldProps, getFormProps and errors. The two first functions are what Kent C. Dodds calls “prop getters” (see here for a great article on those), and is used to get the relevant props for a given form field or form tag. The errors prop is an object with any error messages, keyed per field.

This usage would look like this:

const config = { ... }; // like above
const LoginForm = props => {
  const { getFieldProps, getFormProps, errors } = useValidation(config);
  return (
    <form {...getFormProps()}>
      <label>
        Username<br/>
        <input {...getFieldProps('username')} />
        {errors.username && 
{errors.username}
} </label> <label> Password<br/> <input {...getFieldProps('password')} /> {errors.password &&
{errors.password}
} </label> <button type="submit">Submit my form</button> </form> ); };

Alrighty! So we’ve nailed the API.

Note that we’ve created a mock implementation of the useValidation hook as well. For now, it’s just returning an object with the objects and functions we require to be there, so we don’t break our sample implementation.

Storing The Form State 💾

The first thing we need to do is storing all of the form state in our custom hook. We need to remember the values of each field, any error messages and whether or not the form has been submitted. We’ll use the useReducer hook for this since it allows for the most flexibility (and less boilerplate). If you’ve ever used Redux, you’ll see some familiar concepts — and if not, we’ll explain as we go along! We’ll start off by writing a reducer, which is passed to the useReducer hook:

const initialState = {
  values: {},
  errors: {},
  submitted: false,
};

function validationReducer(state, action) {
  switch(action.type) {
    case 'change': 
      const values = { ...state.values, ...action.payload };
      return { 
        ...state, 
        values,
      };
    case 'submit': 
      return { ...state, submitted: true };
    default: 
      throw new Error('Unknown action type');
  }
}

What’s A Reducer? 🤔

A reducer is a function that accepts an object of values and an “action” and returns an augmented version of the values object.

Actions are plain JavaScript objects with a type property. We’re using a switch statement to handle each possible action type.

The “object of values” is often referred to as state, and in our case, it’s the state of our validation logic.

Our state consists of three pieces of data — values (the current values of our form fields), errors (the current set of error messages) and a flag isSubmitted indicating whether or not our form has been submitted at least once.

In order to store our form state, we need to implement a few parts of our useValidation hook. When we call our getFieldProps method, we need to return an object with the value of that field, a change-handler for when it changes, and a name prop to track which field is which.

function validationReducer(state, action) {
  // Like above
}

const initialState = { /* like above */ };

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);
  
  return {
    errors: state.errors,
    getFormProps: e => {},
    getFieldProps: fieldName => ({
      onChange: e => {
        if (!config.fields[fieldName]) {
          return;
        }
        dispatch({ 
          type: 'change', 
          payload: { [fieldName]: e.target.value } 
        });
      },
      name: fieldName,
      value: state.values[fieldName],
    }),
  };
};

The getFieldProps method now returns the props required for each field. When a change event is fired, we ensure that field is in our validation configuration, and then tell our reducer a change action took place. The reducer will handle the changes to the validation state.

Validating Our Form 📄

Our form validation library is looking good, but isn’t doing much in terms of validating our form values! Let’s fix that. 💪

We’re going to validate all fields on every change event. This might not sound very efficient, but in the real world applications I’ve come across, it isn’t really an issue.

Note, we’re not saying you have to show every error on every change. We’ll revisit how to show errors only when you submit or navigates away from a field, later in this article.

How To Pick Validator Functions

When it comes to validators, there are tons of libraries out there that implement all the validation methods you’d ever need. You can also write your own if you want. It’s a fun exercise!

For this project, we’re going to use a set of validators I wrote some time ago — calidators. These validators have the following API:

function isRequired(config) {
  return function(value) {
    if (value === '') {
      return config.message;
    } else {
      return null;
    }
  };
}

// or the same, but terser

const isRequired = config => value => 
    value === '' ? config.message : null;

In other words, each validator accepts a configuration object and returns a fully-configured validator. When that function is called with a value, it returns the message prop if the value is invalid, or null if it’s valid. You can look at how some of these validators are implemented by looking at the source code.

To access these validators, install the calidators package with npm install calidators.

Validate a single field

Remember the config we pass to our useValidation object? It looks like this:

{ 
  fields: {
    username: {
      isRequired: { message: 'Please fill out a username' },
    },
    password: {
      isRequired: { message: 'Please fill out a password' },
      isMinLength: { value: 6, message: 'Please make it more secure' }
    }
  },
  // more stuff
}

To simplify our implementation, let’s assume we only have a single field to validate. We’ll go through each key of the field’s configuration object, and run the validators one by one until we either find an error or are done validating.

import * as validators from 'calidators';

function validateField(fieldValue = '', fieldConfig) {
  for (let validatorName in fieldConfig) {
    const validatorConfig = fieldConfig[validatorName];
    const validator = validators[validatorName];
    const configuredValidator = validator(validatorConfig);
    const errorMessage = configuredValidator(fieldValue);

    if (errorMessage) {
      return errorMessage;
    }
  }
  return null;
}

Here, we’ve written a function validateField, which accepts the value to validate and the validator configs for that field. We loop through all of the validators, pass them the config for that validator, and run it. If we get an error message, we skip the rest of the validators and return. If not, we try the next validator.

Note: On validator APIs

If you choose different validators with different APIs (like the very popular validator.js), this part of your code might look a bit different. For brevity’s sake, however, we let that part be an exercise left to the reader.

Note: On for…in loops

Never used for...in loops before? That’s fine, this was my first time too! Basically, it iterates over the keys in an object. You can read more about them at MDN.

Validate all the fields

Now that we’ve validated one field, we should be able to validate all fields without too much trouble.

function validateField(fieldValue = '', fieldConfig) {
  // as before
}

function validateFields(fieldValues, fieldConfigs) {
  const errors = {};
  for (let fieldName in fieldConfigs) {
    const fieldConfig = fieldConfigs[fieldName];
    const fieldValue = fieldValues[fieldName];

    errors[fieldName] = validateField(fieldValue, fieldConfig);
  }
  return errors;
}

We’ve written a function validateFields that accepts all field values and the entire field config. We loop through each field name in the config and validate that field with its config object and value.

Next: Tell our reducer

Alrighty, so now we have this function that validates all of our stuff. Let’s pull it into the rest of our code!

First, we’re going to add a validate action handler to our validationReducer.

function validationReducer(state, action) {
  switch (action.type) {
    case 'change':
      // as before
    case 'submit':
      // as before
    case 'validate': 
      return { ...state, errors: action.payload };
    default:
      throw new Error('Unknown action type');
  }
}

Whenever we trigger the validate action, we replace the errors in our state with whatever was passed alongside the action.

Next up, we’re going to trigger our validation logic from a useEffect hook:

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);

  useEffect(() => {
    const errors = validateFields(state.fields, config.fields);
    dispatch({ type: 'validate', payload: errors });
  }, [state.fields, config.fields]);
  
  return {
    // as before
  };
};

This useEffect hook runs whenever either our state.fields or config.fields changes, in addition to on first mount.

Beware Of Bug 🐛

There’s a super subtle bug in the code above. We’ve specified that our useEffect hook should only re-run whenever the state.fields or config.fields change. Turns out, “change” doesn’t necessarily mean a change in value! useEffect uses Object.is to ensure equality between objects, which in turn uses reference equality. That is — if you pass a new object with the same content, it won’t be the same (since the object itself is new).

The state.fields are returned from useReducer, which guarantees us this reference equality, but our config is specified inline in our function component. That means the object is re-created on every render, which in turn will trigger the useEffect above!

To solve this, we need to use for the use-deep-compare-effect library by Kent C. Dodds. You install it with npm install use-deep-compare-effect, and replace your useEffect call with this instead. This makes sure we do a deep equality check instead of a reference equality check.

Your code will now look like this:

import useDeepCompareEffect from 'use-deep-compare-effect';

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);

  useDeepCompareEffect(() => {
    const errors = validateFields(state.fields, config.fields);
    dispatch({ type: 'validate', payload: errors });
  }, [state.fields, config.fields]);
  
  return {
    // as before
  };
};
A Note On useEffect

Turns out, useEffect is a pretty interesting function. Dan Abramov wrote a really nice, long article on the intricacies of useEffect if you’re interested in learning all there is about this hook.

Now things are starting to look like a validation library!

Handling Form Submission

The final piece of our basic form validation library is handling what happens when we submit the form. Right now, it reloads the page, and nothing happens. That’s not optimal. We want to prevent the default browser behavior when it comes to forms, and handle it ourselves instead. We place this logic inside the getFormProps prop getter function:

const useValidation = config => {
  const [state, dispatch] = useReducer(validationReducer, initialState);
  // as before
  return {
    getFormProps: () => ({
      onSubmit: e => {
        e.preventDefault();
        dispatch({ type: 'submit' });
        if (config.onSubmit) {
          config.onSubmit(state);
        }
      },
    }),
    // as before
  };
};

We change our getFormProps function to return an onSubmit function, that is triggered whenever the submit DOM event is triggered. We prevent the default browser behavior, dispatch an action to tell our reducer we submitted, and call the provided onSubmit callback with the entire state — if it’s provided.

Summary

We’re there! We’ve created a simple, usable and pretty cool validation library. There’s still tons of work to do before we can dominate the interwebs, though.

Stay tuned for Part 2 next week!

Smashing Editorial
(dm, il)

Source: Smashing Magazine, Creating Your Own React Validation Library: The Basics (Part 1)

SVG Web Page Components For IoT And Makers (Part 2)

dreamt up by webguru in Uncategorized | Comments Off on SVG Web Page Components For IoT And Makers (Part 2)

SVG Web Page Components For IoT And Makers (Part 2)

SVG Web Page Components For IoT And Makers (Part 2)

Richard Leddy



So, we already have ways of dynamically loading a menu of SVG icons made to react by loading panels if we so desire, but the icons were not actual components. We were able to use a simple trick of bringing in the SVG for each icon and passing it into the Vue application. It was simple enough to generate a list of icons, and each icon reacted in a similar way except for small data differences. The data difference made it possible to bind the name of a panel to each icon in such a way that the handler for the icon’s button click could pass it on.

When a panel is loaded in the form of Vue component, everything about the panel and its components has to be loaded, templates, JavaScript, and more. So, the job of just managing loading the panel is bigger than what we have encountered so far in this discussion.

Let’s look at Vue’s way of providing a hook for async loading. The following snippet is from the Vue guide.

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // Pass the component definition to the resolve callback
    resolve({
      template: '
I am async!
' }) }, 1000) })

The guide tells us that the setTimeout function is an example of how to use the synchronicity with Vue components. Notice that where before there had been an object as the second parameter to Vue.component, there is now a function, which is referred to as a factory function. Within the resolve callback is a component definition, that would have been the second parameter to Vue.component before.

So, I had to stare at this example a while before it made sense to me. Here is another example, which suits me better:

Vue.component('async-example', function (resolve, reject) {
  // Vue will call this function and promise itself to handle
  // it when it gets back with data.

  // this function can then call a promising object loader
  // here the 'loader' function is some abstract function.
  // Most likely the application will use 'fetch'
  // but it could be something else.
  loader('/my/resource/on/server.json').
    then(function (JSON_data) {
         var object = transformJSONToJSObject(JSON_data);
          resolve(object)
    }).catch( (error) => { handle it } );

It seems like the right thing to do to make a more general function to go around this form.

function componentLoader(c_name,resource_url) {
  Vue.component(c_name, function (resolve, reject) {
    loader(resource_url).
      then(function (JSON_data) {
           var object = transformJSONToJSObject(JSON_data);
            resolve(object)
      }).catch( (error) => { handle it } );
}

So, in general, to load a component, we would just need a line like the following:

componentLoader('ThermoPanel','./JSON/thermo-panel.json');

So now, just what is the JSON that is being loaded? It can include everything about the component. In this case, as a panel component, it can include thermometers, machine switches, sliders, gauges, and more. While it seemed nicer to keep the components parts on the web page, it may actually work better to use the subcomponent field that is in the longer example for ‘thermo-panel’ that we made before and also for the other similarly constructed panels. The JSON will contain a complete panel structure.

However, if the reader will notice the inclusion of the function call to transformJSONToJSObject, he will understand that JSON might be coded in some way to make transport easier and to make it easier for a server to handle the definition. After all, the definition will include complete SVG templates, function definitions, and other JavaScript expressions. Also, the JSON object may contain more than just the panel definition because some information may simply aid in bookkeeping or validation. So, one can expect that there will be some treatment of the object upon receipt.

As for the encoding, the data coming in from the server may be encoded in a number of ways. Perhaps it will be simply URL encoded. Or more securely, it might be enciphered. For this discussion, we can just use URL encoding.

Some of the tools that are available for creating Vue applications no doubt take care of the JSON transformation. But, this discussion has so far avoided the use of command line tools. This omission is not that bad as we have also used Vue with the minimum of resources, using only one script tag for the referring to the CDN. However, I certainly do recommend looking into the command line tools especially for organizing projects.

When the JSON arrives at the page, given the component is completely assembled with subcomponents, no more work has to be done to fetch the parts. We can make the assumption that all components will come in fully defined for the rest of this discussion. But, assembling complete component hierarchies will require command line tools at some point.

The SVG editing process will also require some work. The SVG editing processes allow a designer to draw a panel and all the components on it. But, each subcomponent has to be identified, called out in a group, or given a place holder. Any approach to using the drawing requires some treatment of the SVG so that Vue component tags can replace the groups or graphic elements. In this way, any artist rendering can become a template. And, the drawn subcomponents will have to be disassembled into templates for Vue subcomponents.

This sort of parsimony is contrary to the workflow of most of the JavaScript frameworks. The frameworks are about assembling pages. But, editing or drawing, results in something already assembled by an artist. In practice, the result of editing does not provide a text file that corresponds directly to a framework component definition.

More about the editing process may be considered in some other discussion. There is a lot to it. But, for now, we have the tools we need in order to load hierarchal components and make them come alive.

The Lazy Application

For our IoT panel construction, we already have a selection bar that responds to searches. And, we have a way of loading components when we need them. We just need to connect up these parts. And, at last, we have to make sure that the panels appear and that they start working when they do.

The lazy loading of panels done by the async code above provides a sketch of an idea. But, thankfully, some people have experimented to find ways of making sure that all kinds of components can be loaded. There is one codepen entry that shows how to update Vue apps with new components of varying types. That is the mechanism that is needed for updating a designated part of the page with different types of panel.

With the ability to add in different kinds of panels and with a simple mechanism to load their definitions, we can, at last, have our panel searching page.

Here is the HTML that we need in our page so that the Vue app can place components in dynamically:

<template v-for="(panel, index) in panelList">
  <component :is="panel" :key="panel.name"></component>
</template>

The component tag is a Vue meta tag. See the reference for dynamic components. The properties, special attributes, used for the component tag in this case are is and key. The is attribute exists for dynamic components. And, the key ensures that the new children will have different identities from each other and helps Vue to decide what to draw.

“Children of the same common parent must have unique keys. Duplicate keys will cause rendering errors.”

The template tag will loop through components that are provided in the panelList data field of the application.

So, starting with the application level Vue definition for the icon app, we can make changes to include the panelList in the data elements. (Let’s now call it the panelApp).

var panelApp = new Vue({
        el: '#PanelApp',
        data: {
        iconList: [  // Where is the data? Still on the server.
        ],
        panelList: [
        ],
        queryToken : "Thermo Batches"  // picked a name for demo
        },
        methods : {
          goGetPanel: function (pname) {
            //
              var url = panelURL(pname);  // this is custom to the site.
              fetch(url).then((response) => {  // this is now browser native
                response.text().then((text) => {
                      var newData = decodeURIComponent(text);
                       eval(pHat);  // widgdef = object def, must be assignment
                       pHat = widgdef;
                     var pnameHat = pname + pcount++;
                     pHat.name = pnameHat; // this is needed for the key
                     this.panelList.push(pHat);  // now it’s there.
                  }).catch( error => { /* handle it */ });
          }
        }
    });

Besides adding in the panel, goGetPanel is now in a form required for getting a component definition from a database or other store. The server side must be careful about delivering JavaScript code in the correct format. As for what the object looks like coming from the server, we have already seen it. It is the kind of object used as a parameter to Vue.component.

Here is the complete body of the Vue app that provides a menu as a search result and a place to put panels fetched from the server when the user clicks an icon.

Request MCU Groups

These are groups satistfying this query: {{queryToken}}.

<!-- Here is a Vue loop for generating a lit -->

In the last div, the component tag now has a ref parameter bound to the panel name. The ref parameter allows Vue app to identify which component to update with data and keeps components separate. The ref parameters also allow our application access to the new dynamically loaded components.

In one test version of the panel app, I have the following interval handler:

setInterval(() => {
  var refall = panelApp.$refs;   // all named children that panels
  for ( var pname in refall ) {  // in an object
    var pdata = refall[pname][0];  // off Vue translation, but it’s there.
    pdata.temp1 = Math.round(Math.random()*100);  // make thermos jump around.
    pdata.temp2 = Math.round(Math.random()*100);
  }
},2000)

The code provides a little animation, changing thermometers randomly. Each panel has two thermometers, and the app allows the user to keep adding panels. (In the final version, some panels must be thrown away.) The refs are being accessed using panelApp.$refs, a field that Vue creates given the refs information in the component tag.

So, this is what the randomly jumping thermometers look like in one snapshot:

A collection of animated panels for one type of panel (or component) showing thermometers.

A collection of animated panels for one type of panel (or component). (Large preview)

Connecting The Panel To The IoT Device

So, the last piece of code is a setInterval test updating thermometers with random values every two seconds. But, what we want to do is read in real data from real machines. In order to do that, we will need some form of communication.

There are a variety of ways. But, let’s use MQTT which is a pub/sub message system. Our SPWA can subscribe to messages from devices at any time. When it gets those messages the SPWA can direct each message to the appropriate data handler for the panel mapped to the device identified in the message.

So, basically what we need to do is replace the setInterval with a response handler. And, that will be for one panel. We probably want to map panels to handlers as they are loaded. And, it is up to the web server to see that the correct mapping is delivered.

Once the web server and the SPWA have the page ready for operation, the web server no longer needs to take care of messaging between the page and the device. the MQTT protocol specifies a routing server to handle pub/sub. A number of MQTT servers have been made. Some of them are open source. One very popular one is Mosquito, and there are a few developed on top of Node.js.

The process for the page is simple. The SPWA subscribes to a topic. One good version of a topic is an identifier for an MCU such as a MAC address or a serial number. Or, the SPWA could subscribe to all temperature readings. But, then the page would have to do the work of filtering the messages from all devices. Publication in MQTT is essentially a broadcast or multicast.

Let’s take a look at how the SPWA will interface with MQTT.

Initializing MQTT On The SPWA

There are several client libraries to choose from. One, for instance, is a MQTT.js. Another is eclipse paho. There are more of course. Let’s use Eclipse Paho since it has a CDN stored version. We just need to add the following line to our page:

The MQTT client has to connect to a server before it can send and receive messages. So, lines setting up the connection also need to be included in the JavaScript. We can add in a function MQTTinitialize which sets up the client and the responses for connection management and message receipt.

var messagesReady = false;
var mqttClient = null;

function MQTTinitialize() {
  mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId");
  mqttClient.onMessageArrived = onMessageArrived;
  // connect the client
  mqttClient.connect({
           onSuccess: () => {
             messagesReady = true;
           }
        });
  // set callback handlers
  mqttClient.onConnectionLost = (response) => {
    //
    messagesReady = false;
    //
    if (response.errorCode !== 0) {
      console.log("onConnectionLost:"+response.errorMessage);
    }
    setTimeout(() => {
            MQTTinitialize()
           },1000); // try again in a second
  };
}

Setting up Subscription

With the connection ready, the client can subscribe to message channels, send messages on them, etc. Just a few routines can do most of the work necessary to connect panels with the MQTT pathways.

For the panel SPWA, the moment of subscription can be used to establish the association between the panel and the topic, the MCU identifier.

function panelSubcription(topic,panel) {
    gTopicToPanel[topic] = panel;
    gPanelToTopic[panel] = topic;
    mqttClient.subscribe(topic);
}

Given that an MCU is publishing on its topic, the SPWA will receive a message. Here, the Paho message is unpacked. And, then the message is passed on into the application mechanics.

function onMessageArrived(pmessage) {
  //
  var topic = pmessage.destinationName;
  var message = pmessage.payloadString;
  //
  var panel = gTopicToPanel[topic];
  deliverToPanel(panel,message);
}

So, now all we need to do is create deliverToPanel which should be somewhat like the interval handler that we had before. However, the panel is clearly identified, and only the keyed data sent in the particular message may be updated.

function deliverToPanel(panel,message) {
  var refall = panelApp.$refs;   // all named children that panels
  var pdata = refall[panel][0];  // off Vue translation, but it’s there.
  var MCU_updates = JSON.parse(message);
  for ( var ky in MCU_updates ) {
    pdata[ky] = MCU_updates[ky]
  }
}

This deliverToPanel function is abstract enough to allow any panel definition with any number of data points for animation.

Sending Messages

To complete the application loop between the MCU and the SPWA, we define a function to send a message.

function sendPanelMessage(panel,message) {
    var topic = gPanelToTopic[panel];
    var pmessage = new Paho.MQTT.Message(message);
    pmessage.destinationName = topic;
    mqttClient.send(pmessage);
}

The sendPanelMessage function does no more than sending the message out on the same topic pathway that the SPWA subscribes to.

As we plan to make the icon buttons responsible for bringing in some number of panels for a single cluster of MCU’s, there will be more than one panel to take care of. But, we keep in mind that each panel corresponds to a single MCU, so we have a one-one mapping, for which we may use two JavaScript maps for the map and the inverse.

So, when do we send messages? Usually, the panel application will send a message when it wants to change the state of the MCU.

Keeping The View (Vue) State In Sync With Devices

One of the great things about Vue is that it is very easy to keep the data model synchronized with the activity of the user, who may edit fields, click on buttons, use sliders, etc. One can be sure that button and field changes will be reflected immediately in the components’ data fields.

But, we want changes to fire off messages to the MCU as soon as the changes occur. So, we seek to make use of the interface events that Vue may govern. We seek to respond to such an event, but only after the Vue data model is ready with the current value.

I created another kind of panel, this one with a fairly artistic looking button (perhaps inspired by Jackson Pollock). And, I went about turning it into something whose click reports the state back to the panel that contains it. That was not so simple a process.

One thing that threw me off is that I had forgotten some of the oddities in managing SVG. I first tried to change the style string so that the display field of the CSS style would either be “None” or “something”. But, the browser never rewrote the styles string. But, as that was cumbersome, I tried changing the CSS class. That also had no effect. But, there the visibility attribute, which most of us recall from old HTML (version 1.0 perhaps), but that is very up to date in SVG. And, that works well. All, I had to do was to get the button click event to propagate.

Vue has designed properties to propagate in one direction, parent to child. So, to change data in the application, or in the panel, you have to send a change event to the parent. Then, you can change the data. The change of the data element controlling the button causes Vue to update the property affecting the visibility of the SVG element we have chosen to indicate state.
Here is an example:

More than one type of panel and more than one animation instance per type.

Finally, a collection of different types of panels each with instances assigned to separate MCU’s. (Large preview)

Each instance of the squiggly button panel is independent. So, some are ON and some are OFF.

This snippet of SVG contains the odd-looking yellow indicator:

<path
     :visibility="stateView"
     style="opacity:0.98000004;fill:#faea4a;fill-opacity:1;stroke:#eecd5c;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="sunthing"
       d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z"
       transform="translate(78.340803,6.1372042)" />

The visibility is populated by stateView, a computed variable that maps the state boolean to a string for SVG.

Here is the panel component definition template:


  

And, this is the JavaScript definition of the Vue panel with its children as subcomponents:

var widgdef = {
  data: function () {
    var currentPanel = {  // at the top level, values controlling children
      bstate : true,
      fluidLevel : Math.round(Math.random()*100)
    }
    //
    return currentPanel
  },
  template: '#mcu-control-panel-template',
  methods: {
    saveChanges: function() {  // in real life, there is more specificity
      this.bstate = !this.bstate
      relayToMCU(this.name,"button",this.bstate) // to be defined
    }
  },
  components: {
    'control-switch' : {  // the odd looking button
      props: [’state'],
      template: '#control-switch-template',  // for demo it is in the page.
      computed: {
        // you saw this in the SVG above.
        stateView : function() {
          return ( this.state ) ?  "visible" : "hidden"
        }
      },
      methods : {
        // the button handler is in the SVG template at the top.
        stateChange : function () {  // can send
          this.$emit('changed');  // tell the parent. See on the template instance
        }
      }
    },
    'gauge' : { // some other nice bit of SVG
      props: ['level'],
      template: '#gauge-template'
    }
  }
}

So, now the mechanism for a single button embedded in a panel has been laid out. And, there has to be a hook for telling the MCU that something has taken place. It must be called immediately after the data state of the panel component has been updated. Let’s define it here:

function relayToMCU(panel,switchName,bstate) {
  var message = switchName + ':' + bstate  // a on element parameter string.
  sendPanelMessage(panel,message)
}

There is the state change on it’s way to hardware in just two lines of code.

But, this is a fairly simple case. Any switch can be viewed as a function call to a piece of hardware out in the world. So, the string might contain the switch name and several other data elements. So, the component method that registers change will have to have some custom handling in it in order that it might gather together all the pieces of data set on the panel and send them along in one command string. Even the command string is a little simple. If the MCU is quite small, the command string might have to be translated into a code. If the MCU has a great deal of capability, the command string might actually be a JSON structure or perhaps all the data that the panel hosts.

In this discussion, the buttons on the icon panel contain the name of the panel to fetch. That may also be fairly simplified as well. It seems to make sense that that parameter can stand for any panel that might be stored in an enterprises databases. But, perhaps it is some formula. Perhaps, information about the panel should be wrapped around the panel definition that we receive from the server. In any case, the basics can be easily expanded upon once certain headaches are out of the way, like making the SVG respond to clicks properly.

Conclusion

This discussion has laid out some basic steps and decisions that lead to the realization of a Single Page Web App (SPWA) that can interface with IoT devices. We now know how to get panels from a web server and turn them into MCU interface.

There is much more to this discussion with quite a few other discussions that may follow. Starting with Vue is one thing to think about. But, then there is the whole MCU story, which we have only briefly touched upon.

In particular, by selecting MQTT as a communication substrate, we assume that IoT devices on the other end can somehow be ruled by MQTT. But, that may not always be the case. Sometimes gateways are needed if MQTT is to gain access to a device with serial links or Bluetooth. Or, perhaps all one ever needs from on the web page is WebSockets. Nevertheless, we used MQTT as an example to show how Vue could both receive and send data while keeping its data state in sync with devices.

Once again we only have part of the story. This time it is for synchronization because the page should be able to deal with alerts and bother the user if something critical is happening. Sometimes messages can get lost. So, we have to have a mechanism for acknowledgments.

Finally, it is my opinion that Vue makes updating data upon receipt quite elegant. But, sending the state changes is not so straight forward. It does not seem to make the job much simpler than can be done with vanilla JavaScript. But, there is a way and it makes sense.

Perhaps a clean library can be built to make a universal set of components for all panels. The elements for making such libraries and having them stored in a database have been briefly mentioned. Tools that go beyond just making SVG pictures may have to be developed. In any case, there are likely many things that can be done for the next steps.

Smashing Editorial
(dm, yk, il)

Source: Smashing Magazine, SVG Web Page Components For IoT And Makers (Part 2)

How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

dreamt up by webguru in Uncategorized | Comments Off on How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

Stefan Kaltenegger



Within the last nine years, almost every designer I used to work with expressed their frustration to me about them frequently having to spend days giving feedback to developers to correct spacings, font sizes, visual as well as layout aspects that had simply not been implemented correctly. This often lead to weakening the trust between designers and developers, and caused unmotivated designers along with a bad atmosphere among the two disciplines.

A lot of times developers still seem to have the bad reputation of being overly technical and ignorant when it comes to being considerate about details the design team came up with. According to an article by Andy Budd, “[…] a lot of developers are in the same position about design — they just don’t realize it.” In reality though (as Paul Boag points out), “developers [need to] make design decisions all the time.”

In this article, I’ll provide practical points of advice for frontend developers to avoid frustration and increase productivity when working with their creative counterpart.

Looking Through The Eyes Of A Designer

Let’s for one moment imagine you were a designer and spent the last weeks — if not months — to work out a design for a website. You and your teammates went through multiple internal revisions as well as client presentations, and put a solid effort into fine-tuning visual details such as white space, font styles, and sizes. (In a responsive era — for multiple screen sizes, of course.) The designs have been approved by the client and were handed off to the developers. You feel relieved and happy.

A few weeks later, you receive an email from your developer that says:

“Staging site is set up. Here’s the link. Can you please QA?”

In a thrill of anticipation, you open that staging link and after scrolling through some of the pages, you notice that the site looks a little off. Spacings are not even close to what your design suggested and you notice some kinks in the layout: wrong font faces and colors as well as incorrect interactions and hover states. Your excitement starts to slowly fade and turn into a feeling of frustration. You can’t help but ask yourself, “How could that have happened?”

The Search For Reasons

Maybe there were just a lot of unfortunate misunderstandings in the communication between the designers and developers. Nevertheless, you continue asking yourself:

  • What did the the handover of designs look like? Were there just some PDFs, Photoshop or Sketch files shared via e-mail with some comments, or was there an actual handover meeting in which various aspects such as a possible design system, typography, responsive behavior, interactions and animations were discussed?
  • Did interactive or motion prototypes that help to visualize certain interactions exist?
  • Was a list of important aspects with defined levels of priority created?
  • How many conversations took place — with both designers and developers in the same room together?

Since communication and handover are two very important key points, let’s take a closer look at each.

Communication Is Key

Designers and developers, please talk to each other. Talk a lot. The earlier on in the project and the more often, the better. If possible, review design work in progress together early in the project (and regularly) in order to constantly evaluate feasibility and get cross-disciplinary input. Designers and developers naturally both focus on different aspects of the same part and therefore see things from different angles and perspectives.

Checking in early on lets developers become familiarized with the project so they can start researching and planning ahead on technical terms and bring in their ideas on how to possibly optimize features. Having frequent check-ins also brings the team together on a personal and social level, and you learn how to approach each other to communicate effectively.

The Handover From Design To Development

Unless an organization follows a truly agile workflow, an initial handover of design comps and assets (from the design team to the developers) will likely happen at some point in a project. This handover — if done thoroughly — can be a solid foundation of knowledge and agreements between both sides. Therefore, it is essential not to rush through it and plan some extra time.

Ask a lot of questions and talk through every requirement, page, component, feature, interaction, animation, anything — and take notes. If things are unclear, ask for clarification. For example, when working with external or contract-based teams, both designers and developers can sign off the notes taken as a document of mutual agreement for future reference.

Flat and static design comps are good for showing graphical and layout aspects of a website but obviously lack the proper representation of interactions and animations. Asking for prototypes or working demos of complex animations will create a clearer vision of what needs to be built for everyone involved.

Nowadays, there’s is a wide range of prototyping tools available that designers can utilize to mockup flows and interactions in different levels of fidelity. Javier Cuello explains how to choose the right prototyping tool for your project in one of his comprehensive articles.

Every project is unique, and so are its requirements. Due to these requirements, not all conceptualized features can always be built. Often the available time and resources to build something can be a limiting factor. Furthermore, constraints can come from technical requirements such as feasibility, accessibility, performance, usability and cross-browser support, economic requirements like budget and license fees or personal constraints like the skill level and availability of developers.

So, what if these constraints cause conflicts between designers and developers?

Finding Compromises And Building Shared Knowledge

In order to successfully ship a project on time and meet all defined requirements, finding compromises between the two disciplines is mostly inevitable. Developers need to learn to speak to designers in non-technical terms when they explain reasons why things need changes or can’t be built in a specific situation.

Instead of just saying, “Sorry, we can’t build this,” developers should try to give an explanation that is understandable for designers and — in the best case — prepare suggestions for an alternative solution that works within the known constraints. Backing your point with statistics, research, or articles, can help to emphasize your argument. Also, if timing is an issue, maybe the implementation of some time-consuming parts can be moved to a later phase of the project?

Even though it is not always possible, having designers and developers sit next to each other can shorten feedback loops and make it easier to work out a compromised solution. Adapting and prototyping can be done directly through coding and optimizing with DevTools open.

Show your fellow designers how to use DevTools in a browser so that they can alter basic information and preview small changes in their browser (e.g. paddings, margins, font sizes, class names) on the fly.

If the project and team structure allow it, building and prototyping in the browser as soon as possible can give everyone involved a better understanding of the responsive behavior and can help eliminate bugs and errors in the early stage of the project.

The longer designers and developers work together, the better designers will understand what is easier and what is more difficult for the developers to build. Over time, they can eventually refer to solutions that have worked for both sides in the past:

“We’ve used that solution to find a compromise in Project A. Can we use it for this project as well?”

This also helps developers get a better sense of what details the designers are very specific about and what visual aspects are important to them.

Designers Expect The Frontend To Look (And Function) Like Their Design

The Design File Vs. Browser Comparison

A helpful technique to prevent designers from frustration is to make a simple left-right comparison between the design file you got handed over and what your current state of development looks like. This might sound trivial, but as a developer, you have to take care of so many things that need to function under the hood that you might have missed some visual details. If you see some noticeable discrepancies, simply correct them.

Think of it this way: Every detail in your implementation that looks exactly as it was designed saves both you and the designer valuable time and headaches, and encourages trust. Not everyone might have the same level of attention to detail, but in order to train your eye to notice visual differences, a quick round of Can’t Unsee might be a good help.

“Can’t Unsee” is a game where you need to choose the most correct design out of two choices.

(Image credits: Can’t Unsee) (Large preview)

This nostalgically reminds me of a game we used to play a long time ago called “Find it”. You had to find discrepancies by comparing two seemingly similar images in order to score points.

In “Find it”, players have to find errors comparing two images

(Image credits: Mordillo find them) (Large preview)

Still, you may be thinking:

“What if there simply is no noticeable system of font sizes and spacings in the design?”

Well, good point! Experience has shown me that it can help to start a conversation with the designer(s) by asking for clarification rather than radically starting to change things on your own and creating unwanted surprises for the designer(s) later.

Learn Basic Typographic And Design Rules

As Oliver Reichenstein states in one of his articles, 95% of the information on the web is written language. Therefore, typography plays a vital role not only in web design but also in development. Understanding basic terms and concepts of typography can help you communicate more effectively with designers, and will also make you more versatile as a developer. I recommend reading Oliver’s article as he elaborates the importance of typography on the web and explains terms such as micro- and macro-typography.

In the “Reference Guide For Typography In Mobile Web Design”, Suzanne Scacca thoroughly covers typography terminology such as typeface, font, size, weight, kerning, leading and tracking as well as the role of typography in modern web design.

If you would like to further expand your typographical horizon, Matthew Butterick’s book “Butterick’s Practical Typography” might be worth reading. It also provides a summary of key rules of typography.

One thing I found particularly useful in responsive web design is that one should aim for an average line length (characters per line) of 45 to 90 characters since shorter lines are more comfortable to read than longer lines.

Comparing two text paragraphs with different line lengths

Comparing different line lengths (Large preview)

Should Developers Design?

There has been a lot of discussion whether designers should learn to code, and you may be asking yourself the same question the other way around. I believe that one can hardly excel in both disciplines, and that’s totally fine.

Rachel Andrew nicely outlines in her article “Working Together: How Designers And Developers Can Communicate To Create Better Projects” that in order to collaborate more effectively, we all need to learn something of the language, skills, and priorities of our teammates so that we can create a shared language and overlapping areas of expertise.

One way to become more knowledgable in the field of design is an online course known as “Design for Developers” that is offered by Sarah Drasner in which she talks about basic layout principles and color theory — two fundamental areas in web design.

“The more you learn outside of your own discipline, is actually better for you […] as a developer.”

— Sarah Drasner

The Visual Center

By collaborating with designers, I learned the difference between the mathematical and visual center. When we want to draw the reader’s attention to a certain element, our eye’s natural focal point lies just slightly above the mathematical center of the page.

We can apply this concept, for example, to position modals or any kinds of overlays. This technique helps us to naturally get the user’s attention and makes the design appear more balanced:

Comparing two page layouts where one shows a text aligned to the mathematical and the other a text aligned to the visual center

(Large preview)

We’re All In This Together

In fast-paced and not-so-agile agency environments with tight deadlines, developers are often asked to implement fully functional responsive frontends based on a mobile and desktop mockup. This inevitably forces the developer to take design decisions throughout the process. Questions such as, “At what width will we decrease the font size of headlines?” or “When should we switch our three-column layout to a single column?” may arise.

Also, in the heat of the moment, it may happen that details like error states, notifications, loading states, modals or styles of 404 pages simply fall through the cracks. In such situations, it’s easy to start finger-pointing and blaming the people who should have thought about this earlier on. Ideally, developers shouldn’t ever be put in such a situation, but what if that’s the case?

When I listened to Ueno’s founder and CEO, Haraldur Thorleifsson, speak at a conference in San Francisco in 2018, he presented two of their core values:

“Nothing here is someone else’s problem.”

“We pick up the trash we didn’t put down.”

What if more developers proactively start mocking-up the above-mentioned missing parts as good as they can in the first place, and then refine together with the designer sitting next to them? Websites live in the browser, so why not utilize it to build and refine?

While winging missing or forgotten parts might not always be ideal, I’ve learned in my past experiences that it has always helped us to move forward faster and eliminate errors on the fly — as a team.

Of course, this does not mean that designers should be overruled in the process. It means that developers should try to respectfully meet designers halfway by showing initiative in problem-solving. Besides that, I as a developer was valued way more by the team simply for caring and taking on responsibility.

Building Trust Between Designers And Developers

Having a trustful and positive relationship between the creative and tech team can strongly increase productivity and outcome of work. So what can we, as developers, do to increase trust between the two disciplines? Here are a few suggestions:

  1. Show an eye for details.
    Building things exactly as they were designed will show the designers that you care and put a big smile on their faces.
  2. Communicate with respect.
    We’re all human beings in a professional environment striving for the best possible outcome. Showing respect for each other’s discipline should be the basis for all communication.
  3. Check in early on and regularly.
    Involving developers from the start can help to eliminate errors early on. Through frequent communication, team members can develop a shared language and better understanding of each other’s positions.
  4. Make yourself available.
    Having at least an optional 30-minute window a day when designers can discuss ideas with developers can give designers a feeling of being supported. This also gives developers the opportunity to explain complex technical things in words that not-so-technical people can understand better.

The Result: A Win-Win Situation

Having to spend less time in QA through effective communication and a proper handover of designs gives both the creative and dev team more time to focus on building actual things and less headaches. It ultimately creates a better atmosphere and builds trust between designers and developers. The voice of frontend developers that show interest and knowledge in some design-related fields will be heard more in design meetings.

Proactively contributing to finding a compromise between designers and developers and problem-solving as a developer can give you a broader sense of ownership and involvement with the whole project. Even in today’s booming creative industry, it’s not easy to find developers who — besides their technical skillset — care about and have an eye for visual details. This can be your opportunity to help bridge the gap in your team.

Smashing Editorial
(dm, yk, il)

Source: Smashing Magazine, How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

Setting Up A Digital Policy: An Interview With Kristina Podnar

dreamt up by webguru in Uncategorized | Comments Off on Setting Up A Digital Policy: An Interview With Kristina Podnar

Setting Up A Digital Policy: An Interview With Kristina Podnar

Setting Up A Digital Policy: An Interview With Kristina Podnar

Vitaly Friedman



The web is wonderfully diverse and unpredictable because of wonderfully diverse people shaping it. In this new series of short interviews, we talk to interesting people doing interesting work in our industry, and sharing what they’ve learned.

For over two decades, Kristina Podnar has worked with some of the most high-profile companies in the world and has helped them see digital policies as opportunities to free the organization from uncertainty, risk, and internal chaos.

Kristina is an energetic and passionate problem-solver, and we’re honored to welcome her at SmashingConf Toronto 2019 for a live session for creating and documenting a sound policy and standards, and a few tools and tactics which will help nurse your website back to health.

Vitaly: So, hello everyone. Thank you so much for joining in again. This is one of those mysterious sessions where we interview interesting people behind the scenes. I think it’s actually very important to highlight the important people doing important work just silently in the back, hiding a little bit, trying to make the world a bit better, one step at a time and, that’s important, sharing what they learned with the community, with all of us, so we can benefit from it.

Vitaly: And so, I’m very happy and privileged today to have with us Kristina Podnar who is a digital policy innovator. And, for over two decades she has worked with some of the most high profile companies in the world, and has helped them see policies as opportunities to free the organization from uncertainty, risk, and internal chaos. This is the official description. What I can tell from my side though is that Kristina is just such an incredibly positive and energetic and nice person. I’m so privileged to have you speaking in Toronto with us, Kristina. So Kristina, how are you today?

Kristina Podnar: Thanks for having me, Vitaly. I am doing really well and really excited to be here with you. You have no idea. This is sort of a pinnacle of my career and a path I’ve been on for a while. As you know, I contributed to Smashing Magazine back in 2016, but having the opportunity to be with you in Toronto is, I think, an ultimate high for me amongst everything else that I’ve done so far. I’m really excited.

Vitaly: This is so nice. I can’t wait. I can’t wait.

Kristina Podnar: Same here.

Vitaly: So, Kristina, tell me, the truth, the story, how did you end up in this mess? Every time we talk about digital policies and governance, and I heard rumors that you are going to speak about that, everybody thinks about boring stuff. Bureaucracy, slow processes, and communication issues, and maintenance problems. Messy, messy things.

Kristina Podnar: That’s right.

Vitaly: How do you feel there?

Kristina Podnar: Well, you know what, I don’t blame anybody for thinking that because that’s all that we’ve all been taught, right? I mean, we always think about policies as these 20 page PDF documents that have been signed off by legal or HR, or there somewhere on SharePoint. We have to go searching for them when we need to know something, and all we need is a yes or no answer and somebody’s saying, “No, no. Go read this document. Really, it’ll help you.” And, if you are a digital, that usually means reading 30 or 40 such documents.

Kristina Podnar: I don’t blame anybody for feeling like it’s a lot of bureaucracy. It’s really, really annoying. And, it’s where I actually came from in my career. Well, that’s not true. It was a little bit of a derailment in my career, but I came from the world where we used to live in the wild, wild west. We did things like migrate new websites in HTML with having a backup, which is how I personally made sure that one of my clients didn’t have a website for nine hours. Or, we would pass credit card numbers through FTP without encryption. Right. It was the crazy days.

Kristina Podnar: And then, it seems like the world just went to this extreme of trying to tie down anybody who was doing anything creative. And, if you wanted to do a really cool marketing campaign online, it was like compliance had to sign off, and legal had to sign off, and you had to say certain things. And, by the time you got to this point where your really cool idea came out the other end, you didn’t even recognize it. It was boring and it was dull.

Kristina Podnar: And so, I lived in this world for many years, and what I discovered is it doesn’t have to be like that. We can actually have a really good balance between understanding what needs to be done to protect the business, doing things the right way in terms of laws and regulations, and yet freeing everybody to do really creative and innovative work. And so, I’m on this mission to help businesses understand that because I think far too many people come into their work job every day and they’re not happy. And, I think that’s really sad.

Kristina Podnar: So, I’m all about let’s create policies that free the organization to do what it needs to get done in digital, and let’s free the workers to be creative and innovative and not have to do the humdrum of reading these long PDF’s or putting up with red tape because digital policies are fun and exciting and enabling. They are anything but red tape.

Vitaly: But, Kristina it sounds like a magic dream. It sounds like it’s something that it’s really hard to achieve. So, when it comes to something like that, and I guess this is also something you’re going to speak about in Toronto,-

Kristina Podnar: Yeah.

Vitaly: … where do you even start? Imagine you have this mass organization just in front of you and it desperately needs some better structure, maybe better communication. Every single company I was working within my career had communication issues, including ours to be honest for quite a bit of time.

Kristina Podnar: No.

Vitaly: So, where do you even start? What’s the starting point for you?

Kristina Podnar: So, personally what I like to do is really kind of just come into the organization fresh-eyed, and trying to understand really what are the biggest challenges. And, I’ve worked with really, really large multinationals all the way down to really small companies. And, it varies. The problem varies. But, in most organizations that I work with, what I find is people feel like they have to really control digital because it’s something new and they feel like it’s something that’s really, really dangerous and can kind of pose a threat to the organization as much as it can kind of create that opportunity.

Kristina Podnar: And so, it’s all about trying to find the pain point. So, for example, I recently worked with a pharma company, and they had this really crazy review process where it took 21 days to get content published. I’m thinking to myself that could work if it’s a really big product launch and you’ve been creating the product for years. 21 days isn’t a big deal. But, if you had like the measles outbreak in the United States, you want to act really quickly and get the information out there. 21 days is forever.

Kristina Podnar: And so, what it was is people had to go through the same pain staking points for content review over and over again and their medical signatories had to feel comfortable. They had to do these crazy screenshots of the content on an iPad versus an iPhone versus this screen, that screen. Legal had to review things. And, what we found is that we can actually boil the steps down and creates certain rules that can’t be broken and do this in a way that facilitates the content being created with awareness across the whole sign-off team.

Kristina Podnar: And so, really ahead of time, what we would do is, as content was being created, we would do screenshots with the different devices. We would make sure that, up front, whoever was in charge of the marketing campaign was following certain sort of rules and regulations and actually showing where they were getting creative or where they wanted to kind of relax some of the rules.

Kristina Podnar: And, what that meant is that there was a summary and a summative package at the end of the process that we could serve up, almost in a restaurant where you have your menu item and you check things off and go, “I don’t want the fish today, but gosh, the chicken sounds delicious.” We’ll go with that really quickly and get that order in. And, it was the same thing. And so, all of a sudden we found ourselves in this crazy pharma world, which is probably the most regulated of anybody out there, 21 review day process down to three.

Kristina Podnar: But, it has to do with understanding what the expectations are of sort of this regulatory policy driven world and really making sure that as creatives we address that up front, and that we actually give everybody the ability to exhale, take a deep breath, and understand we’re doing things and working towards the same common goal, and we’re going to make sure we don’t get the company sued. But, at the end of the day, we want to have a lot of freedom. We want to make sure that it’s innovative, that it catches the user’s imagination, that we have these great digital experiences, and that that can still be done within that framework. Because it’s really freedom within a framework, if you will. And, it doesn’t have to be boring and it doesn’t have to be onerous and it certainly doesn’t have to take 21 days.

Vitaly: Wow. Now, I actually getting excited about all that stuff. That’s surprising.

Kristina Podnar: Yay.

Vitaly: I did not see that coming at all. But, I’m wondering at this point, so would you say that every single company of every size could benefit from a very clear digital governance and kind of policy? Does every company has to invest time in it, or do you see it’s more a deal for enterprise or larger level, larger size companies?

Kristina Podnar: So yes, everybody needs to have digital policies, even me. I’m an independent consultant, but even I have to comply with things like GDPR. And so, last year I actually wrote up how I did that and how GDPR applies to the gig economy. So, policies are really good for anybody, whether you’re a single consultant all the way up to multinational. The thing that’s different I think, and we have to be very, very cognizant of this because I don’t want everybody to run out there and create 300 policies. Don’t do that. That’s also wrong.

Kristina Podnar: What we have to be really cognizant of is if you’re a small startup, for example, you’re not going to have the same policies nor the same number of policies, that they’re not going to be as robust, perhaps, in terms of how you implement them, as a large multinational. And, I really wrote my book, The Power of Digital Policy, and that’s really what I focused on. I focused on how can you get this done, whether you’re a startup, or if you’re a small company, if you’re a large enterprise, and it really is about where you are in your maturity growth in terms of policy.

Kristina Podnar: So, if you’re just starting out, don’t worry about 300 things. Worry about the four things that I’m going to tell you about at the conference, right? Let’s kind of just get you started. Pay attention to the most important things and get you to the point where, for you, in terms of what you’re trying to get done, you’ve properly balanced out that risk and that opportunity that digital brings with it. Because that’s really what I want people to understand. There is no magic checklist for policies. Just because somebody else is doing the crazy dance over there with 300 policies and that’s what they need to do, the crazy dance in a happy way. That’s okay.

Kristina Podnar: But, the same thing doesn’t apply to you. You’re unique in terms of your culture, you’re unique in terms of your beliefs. You’re unique in terms of what you’re trying to get done. And so, don’t just take somebody else’s suit and put it on. It’s going to be constructive if it’s too small and too tight. It’s not going to feel good. Same thing with policies. Don’t go off and take somebody’s policies and put them on. They’re not going to feel good. We want your organization to be safe, to be productive, to do the right things for the business. But, by the same token, we want you to actually be able to get some cool things done. And, that’s really what digital policies are and that’s what I’m trying to actually get done and help everybody else do.

Kristina Podnar: And so yes, one person all the way up to multinational, everybody needs policies. What type? It depends on what you’re doing. It could be accessibility, which I know we’re going to also be covering it at Smashing and I’m excited about that. But, it could be anything from accessibility to user-generated content. It could be policy and privacy, lots of conversation around that these days. It could be about just literally who gets to select the content management system we’re going to use inside of an organization so we don’t have to have that conversation over and over again every time we have a new digital martech stack or something else we want to introduce into the organization and get something done. So, to me, yes, policies always sound boring, but the reality is they can be anything but that. And, it’s just about how we get that done and get it done in a reasonable way that helps everybody out and is in the interest of everybody in the organization. And, that’s where I see the most success.

Vitaly: I have to switch cameras now.

Kristina Podnar: Okay.

Vitaly: Interesting. And, it’s also, for me personally, when it comes to policies, I think it’s all about streamlining. So, we improved a lot of things just to streamline processes to make sure that everything is kind of clear, what is following what, kind of how do we move from a to b in a very predictable set of steps rather than chaotic, just throwing everything in the air and hoping that something will stick. And so, this was actually very helpful and it was very informal in many ways. Would you say that a policy has to be kind of stated on a piece of paper or in a document? How do you document it? How does it manifest itself?

Kristina Podnar: So, it’s interesting, I actually spent a year thinking about all of my experiences in terms of what works best in an organization and size, industry, et cetera. And, what I found is policies do need to be written down somewhere, right? Just because most organizations, no matter how small you are, there’s always somebody new jumping onto the team, or somebody’s leaving for maternity leave and so somebody has to step in, et cetera. So, it’s important to document things.

Kristina Podnar: Now, I think, especially if you’re in a small organization, you’re part of a smaller team, you don’t need to have a really formal template. You can even write on the back of a napkin if everybody can see that napkin in the lunchroom and knows where to find it. So, I don’t think we need to get stuck on this is the template, this is the format, although in a larger organization that does help.

Kristina Podnar: What I think we need to really focus on, and this is where policies get the bad rap, policies are not just about how we document things and that’s sort of old-world thinking, right? That’s how we did things 25 years ago. We wrote it on a piece of paper and it’s in a file folder over there. But, here we are in the digital world, right? We’re trying to make these really great user experiences online, but what we forget to do is the same thing for our internal friends and colleagues. And, that’s really what I think we need to be doing around policies.

Kristina Podnar: We need to be making policies and documenting them in a way that’s easily accessible by everybody and it fits into what you’re already doing. And, that’s what I see work the best. If you want people to do certain things, for example, around content creation and they’re in Drupal, honestly just create a little checklist that they can actually link to from Drupal, and understand quickly these are the things I should be paying attention to. Don’t make them quit their day job and go looking for guidance because nobody wants that. Right?

Kristina Podnar: Or, if in a really large multinational, like we just deployed a chat bot that is really great. It actually tells marketers real time what they need to be thinking about and what they need to be doing in terms of that campaign. But, what’s really cool is it remembers and builds on top of itself over and over again. So, if a marketer is focused, for example, on Asia Pacific, we already know you’re focused on Asia Pacific and so all guidance we’ll ever give you is in the context of Asia Pacific and you can get that real time. We remember last time you did a campaign, what you were trying to achieve, and what your performance objectives were. And so, if they’re the same ones, we can just track that going forward and narrow the amount of guidance that you have to think about or even do.

Kristina Podnar: And, what’s really great is if you do this in the right way, it doesn’t just empower the designer, the marketer, or the developer, the content strategist. It really also helps your vendors and agencies that you bring on board. Or, if you’re a part of an agency and you’re coming to the table, imagine how cool when somebody brings you on board and says, “Hey, I want you to do this for me. Stand up this new website.” And then it’s like, ta-da. These are the things we expect you to do and this is how we’re going to measure you when you’re done. I mean, that’s great. You already know how high you have to jump and what you have to achieve, and that allows you to focus on the things that really matter, in where you have that freedom and creativity without having to worry, oh no, are they going to tell me at the last hour my website has to be accessible and I haven’t built it that way. It’s like, man, nobody wants to go back to step one.

Kristina Podnar: And so yes, it’s about documentation, but more than just write it down on a piece of paper, although that can certainly work. It’s about doing it in the context of your culture and how people want to be delivered that information, and treating people who are going to consume this information like they’re actual users because they are.

Vitaly: Oh, this sounds like… I’m so happy now. I’m so happy.

Kristina Podnar: Oh good.

Vitaly: So, if you had to sum up what you’re going to cover in 40 or 45 minutes at this madness show called SmashingConf Toronto, how would you sum it up? What is it all about in maybe 40 seconds or less?

Kristina Podnar: Sure. So, you know what, all of us collectively, even if you’ve only been in this field for a few years, have contributed to a big mess. The mess has been underway in 25 years. It’s not going to get cleaned up right away, but we can make a huge difference in terms of what we do, cleaning up the messes, and making our life easier and more fun. So, we’re going to play doctor and patient in this session. We’re going to have some fun and hopefully make it funny as well. And, we’re going to literally go through how can we diagnose some of the illnesses that our organizations have, some of our projects have, and make sure that we give the right medicine, the right Rx, the right policies so that we can enable ourselves to have fun, be creative, and balance out that risk and that opportunity that I keep talking about.

Vitaly: Wow. I have a question for you.

Kristina Podnar: Sure.

Vitaly: Kristina, are you planning to run for President? Because if you do, I think you have very good chances of winning.

Kristina Podnar: Oh, thank you. I don’t know about that. But, you know what, and I shouldn’t say this publicly, it’ll be an interesting scene in the United States in terms of who’s going to run and where the bar is. And, I’ll let everybody decide on where they fall on that one.

Vitaly: Yes. So, maybe the last one, can you maybe share some insights with us about what you’re working on now, and also what excites you the most in this vast worldwide web of ours? Is there something you’re particularly interested in? Or, if you look into GDPR and all of this stuff, and I know that there is a law coming in California next year.

Kristina Podnar: Yes. CCPA.

Vitaly: Yes, exactly.

Kristina Podnar: January 1st, yeah.

Vitaly: Oh, January 1st. Here we go.

Kristina Podnar: January 1st, yes. Here we go.

Vitaly: What are you kind of looking forward to? What is something that really brings you to life or keeps you awake at night?

Kristina Podnar: Okay. So, two things. I’m working on something really fun right now, which I love. I’m actually becoming a spokesperson for this really small company in the United States. They are active in every country in the world with the exception, I think of Cuba and maybe Iraq. And, very tiny company, really small staff, not a lot of money. They’ve decided to become GDPR compliant, but get this, they’re applying GDPR principles to everybody, that’s their customer or consumer or prospect around the world, and they’re applying the same principles to everybody who works for them. Which is a huge order.

Kristina Podnar: And so, for me, it’s really fun. It’s really energizing. It’s a little bit of a proof of concept because GDPR inherently conflicts with other regulations around the world and other things that we try to do in terms of best practice. And so, I’m kind of taking this as an extreme case and an opportunity to do a proof of concept and see how do you do this in a practical way, and what does an organization do when there’s actually a conflict? Right? Where do you decide to kind of go in terms of your practices? So, that’s really something that gets me up in the morning and I don’t even need coffee to get started. I just go.

Kristina Podnar: And, in terms of what keeps me up at night, I think it’s this entire notion, what I call, the perfect storm of where we are right now. We have a situation where there’s sort of the crazy dance going on in social media, right? We have the opportunity for violence to be streamlined in social media. We have politicians using social media as a platform, claiming that they have First Amendment rights in the United States, of freedom of speech on a private platform, which is just crazy. We have users getting really upset around privacy and all of the privacy laws you just mentioned.

Kristina Podnar: So, I see this as the perfect storm, and what keeps me up at night is are we going to take this as an opportunity and make the best of it, or are we going to just passively sit by and not contribute, in which case the perfect storm will pass. And so, I hope that all of us step up and play a role because we have an important one to play and it’s a little bit more important than we probably realize. So, I hope we all engage in that.

Vitaly: Yeah. Well, so that sounds very exciting. So, with this in mind, thank you so much Kristina, for being with us today. I can’t wait for Toronto.

Kristina Podnar: Me either.

Vitaly: It’s coming up in just a few weeks from now, like six weeks or so from now.

Kristina Podnar: Yep. Countdown’s on.

Vitaly: This’ll be the first time where we actually finally meet. We have many friends in common-

Kristina Podnar: That’s right.

Vitaly: … and so I can’t wait. So, thank you so much, Kristina.

Kristina Podnar: Same here.

Vitaly: Everyone, thank you so much for joining us today. I’m looking forward to the next little sessions about people behind the scenes and all of that. And, with this in mind, signing off. Kristina, any last words you want to share with the audience to kind of send a message out there?

Kristina Podnar: I’m bringing cookies and I’ll leave it at that.

Vitaly: Oh, wow. If that doesn’t work, I don’t know what will.

Kristina Podnar: Sounds good.

Vitaly: All right, thanks everyone. Thanks Kristina, and see you next time.

Kristina Podnar: Thanks Vitaly. Take good care.

That’s a Wrap!

We’re looking forward to welcoming Kristina to SmashingConf Toronto 2019, with a live session on digital policy, how to set up one, and how to solve some of the issues most companies are struggling with these days. We’d love to see you there as well!

Please let us know if you find this series of interviews useful, and whom you’d love us to interview, or what topics you’d like us to cover and we’ll get right to it!

Smashing Editorial
(ra, il)

Source: Smashing Magazine, Setting Up A Digital Policy: An Interview With Kristina Podnar

Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

dreamt up by webguru in Uncategorized | Comments Off on Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

Manuela Langella



In this tutorial, I’m going to show you how to create a beautiful cover design inspired by the 1950s. Specifically, the cover will be for a children’s book, so we’re going to create a well-known character: Little Red Riding Hood.

The interesting aspect of this design is that we are going to create its purely retro character that was typical for cartoons back then. As an illustrator, I have always been fascinated by the graphics of the last half-century. I grew up watching many cartoons, books, and comics characterized by that style, although I wasn’t exactly born in the 50s.

This is the reason why I want you to soak in a little inspiration from 1950. In this article, I’ll explain why I chose this precise historical period to inspire me and where my love for this type of artwork comes from. I’ll also share some ideas which you can find online if you are looking for a little inspiration to give this a try yourself.

In order to follow along, you can download the files and practice on my self-made drawing or, if you like, you can create one of your own. The important thing is that you follow all of the steps and tips if you want to create an absolutely fascinating retro design!

You will then discover the world of retro colors and all those effects that will allow us to have retro effects: I’m talking about brushes, textures, and patterns. Once the design is finished, the cover design is ready. Finally, we will prepare our cover in InDesign to export for print.

Are you ready? Let’s have fun!

  1. Why Mid-Century Art?
  2. Looking For Inspiration
  3. Drawing Concepts

    1. How To Import A Hand-Drawn Design
    2. How To Create A Basic Design
    3. How To Create A Retro Brush
    4. How To Outline Drawings
    5. Further Details
  4. Colors, Textures And Patterns

    1. Coloring Characters
    2. Brushes Effects
    3. The Background
    4. Texture Effects
  5. How To Organize A Cover Into InDesign
  6. The Final Result

1. Why Mid-Century Art?

Growing up, I read so many comics and watched so many cartoons. But not any kind — just the ones that had been drawn in a mid-century style. I’m not sure why that particular design atttracted me that much; maybe it was because of the simple lines used in the drawings or the pastel colors that were used to create the comics and cartoons.

As an illustrator and graphic designer, I always search for inspiration and like to browser through Pinterest. (It’s a great place to discover some very special ideas!)

While searching for some retro inspiration for this tutorial, I found a couple of illustrations that captured my attention:

Illustrations used for inspiration

Illustrations by Satoshi Hashimoto (left) and Derek Yaniger (middle and right) inspired by the 1950s (Large preview)

I absolutely love the hilarious way these artists have represented people and things in their artwork — the exaggeration, the details in simplicity, and the vibrant colors. Aren’t they something!

I’ve always wanted to know everything about drawings and designs created during the mid-century age, and the more I research, the more I keep rediscovering a world created with beautiful patterns, Scandinavian colors, and simple but very communicative designs.

2. Looking For Inspiration

There is so much to discover about mid-century designs. Here some examples of very inspiring advertisements and illustrations.

Image credits (from left to right): Luca Vecchi, Vintage Ad Browser, Classic Film, Ward Jenkins. (Large preview)

Characteristics: few colors, simple lines, brush effects.

Inspiration from mid-century advertisements

Image credits: Vintage Ad Browser (top left), CrumbByCrumb (top right), Vintage Everday (bottom left), Kathryn Howard (bottom right). (Large preview)

3. Drawing Concepts

For this tutorial, I wanted to find something to draw that is well known to everyone, so that it’s not too difficult to understand how the details can be applied to an illustration of your choice later on when you want to try out the steps on your own.

3.1. How To Import A Hand-Drawn Design

So, Little Red Riding Hood came to mind. I’m going to guess that everybody is familiar with this fairy tale, and we all have an idea of how Little Red Riding Hood looks like. As children, we have seen her at least once, i.e. in a book or a cartoon.

As with all of my designs, I begin drawing my idea by hand. Below, you’ll see the two original drawings (including the erasures and the yellow color of recycled paper):

sketch drawings of the characters

(Large preview)

I tidied up my sketches with the help of Photoshop and so now we can easily outline the characters and use them in the illustration:

sketches cleaned up in Photoshop

(Large preview)

Note: You can download the start images over here.

To achieve the retro look, let’s take a look now at which elements I used for the principal characters:

making Little Red Riding Hood look retro

For Little Red Riding Hood, I used many edges on the hood, the eyes, eyebrows, elbows, and feet. The face is pretty simple, too, and has a triangular shape. (Large preview)

Edges are one of the most useful details used for mid-century graphics and designs. I think edges give a very funny nature to the design, making it very playful and childish.

The little coat I used is also typical of 50s clothing:

vintage 1950’s coat inspiration for Little Red Riding Hood to wear in the illustration

(Image source: 1stdibs on Pinterest) (Large preview)

For the wolf, I also used some typical elements from the 50s, such as the cartoon-like as eyes and feet:

(Large preview)

Funny note: In his book, “Modern Cartooning: Essential Techniques for Drawing Today’s Popular Cartoons”, Christopher Hart shows two ways to draw the same shoe:

“It’s funnier to draw the boots in a quirky manner. The disadvantage is that they only come in a size 7.”

(Large preview)

I decided to give the wolf typical facial expressions that were widely used in retro cartoons. Take a look at the image below (taken once again from Christopher Hart book):

(Large preview)

“The circle shape is the most common eye shape. It can be used for almost any character.”

For the rest of my design, everything follows the same rules. The trees, the house, and even the clouds have that particular edgy effect.

(Large preview)

Now that you know how to get started, we can finally begin to bring our illustration to life!

Let’s fire up Adobe Illustrator.

3.2. How To Create A Basic Design

Once you open Illustrator, start with creating a new document first. I will create a square artboard for a square book cover. (Many children’s books have a square shape.)

(Image credits: Pam Keller) (Large preview)

Let’s go to File → New. In the open Window, I chose Print because I’d like to have my design printed. Then, I set 3000px × 3000px for the artboard size. Finally, I name it Little Red Riding Hood. See my setting below:

(Large preview)

(Large preview)

Now you have to import the drawings. (I’ve provided the files for you here.)

Go to File → Place, choose the folder where you saved the drawings, and put them onto the artboard. Since the files are bigger than our artboard, just resize them to fit in.

(Large preview)

Put the drawings on two different layers, so we can have control on both of them.

(Large preview)

Once we have done, let’s go to the further step: create a brush to draw in Illustrator.

3.3. How To Create A Retro Brush

I have drawn some brushes myself, inventing something always based on the 50s style. As you can see in some examples below, used lines are not perfect. They always give the impression of something handmade.

So I grabbed my iPad and drawn some lines I liked in Procreate. I wanted to give the brushes a hand-drawn look, typical from 50s design, so this is my result:

(Large preview)

Note: For our mid-century-inspired illustration, I’ve provided the brushes for you here— feel free to download and use them.

So, let’s go back to Illustrator and see how the brushes can be installed.

Open the file you just downloaded and open it in Illustrator. Be sure your Brush Panel is open by clicking on Window → Brushes. Select the first brush from the file you just opened and drag it into the Brush Panel as shown below:

Large preview

As you can see, after I dragged the brush in the Brush Panel, I selected “Art brush” from the open window and renamed the brush. I checked the “Stretch to fit stroke length” option and then selected “Tint” as Colorization Method. This way, we will be able to change our brush color as well.

Let’s go on and drag all the brushes in the Brush Panel, following the same instructions as above. At the end, you should have five brushes:

(Large preview)

Nice! Your very own custom mid-century-inspired brushes!

Note: If you want your brushes be permanent in Illustrator, select them all and click on the first left icon at the bottom of the panel (“Brush Library Menu”). Then click on “Save Brushes”.

(Large preview)

Illustrator will save them in a “Brushes” folder as the default. Then you will see your custom brushes by clicking Brush Library Menu → User Defined.

3.4. How To Outline Drawings

With our new brushes, let’s begin to outline our design. You just need to select the brush you like most and begin to draw on the design lines.

If you don’t see the brushes in your panel, go on to Brush Library Menu → User Defined and choose mid-century01 (or whatever other name you used).

Select the layers with imported files and set their opacity to 50% through the Appearance panel:

(Large preview)

(Large preview)

Once you’ve done that, lock them and create another layer on the top. Then, begin to trace:

(Large preview)

You can choose to work with just one or all of the brushes — it’s up to you. I suggest to use the first one for thinner lines, and the other ones for thicker lines. Of course, you can set the size of the brushes in any way you like.

(Large preview)

Have fun by tracing all of the lines. The thing I like the most are the trembling lines — that’s exactly the effect I desire.

Your finally design should look something like this:

(Large preview)

3.5. Further Details

Now, let’s add some details to our characters. I drew some stains with the help of the Blob Brush tool (Shift + B):

Large preview

This is the result:

(Large preview)

Another cute detail are the dotted lines on LRRH’s coat. They are very simple: open the Properties panel and click on Stroke. Check the Dashed Line and give 0 pt dash and 20 pt gap:

(Large preview)

Grab the Pencil tool (N) and draw dotted lines on the edges of the coat.

This is the result:

(Large preview)

Now that we’ve completed this step, we can now continue to the next one: adding colors, textures, and effects.

4. Colors, Textures And Patterns

4.1. Coloring Characters

The first thing we need is a palette to color our characters. I researched some colors on Pinterest and saved many interesting palettes on my Pinterest wall:

(Large preview)

I then created this palette for myself:

(Large preview)

Let’s insert our palette in the Swatches. Create some circles with these colors in Illustrator, then select them and open the Swatches panel through Windows → Swatches. With color circles selected, click on New Color Group:

(Large preview)

In the pop-up window, click on “Selected Artwork”, including “Convert Process to Global (the palette will be permanent in the Swatches panel) and “Include Swatches for Tints”.

(Large preview)

And now we have our palette in the swatches:

(Large preview)

Let’s color Little Red Riding Hood and the wolf. Go into the Layers panel and create a new layer below the other two:

(Large preview)

Grab the Blob Brush tool and begin to color on this layer. The lines of the characters will stay on top and colors on the bottom.

I set the Blob Brush as shown below:

(Large preview)

Take the time you need to color everything. This is a relaxing and fun step, so enjoy it!

(Large preview)

Here are my final colors:

(Large preview)

4.2. Brushes Effects

I used some other brushes to create shadow effects on the characters. The brushes are default in Illustrator; you can find them by clicking Brush Library Menu → Artistic → ChalkCharcoalPencil.

(Large preview)

Select one of them, go to Appearance and set the opacity to 15% Multiply.

(Large preview)

Now, draw some lines on the characters to create some shadow effects:

(Large preview)

(Large preview)

(Large preview)

And we’re done with the characters! Let’s move on to the background.

4.3. The Background

As first thought, we probably need to start with the sky. So let’s create another layer (under the characters) and rename it as “Sky”.

Draw a rectangle with the color #9BD2D2, then grab and drag a circle inwards to make the rectangle rounded.

Large preview

Again, let’s work with the Chalk brushes see 4.2. above. With the same color applied as the background. Brush some lines at the bottom of the rectangle to give some art effects:

(Large preview)

We will add some others brush effects to the sky. Create a new layer above the sky one and rename it as “Brushes effect”. With another charcoal brush (I used charcoal feather), draw some lines in the sky. The color is #FFFFFF with opacity set to 50%. See the image below.

(Large preview)

Now that wasn’t that hard, was it? Let’s draw some clouds now. You can use the Pencil tool (N) with #FFFFFF as the color and draw some simple shapes like the ones shown below:

(Large preview)

Next, draw a country lane with the Pencil tool (N) (again, with #FFFFFF as the fill color):

(Large preview)

Let’s add some tufts of grass. Select a brush as we did in 4.3 and draw them as shown below. Set the brush color to #1BA58E:

(Large preview)

By using the Rectangle tool (M), you can create simple shapes so let’s try to create a little house in the background as well. In order to make it a bit deformed, we need to use the Direct Selection tool (A), then grab and drag the angles.

Large preview

Let’s move on to the trees now. With the Polygon Tool, click just once on your artboard, so that a window appeary. Set “3 sides” and 100 px for Radius:

(Large preview)

For the triangle you just created, set the background color on #1BA58E. To make it look a bit deformed, use the the Direct Selection tool (A), then grab and drag the angles like we did when we created the house earlier.

(Large preview)

With the Pen tool (P), make a simple line in the center of the tree. Open Window → Stroke and set the stroke profile as shown below:

(Large preview)

The result should be something like this:

(Large preview)

Keep the same settings and draw some little lines with the Pen tool (P) to create a couple of branches:

(Large preview)

Let’s now group all tree elements, duplicate it or create some other trees to fill the scene. Put every tree on a different layer and play with layers to give depth to the scene.

Be brave. Try different shades of green for the trees:

(Large preview)

With the Ellipse tool (L), create some circles under the trees to simulate a shadow. Set the background to #000 and the opacity to 50%.

(Large preview)

4.4. Texture Effects

Let’s now add some effect to the trees, to make them more “retro”. I applied this effects just to the trees, but you are free to apply it to the entire design.

First of all, we need a texture. Since we work in vectors, we should apply a vector texture. You can download one for free (just googling “vector textures”. Anyway, I provided a vector texture for you here.

Download the texture and open it in Illustrator. Create a new layer and rename it as “Texture”.

(Large preview)

Put the texture on the new layer. Your illustration should look like this:

(Large preview)

Don’t be scared, we won’t ruin our design. We just need to make some changes.

Go to Windows > Appearance and set the Opacity on 15% and Blending Mode on Overlay. Then go to Object > Expand.

(Large preview)

In order to apply the texture just on trees, I deleted the superfluous parts of the texture with the Eraser tool (Shift + E). See my example below:

Large preview

Here my final result:

(Large preview)

All that remains is to make visible the layer with our characters and put them in the centre of the scene:

(Large preview)

As the very last thing, let’s create the title. Draw two simple black and white rectangles using the Rectangle tool (M) and write the title ad I show you in the image below. The fonts I used are Fontdiner Swanky and Fontdiner Sparkly (both free to download).

(Large preview)

Congratulations! You just finished your first Mid-Century Cover!

Next step is to complete our cover in InDesign. Ready?

5. How To Organize A Cover Into InDesign

Now I need to work in InDesign to prepare my cover for the print. Consider that we will need the front and back cover and must calculate a space for the spine.

I want my front cover size be 18 x 18 cm (7.00 × 7.00 in). Since I need to create everything in a single artboard, I need to put the pages side by side, plus a space more for the spine.

So, let’s set 37 cm width (18 cm front + 18 cm back + 1 cm spine) and 18 cm height. Other settings are 0,3 cm Margins and 0,3 cm Bleed.

(Large preview)

Create two guides, respectively on 18 and 19 cm.

(Large preview)

A quick back to Illustrator to save our cover design. If you have Adobe CC, you can use the Library to save your design. Open Window > Libraries, select everything on your artboard and drag to the library:

Large preview

By opening the Library in Indesign, you will find your cover. Drag it and drop into the page. Put it on the right side of it.

(Large preview)

For the back side i’d like to use just the Little Red Riding Hood Character. Go back to illustrator and drag it in the Library.

Large preview

Again, come back to InDesign and import the character into the page from Library the way I show you:

Large preview

Then write the title again, this time directly into InDesign. Feel free to play with the size and position of the words! Here my result:

(Large preview)

Let’s write the title on the spine too:

(Large preview)

And we’re done! Let’s export our file for the print.

Click on File > Export and choose Adobe PDF (Print).

In the General panel choose Adobe PDF Preset: High Quality Print. Leave the rest as it is.

In the Mark and Bleeds select All Printer’s Marks. Clic OK.

Here your result:

(Large preview)

Nice job! Bravo! You have finished this (quite long) tutorial!

6. The Final Result

Here some mockups to simulate the real book:

(Large preview)

(Large preview)

(Large preview)

(Large preview)

I hope you enjoyed this tutorial, and — most of all — I hope I was able to convey to you my passion for mid-century design!

Try it out, and please share your own illustrations and thoughts in the comments below.

Smashing Editorial
(yk, il)

Source: Smashing Magazine, Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

Collective #514

dreamt up by webguru in Uncategorized | Comments Off on Collective #514





C514_svgwillsaveus

SVG Will Save Us

Sarah Drasner shows some great things we can do with SVGs in this PerfMatters Conference 2019 talk.

Watch it





C514_cssonly

CSS-Only Chat

An insane project that shows how it’s possible to achieve an asynchronous chat that sends and receives messages in the browser with no reloads and no JavaScript.

Check it out





C514_formation

Formation

Formation is a shell script to set up a macOS laptop for design and development.

Check it out











Collective #514 was written by Pedro Botelho and published on Codrops.


Source: Codrops, Collective #514

Collective #514

dreamt up by webguru in Uncategorized | Comments Off on Collective #514





C514_svgwillsaveus

SVG Will Save Us

Sarah Drasner shows some great things we can do with SVGs in this PerfMatters Conference 2019 talk.

Watch it





C514_cssonly

CSS-Only Chat

An insane project that shows how it’s possible to achieve an asynchronous chat that sends and receives messages in the browser with no reloads and no JavaScript.

Check it out





C514_formation

Formation

Formation is a shell script to set up a macOS laptop for design and development.

Check it out











Collective #514 was written by Pedro Botelho and published on Codrops.


Source: Codrops, Collective #514

Finding Inspiration In Digital Influencers

dreamt up by webguru in Uncategorized | Comments Off on Finding Inspiration In Digital Influencers

Finding Inspiration In Digital Influencers

Finding Inspiration In Digital Influencers

Suzanne Scacca



You want your client’s website to become the go-to destination for their target audience. So, you design them to look great, work perfectly and rank well in search. Is that enough? It could be, though I have a sneaking suspicion that the growing millennial and Gen Z consumer base are going to complicate that with their mobile-loving ways.

An eMarketer report from 2018 revealed that consumers’ time spent on mobile devices is about to surpass time spent watching TV:

eMarketer - TV vs mobile device time

eMarketer shows the TV versus mobile device statistics flip. (Image source: eMarketer) (Large preview)

And here’s why that matters so much:

TV is littered with celebrities. As consumers spend more time with their smartphones, there’s going to be a fundamental shift from trusting and admiring celebrities to trusting and admiring digital influencers.

In this post, I’m going to explain:

  • What a digital influencer is (as opposed to a celebrity or lifestyle influencer).
  • Why they’re so successful in building trust with their target audience.
  • How to leverage certain influencer-like qualities to attract higher levels of consistent traffic (and business) for the websites you build.

To be clear, this post has nothing to do with turning your clients’ websites into sponsor-driven money-making machines. This is about giving your website the same kind of clout as a digital influencer — and using that perceived expert status to consistently maintain high levels of traffic, engagement and referrals.

What Is An Influencer?

In the past, celebrities were mainly the ones that companies turned to promote their products or services. While that still happens today, you’re more likely to see celebrity influencers pushing luxury products.

Thanks to the Internet and social media, businesses no longer have to pay top-dollar to get a celebrity endorsement. Instead, we’re now seeing the rise of digital influencer marketing.

A digital influencer is one that’s built a brand around their expertise or knowledge. There are different ways to be an influencer, too:

  • Content creators
  • Industry experts
  • Micro-influencers (these are average joes who’ve amassed a following of more than 500)
  • Thought leaders.

In reality, you’ll find that most digital influencers cover each one of these categories. For example, you have Neil Patel:

Neil Patel on Twitter

Neil Patel has hundreds of thousands of followers and a highly engaged audience. (Image source: Neil Patel) (Large preview)

He’s an entrepreneur, content creator, thought leader, trusted expert in content marketing and has way more than 500 followers wherever you encounter him online.

That’s obviously an extreme example of a digital influencer though. How about we look at a web developer that’s established himself as an authority in his space?

This is Iain Poulson’s Twitter account:

Iain Poulson on Twitter

Iain Poulson is a micro-influencer web developer. (Image source: Iain Poulson) (Large preview)

Although his follower count and engagement levels don’t reach that of macro-influencers like Patel, it doesn’t make his words any less impactful with his target audience (on or off Twitter). The point is that he creates high-quality and engage-worthy content that his audience recognizes as such.

Regardless of the size of the influencer and the space in which they work, their words command so much authority that consumers can’t help but trust them. This is the power of the digital influencer.

This is why businesses flock to influencers for help in getting the word out about their brand. If a business can leverage that built-in authority, it can grow its follower and customer base with a solid recommendation from that influencer. Influencer Marketing Hub reports that those who’ve used influencer marketing earn $7.65, on average, for every $1.00 paid to a digital influencer.

Needless to say, digital influencers are powerful and valuable entities in the world we live in. Now, we need to look at how you can imbue your websites with digital influencer-like qualities to increase their own value on the web.

How To Turn Websites Into Digital Stars

To turn a website into a digital influencer-like entity, you have to make it embody those qualities that make digital influencers so trustworthy and powerful in the first place.

For the purposes of demonstrating what these qualities are, I’m going to use websites that represent today’s top digital influencers and/or their businesses.

Whether you’re in the process of building a new site for a client or you’re looking for a way to rebrand or upgrade one that already exists, use these tips to up the influencer factor:

1. Let the Navigation Tell Your Story

In general, the navigation (and sitemap) of a website is a very powerful tool for both your visitors as well as search engines.

The only thing is, many websites use a similarly-structured and labeled navigation. That’s fine if the website’s offer is plain and simple:

  • This is the product we sell (“Products” or “Services”).
  • This is who we are (“About” or “Team”).
  • Get in touch or buy the product (“Contact Us” or “Buy Now”).

What makes many digital influencers stand apart is that they’ve crafted a robust brand for themselves, which means they’re usually a double- or triple-threat. And they make sure the navigation highlights each of these strengths or offerings.

Social Media Examiner, for instance, demonstrates that it’s not just a blog containing posts related to social media. Social Media Examiner does it all:

Social Media Examiner mobile navigation

The Social Media Examiner mobile website navigation (Image source: Social Media Examiner) (Large preview)

As you can see, the navigation shows you all of the different ventures Social Media Examiner has going on:

  • Blogging
  • Podcasting
  • Membership
  • A live conference.

It’s an impressive list and one that will instantly demonstrate to visitors that they are the authority on social media.

The Marketing Nutz takes a similar approach with its navigation:

Marketing Nutz mobile navigation

The Marketing Nutz navigation on mobile (Image source: The Marketing Nutz) (Large preview)

This navigation, however, is less focused on authority-building content. Instead, it highlights all of the ways in which it empowers its followers to get more out of their social media efforts with:

  • Social media training
  • Information on Pam Moore as a keynote speaker
  • Free social media management tools and ebooks
  • A regularly updated blog.

In sum, your navigation needs to be able to demonstrate the website’s/brand’s expertise and value within seconds. It should also be one that has visitors thinking, “Wow! They do all that?”

2. Lead with a Strong Visual

Another way to establish authority immediately is with a strong and unique visual. This sends the signal that this website isn’t just going to be a place to get information. It’s a place to actually experience something.

Take a look at the Youpreneur website:

Youpreneur home page image

The Youpreneur’s striking image and animated text (Image source: Youpreneur) (Large preview)

What you can’t see in the screenshot above is the animation directly below the image and tagline that definitely took some time to design.

See the cursor after the word “speaker”? This is a text animation that types out and deletes different entrepreneurial titles. Speaker. Blogger. Consultant. If the banner image didn’t capture their attention, this certainly will.

Jay Baer’s personal website is another beautiful example of making a strong impression with visuals.

Jay Baer home page banner

Jay Baer uses a combination of image, colorful filter and video to make a strong first impression. (Image source: Jay Baer) (Large preview)

Not only does he include a uniquely personal photo of himself in the hero section of the home page, but he has also applied a powerful color filter atop it. Further, he leads with a call-to-action for visitors to watch his five-minute video.

Although the messaging puts the focus on the customer, these strong visuals simultaneously convey that Jay Baer is someone they need to stop and listen to.

You’ll want to strike the same balance with your own entry visuals and messaging. Make sure the text lets visitors know there’s something really valuable here to stick around for. But be savvy in how you design the visuals surrounding that message. There’s a lot you can to do to convince visitors that they’ve entered the website of authority instead of just a service provider or seller.

Recommended reading: Reasons Your Mobile App Retention Rate Might Be So Low

3. Be Ripe with Content

I touched on this point slightly in the navigation point, though I think it’s worth taking a closer look so you can see the ways influencer websites produce and disseminate a variety of content.

Here is the Single Grain blog:

Single Grain blog

Single Grain’s blog page (Image source: Single Grain) (Large preview)

Single Grain’s blog is full of new and cutting-edge posts on the subject of digital marketing. As you scroll down the page, you’ll soon see that each of the featured images is designed in the same manner. All are customly illustrated and contain a mix of visuals and light text.

This not only gives the blog a consistent and easily recognizable look, but it also gives the content an edge up when it gets shared on social media. Imagine you’re looking through your social media feed and happen upon a short post with a descriptive image attached to it. In a sea of image-less posts or ones that use meaningless stock images, this kind of visual content is sure to stand out.

Now, what’s interesting about Single Grain is that its podcasts page has a different style from the blog:

Single Grain podcast

Single Grain’s podcast page (Image source: Single Grain) (Large preview)

You can tell right away that the lightness in design and custom illustrations for the blog posts have no place here. Instead, Single Grain uses a more traditional design and layout for its Growth Everywhere podcast.

That doesn’t necessarily say anything about the kind of content covered here compared to the blog; it’s not more serious in nature nor is it created by someone with more traditional leanings. It’s simply a matter of designing for the channel. In this case, simpler and less customized makes more sense for a podcast.

As you bring together the pieces of your client’s website, don’t feel as though all of their content needs to be shoved under a single “Resources” tab and designed in the same manner.

Instead, give each content channel (e.g. blog posts, podcast episodes, video training, etc.) a separate tab and design it in a way that makes the most sense. For instance, you want visitors to spend a lot of time looking through a blog post, so you might design custom yet consistently styled graphics for each one. With something like an ebook, you’d keep it simple: show a picture of a bound book (even if it’s a digital-only book) and pair it with some intro text.

Influencers treat their different channels like sub-brands with unique identities. You should do the same.

Recommended reading: Designing For Micro-Moments

4. Confidently Collect Leads

Recently, I wrote about how to design lead gen landing pages for mobile. There were different examples included (a SaaS company, a digital magazine, a monthly subscription box company, etc.), which isn’t surprising considering how valuable lead generation is for online businesses.

That said, you’d be hard-pressed to find a digital influencer that doesn’t have a lead magnet offer on his or her website. It’s almost a guarantee.

The main difference between how some websites promote their lead gen offers and how digital influencers do it is the strength of the message and design.

This is the blog of Tim Ferriss:

Tim Ferriss lead magnet promo

Tim Ferriss’ strongly worded and designed lead magnet promo (Image source: Tim Ferriss) (Large preview)

All this is is a promotional banner asking visitors to subscribe to the blog. Take note, however, that this isn’t posed as a request. This is an invitation to something special. And it’s intense. This is because of the special way in which the banner is designed:

  • The solid black background;
  • The words “EXCLUSIVE CONTENT”;
  • The red all-capped letters;
  • The call to “GET ACCESS”.

This is not at all the kind of thing you’d see on most websites and that’s because many of them just don’t exude the kind of in-your-face confidence and authority that digital influencers do.

Kim Garst is another influencer with an eye-catching lead gen banner:

Kim Garst lead capture form

Kim Garst’s engaging lead capture form (Image source: Kim Garst) (Large preview)

Clearly, the color palette is one you can’t help but stop and look at. The teal and purple colors are pretty safe choices, but it’s the contrast of the red callouts that gives this an edge.

Also, check out the wording she uses — it’s very similar to how Ferriss gave his lead gen an air of exclusivity. With Kim’s lead gen promo, she uses strong wording like “Top Secret”, “Discover” and “A Matter of Minutes”. If visitors weren’t feeling as though they had to read any more of the content on her website, this would surely get them to reconsider.

Bottom line: to demonstrate your authority, you can’t waiver nor can you provide a soft sell (e.g. “Subscribe here”) when promoting a lead magnet. Instead, your messaging and design both need to convey the confidence and authority that tell visitors:

“Don’t miss this special opportunity to peek inside my brain and gain more valuable knowledge and skills than you could ever ask for!”

Wrapping Up

Digital influencers are a special breed, that’s for sure. But that doesn’t mean you can’t draw lessons from how they’ve managed to convey and reinforce authority through their websites.

What’s nice about digital influencer websites is that they show you that obvious cash-grab features (like affiliate advertising and gated content) aren’t necessary in order to increase conversions. By designing your website as an authority, you’ll see an increase in traffic, be able to more easily collect leads, and establish long-term trust with an audience.

The revenue increase will come naturally as visitors are dying to share the news about what they discovered.

Further Reading on SmashingMag:

Smashing Editorial
(ra, yk, il)

Source: Smashing Magazine, Finding Inspiration In Digital Influencers

SVG Web Page Components For IoT And Makers (Part 1)

dreamt up by webguru in Uncategorized | Comments Off on SVG Web Page Components For IoT And Makers (Part 1)

SVG Web Page Components For IoT And Makers (Part 1)

SVG Web Page Components For IoT And Makers (Part 1)

Richard Leddy



The IoT market is still in its early stages, but gathering steam. We are at a cusp in the history of IoT. Markets are quadrupling in the course of five years, 2015 to 2020. For web developers, this IoT growth is significant. There is already a great demand for IoT web techniques.

Many devices will be spread out geospatially, and its owners will desire remote control and management. Full web stacks must be made in order to create channels for teleoperation. Also, the interaction will be with one or more IoT devices at a time. The interaction must be in the real time of the physical world.

This discussion delves into the interface requirements using Vue.js as a catalyst and illustrates one method of webpage to device communication out of many subsitutions.

Here are some of the goals planned for this discussion:

  1. Create a single page web app SPWA that hosts groups of IoT human-machine interfaces (we may call these “panel groups”);
  2. Display lists of panel group identifiers as a result of querying a server;
  3. Display the panels of a selected group as a result of a query;
  4. Ensure that the panel display is loaded lazily and becomes animated quickly;
  5. Ensure that panels synchronize with IoT devices.

IoT And The Rapid Growth Of Web Pages

The presentation of graphics for visualization and remote control of hardware along with synchronization of web pages with real-time physical processes are within the realm of web page problem solving inherent in this IoT future.

Many of us are beginning our search for IoT presentation techniques, but there are a few web standards along with a few presentation techniques that we can begin using now. As we explore these standards and techniques together, we can join this IoT wave.

Dashboards and data visualization are in demand. Furthermore, the demand for going beyond web pages that provide forms or display lists or textual content is high. The dashboards for IoT need to be pictographic, animated. Animations must be synchronized with real-time physical processes in order to provide a veridical view of machine state to users. Machine state, such as a flame burning or not, trumps application state and provides critical information to operators, perhaps even safety information.

The dashboards require more than the visualization of data. We have to keep in mind that the things part of IoT is devices that not only have sensors but also control interfaces. In hardware implementations, MCUs are extended with switches, threshold switches, parameter settings, and more. Still, web pages may take the place of those hardware control components.

Nothing new. Computer interfaces for hardware have been around for a long time, but the rapid growth of web page use for these interfaces is part of our present experience. WebRTC and Speech API are on a development path that started in 2012. WebSockets has been developing in a similar time frame.

IoT has been in our minds for a long time. IoT has been part of the human dialog since 1832. But, IoT and wireless as we are coming to know it was envisioned by Tesla around 1926. Forbes 2018 State of Iot tells us the current market focus for IoT. Of interest to web developers, the article calls out dashboards:

“IoT early adopters or advocates prioritize dashboards, reporting, IoT use cases that provide data streams integral to analytics, advanced visualization, and data mining.”

The IoT market is huge. This Market Size article gives a prediction for the number of devices that will appear: 2018: 23.14 billion ⇒ 2025: 75.44 billion. And, it attempts to put a financial figure on it: 2014: .99 trillion ⇒ 2020: $8.90 trillion. The demand for IoT skills will be the fastest growing: IoT in Demand.

As we develop clear interfaces for controlling and monitoring devices, we encounter a new problem for developing our interfaces. All the many billions of devices will be owned by many people (or organizations). Also, each person may own any number of devices. Perhaps even some of the devices will be shared.

Modern interfaces that have been made for machine controls often have a well-defined layout specific to a particular machine or installation of a few machines. For instance, in a smart house, a high-end system will have an LCD with panels for carefully placed devices. But, as we grow with the web version of IoT, there will be any number of panels for a dynamic and even mobile stream of devices.

The management of panels for devices becomes similar to managing social connections on social web sites.

“Our user interfaces will have to be dynamic in managing which highly animated real-time panel must be displayed at any one time for each particular user.”

The dashboard is a single page web app SPWA. And, we can imagine a database of panels. So, if a single user is going to access a number of panels and configurations for his devices strewn about the planet, the SPWA needs to access panel components on demand. The panels and some of their supporting JavaScript will have to load lazily.

“Our interfaces will have to work with web page frameworks that can allow incorporating asynchronous component bindings without reinitializing their frameworks.”

Let’s use Vue.js, WebSockets, MQTT, and SVG to make our step into the IoT market.

Recommended reading: Building An Interactive Infographic With Vue.js

High-Level Architecture For An IoT Web App

When designing the interface for the IoT web page, one always has many options. One option might be to dedicate one single page to one single device. The page might even be rendered on the server side. The server would have the job of querying the device to get its sensor values and then putting the values into the appropriate places in the HTML string.

Many of us are familiar with tools that allow HTML templates to be written with special markers that indicate where to put variable values. Seeing {{temperature}} in such a template tells us and the view engine to take the temperature queried from a device and replace the {{temperature}} symbol with it. So, after waiting for the server to query the device, the device responding, rendering the page, and delivering the page, the user will finally be able to see the temperature reported by the device.

For this page per device architecture, the user may then wish to send a command to the device. No problem, he can fill out an HTML form and submit. The server might even have a route just for the device, or perhaps a little more cleverly, a route for the type of device and device ID. The server would then translate the form data into a message to send to the device, write it to some device handler and wait for an acknowledgment. Then, the server may finally respond to the post request and tell the user that everything is fine with the device.

A web page architecture for treating the IoT as a form server - looking for something better.

A web page architecture for treating the IoT as a form server — looking for something better. (Large preview)

Many CMSs work in this way for updating blog entries and the like. Nothing seems strange about it. It seems that HTML over HTTP has always had the design for getting pages that have been rendered and for sending form data to be handled by the web server. What’s more, there are thousands of CMS’s to choose from. So, in order to get our IoT system up, it seems reasonable to wade through those thousands of CMS’s to see which one is right for the job. Or, we might apply one filter on CMS’s to start with.

We have to take the real-time nature of what we are dealing with into consideration. So, while HTML in its original form is quite good for many enterprise tasks, it needs a little help in order to become the delivery mechanism for IoT management. So, we need a CMS or custom web server that helps HTML do this IoT job. We can also just think of the server as we assume CMS’s provide server functionality. We just need to keep in mind that the server has to provide event-driven animation, so the page can’t be 100% finalized static print.

Here are some parameters that might guide choices for our device-linked web page, things that it should do:

  1. Receive sensor data and other device status messages asynchronously;
  2. Render the sensor data for the page in the client (almost corollary to 1);
  3. Publish commands to a particular device or group of devices asynchronously;
  4. Optionally send commands through the server or bypass it.
  5. Securely maintain the ownership relationship between the device and the user;
  6. Manage critical device operation by either not interfering or overriding.

The list comes to mind when thinking about just one page acting as the interface to a selected device. We want to be able to communicate with the device freely when it comes to commands and data.

As for the page, we need only ask the web server for it once. We would expect that the web server (or associated application) would provide a secure communication pathway. And, the pathway does not have to be through the server, or maybe it should avoid the server altogether as the server may have higher priority tasks other than taking care of one page’s communication for data coming from sensors.

In fact, we can imagine data coming in from a sensor once a second, and we would not expect the web server itself to provide a constant second by the second update for thousands of individual sensor streams multiplied by thousands of viewers. Of course, a web server can be partitioned or set up in a load balancing framework, but there are other services that are customized for sensor delivery and marshaling commands to hardware.

The web server will need to deliver some packet so that the page may establish secure communication channels with the device. We have to be careful about sending messages on channels that don’t provide some management of the kinds of messages going through. There has to be some knowledge as to whether a device is in a mode that can be interrupted or there may be a demand for user action if a device is out of control. So, the web server can help the client to obtain the appropriate resources which can know more about the device. Messaging could be done with something like an MQTT server. And, there could be some services for preparing the MQTT server that can be initiated when the user gains access to his panel via the web server.

Because of the physical world with its real-time requirements and because of additional security considerations, our diagram becomes a little different from the original.

A single page app that talks to one MCU.

A single page app that talks to one MCU. It now interacts asynchronously with the MCU independently of the web page server. (Large preview)

We don’t get to stop here. Setting up a single page per device, even if it is responsive and handles communication well, is not what we asked for. We have to assume that a user will log in to his account and access his dashboard. From there, he will ask for some list of content projects (most likely projects he is working on). Each item in the list will refer to a number of resources. When he selects an item by clicking or tapping, he will gain access to a collection of panels, each of which will have some information about a particular resource or IoT device.

Any number of the panels delivered in response to the query generated as a result of the user’s interface action may be those panels that interact with live devices. So, as soon as a panel comes up, it will be expected to show real-time activity and to be able to send a command to a device.

How the panels are seen on the page is a design decision. They might be floating windows, or they might be boxes on a scrollable background. However that is presented, panels will be ticking off time, temperature, pressure, wind speed, or whatever else you can imagine. We expect the panels to be animated with respect to various graphic scales. Temperature can be presented as a thermometer, speed as a semicircular speed gauge, sound as a streaming waveform, and so on.

The web server has the job of delivering the right panels to the right user given queries to a database of panels and given that devices have to be physically available. What’s more, given that there will be many different kinds of devices, the panels for each device will likely be different. So, the web server should be able to deliver the pictographic information needed for rendering a panel. However, the HTML page for the dashboard should not have to be loaded with all the possible panels. There is no idea of how many there will be.

Here are some parameters that might guide choices for our dashboard page, things that it should do:

  1. Present a way of selecting groups of related device panels;
  2. Make use of simultaneous device communication mechanisms for some number of devices;
  3. Activate device panels when the user requests them;
  4. Incorporate lazily loaded graphics for unique panel designs;
  5. Make use of security tokens and parameters with respect to each panel;
  6. Maintain synchronicity with all devices under user inspection.

A single page app that talks to multiple MCU's, asynchronously and independently of the web page server.

A single page app that talks to multiple MCU’s, asynchronously and independently of the web page server. (Large preview)

We can begin to see how the game changes, but in the world of dashboard design, the game has been changing a little bit here and there for some time. We just have to narrow ourselves down to some up to date and useful page development tools to get ourselves up and going.

Let’s start with how we can render the panels. This already seems like a big job. We are imagining many different kinds of panels. But, if you ever used a music DAW, you would see how they have used graphics to make panels look like the analog devices used by bands from long ago. All the panels in DAW’s are drawn by the plugins that operate on sound. In fact, a lot of those DAW’s plugins might use SVG to render their interfaces. So, we limit ourselves to handling SVG interfaces, which in turn can be any graphic we can imagine.

Choosing SVG For Panels

Of course, I like DAWs and would use that for an example, but SVG is a web page standard. SVG is a W3C standard. It is for carrying line drawings to the web pages. SVG used to be a second class citizen on the web page, required to live in iFrames. But, since HTML5, it has been a first class citizen. Perhaps, when SVG2 comes out, that it will be able to use form elements. For now, form elements are Foreign Objects in SVG. But, that should not stop us from making SVG the substrate for panels.

SVG can be drawn, stored for display, and it can be lazily loaded. In fact, as we explore the component system we will see that SVG can be used for component templates. In this discussion, we will be using Vue.js to make components for the panels.

Drawing SVG is not difficult, because there are many line drawing programs that are easy to get. If you spend the money, you can get Adobe Illustrator, which exports SVG. Inkscape has been a goto for SVG creation for some time. It is open source and works well on Linux, but can also be run on Mac and Windows. Then, there are several web page SVG editing programs that are open source, and some SaaS versions as well.

I have been looking around for an open-source web-based SVG editor. After some looking around, I came upon SVG-Edit. You can include it in your own web pages, perhaps if you are making an SVG based blog or something.

Electric diagram in SVG ready for animation.

An electric diagram is pretty detailed, but we can obtain it easily in SVG and animate it with just a little code. (Large preview)

When you save your work to a file, SVG-Edit downloads it in your browser, and you can pick up the file from your download directory.

The picture I have drawn shows an AND gate controlling an integrator. That is not what one would usually expect to see in a panel for an MCU. The panel might have a button to feed one of the AND gate inputs, perhaps. Then it might have a display from an ADC that reads the output of the integrator. Perhaps that will be a line chart on a time axis. Most panels will have graphics that allow the user to relate to what is going on inside the MCU. And, if our circuit is going to live anywhere, it will be inside the MCU.

All the same, our electronic diagram can be used to discuss animation. What we want to do is take a look at the SVG and see where we can get at some of the DOM tags that we would like to change in some way. We can then animate the SVG by using a little vanilla JavaScript and a timer. Let’s make the AND gate blink in different colors.

The SVG that we are looking for is in the following code box. It doesn’t look very friendly for the programmer, although the user will be quite happy. Nevertheless, there are still some cues to go on for finding which DOM element we wish to operate on. First, most SVG drawing tools have a way of getting at object properties, in particular, the id attribute. SVG-Edit has a way, too. In the editor, select the AND gate and observe the toolbar. You will see a field for the id and the CSS class as well.

One of the SVG drawing tools with a way to capture the object id using the provided interface.

One of the SVG drawing tools with a way to capture the object id using the provided interface. (Large preview)

If you can’t get to an editing tool for some reason, you can open the SVG up in a browser and inspect the DOM. In any case, we have found that our gate had id = “svg_1”.

<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
 <g class="layer">
  <title>Layer 1</title>
  <path d="m80.59881,87.020171l14.714795,0m-14.714793,-11.938687l14.714797,0.000004m-0.033867,-6.543869l0,24.758504c42.377882,2.221929 43.364812,-27.139117 0,-24.758504zm47.366321,12.333056l-15.303943,0m-48.188699,-6.489897l1.454753,0l0,1.454751l-1.454753,0l0,-1.454751zm-0.068425,11.869359l1.454753,0l0,1.454753l-1.454753,0l0,-1.454753zm63.545246,-6.089294l1.454751,0l0,1.454751l-1.454751,0l0,-1.454751z" fill="#FF0000" id="svg_1" stroke="#000000"/>
  <path d="m48.58886,119.662231l18.234678,0l2.523043,-7.173309l4.128604,13.808613l4.587337,-13.987948l4.013933,13.808613l4.35797,-13.629278l4.35797,13.718944l2.408353,-6.72497l18.349357,0m-64.482612,-0.623112l1.515724,0l0,1.515728l-1.515724,0l0,-1.515728zm64.484275,-0.103111l1.515721,0l0,1.515728l-1.515721,0l0,-1.515728z" fill="#FF0000" id="svg_3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="rotate(90.3367 80.0675 119.304)"/>
  <polygon cx="108.5" cy="79.5" edge="0" fill="#ffffff" id="svg_6" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="#000000"/>
  <polygon cx="215.5" cy="192.5" edge="0" fill="#ffffff" id="svg_7" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/>
  <polygon cx="165.5" cy="164.5" edge="0" fill="#ffffff" id="svg_8" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/>
  <polygon cx="161.5" cy="138.5" edge="0" fill="#ffffff" id="svg_9" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/>
  <polygon cx="160.5" cy="161.5" edge="0" fill="#ffffff" id="svg_10" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/>
  <g id="svg_23">
   <path d="m225.016923,53.008793l0,3.419331m-4.558966,-1.709666l9.11791,0m10.303228,4.235512l-25.770656,0m-34.429182,0l24.544724,0m0.220544,-4.058194l1.543807,0l0,8.164451l-1.543807,0l0,-8.164451zm7.939567,-4.473673l1.543805,0l0,16.999955l-1.543805,0l0,-16.999955zm-34.176663,8.126854l1.474036,0l0,0.747515l-1.474036,0l0,-0.747515zm61.677552,0.018809l1.474038,0l0,0.747515l-1.474038,0l0,-0.747515z" fill="#FF0000" id="svg_4" sides="3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/>
   <polygon cx="171.5" cy="159.5" edge="43.256342" fill="#ffffff" id="svg_5" orient="x" points="223.47406005859375,91.5 186.01296997070312,113.128173828125 186.01296997070312,69.871826171875 223.47406005859375,91.5 " shape="regularPoly" sides="3" stroke="#000000" stroke-width="null" strokeWidth="null" strokecolor="#000000"/>
   <line fill="none" id="svg_12" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171" x2="186" y1="103.5" y2="103.5"/>
   <path d="m130.801817,80.659041l15.333707,0l2.12165,-4.564833l3.47178,8.787299l3.857534,-8.901421l3.375353,8.787299l3.664657,-8.673176l3.664657,8.730237l2.025206,-4.279526l15.430142,0m-54.224016,-0.396526l1.274586,0l0,0.964554l-1.274586,0l0,-0.964554zm54.225414,-0.065616l1.274584,0l0,0.964554l-1.274584,0l0,-0.964554z" fill="none" id="svg_14" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/>
   <line fill="none" id="svg_15" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171.5" x2="171.5" y1="103.75" y2="135.388167"/>
   <line fill="none" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="177.75" x2="177.75" y1="58.75" y2="80.255951"/>
   <line fill="none" id="svg_17" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="223.75" x2="266.854524" y1="91.75" y2="91.75"/>
   <line fill="none" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="241.75" x2="241.75" y1="59.75" y2="91.754167"/>
   <line fill="none" id="svg_19" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="168.25" x2="180.75" y1="135.75" y2="135.75"/>
   <line fill="none" id="svg_20" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="169.75" x2="179.25" y1="138.5" y2="138.5"/>
   <line fill="none" id="svg_22" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" x1="171" x2="179.75" y1="141.25" y2="141.25"/>
  </g>
 </g>
 </svg>

All we need now is a little JavaScript. We do take note first that the element attribute “fill” is present. Then there is just the simple program that follows:

<html>
    <head>
    </head>
<body>
        <!-- ALL THE SVG FROM ABOVE GOES HERE -->
</body>
<html>
</svg>

  // Set up a timer interval flash the color.
  var gateElement = document.getElementById("svg_1");
  if ( gateElement ) {
      setInterval( () => {
                    var fillC = gateElement.getAttribute("fill");
                    gateElement.setAttribute("fill", (fillC == "#00FF00") ? "#FF0000" : "#00FF00" );
                  }, 2000 )
    
  }

Notice that what we have is a minimal HTML page. You can cut and paste the code into your favorite editor. And, then don’t forget to cut and paste the SVG to replace the comment. My version of Chrome requires the page to be HTML in order to have the JavaScript section. So, that is one browser still treating SVG as something separate. But, it is a long way from the <iframe> days.

If you cut and paste just right, you can bring up the page and see the AND gate go from red to green over and over.

Recommended reading: SVG Circle Decomposition To Paths

Building Panels From VUE Components

We are already on our way to making any single panel come alive, but if we want to manage large collections of panels in sensible ways, we would have our work cut out for us. That would especially be the case if we simply built on our first example.

While the first example shows us how we can asynchronously change an object view, it does not show us how to tie the view to the state of any data object let alone one that manages a machine. We can certainly understand how the setInterval demonstration can be replaced by a fetch handler, but we might not even get the state of a machine from the web server that serves the SVG containing page. Also, when we get the data, our programs are now required to know about the DOM structure of the given page.

Fortunately, frameworks such as Vue have become popular, and they can save us a lot of work.

It’s easy to find out about Vue. The Vue documentation is very accessible. So, if this discussion jumps too far ahead, then you may spend some time learning about Vue on its own web site. But, there are very good discussions within the Smashing pages. Krutie Patel wrote a stunning article on making an infographic. Souvik Sarkar tells us how to build a weather dashboard with Vue.

For the first step, we should address searching for groups of panels. One reason for doing this first is that it is at the framework level of our human interactions.

The user searches for something he is interested in. Perhaps he is interested in all the devices at locations in one town. Perhaps he has many batches of liquid products and he wants to narrow down to one type of product with each batch governed by a small collection of IoT devices. So, the user will first search to get a small list.

Here is the process:

  1. Search for groups of panels by features/parameters.
  2. View a list of icons representing groups.
  3. Select an icon (click/tap).
  4. Start using panels identified with the icon when they come up.

Another reason this is a good first step is that we can use Vue in its simplest form. No build tools needed. We will just include vue.js with a script tag in HTML. In fact, we don’t even have to download it. There is a site where a working copy of vue.js is being served.

All we need is the following tag:

I copied the script tag directly from the Vue documentation about installation.

Now, we need a web page that can load icons and make them into something that clicks. Vue makes that very easy. In fact, I just wrote a little app to manage a Twitter list using Vue. It just manages text fields. As it is a tiny bit simpler than an SPWA using icons, we can have a look at it and then change it to be our desired single page app framework.

Here is part of what the page looks like:

A text-based page to use as a starting point for building a graphics application.

A text-based page to use as a starting point for building a graphics application. (Large preview)

This looks like a fairly simple page. Each outer numerical entry is a time slot with one or two tweets in it. The second tweet is optional. If you edit a tweet, Vue mechanisms update a JavaScript object. This page leaves it up to the user to click the “update entries” button to tell the server that something has changed, via its button handler function.

In order for the button handler to relay data to the server, it must change the Vue data object into a JSON string. Now, you may wonder just how difficult translating a Vue object to JSON will be. It turns out to be one line of code. You can find the line in the following source code, but if you want to find it faster, it is highlighted in the paragraph after the source code.

The page looks simple. Looks can be deceiving. Of course, the page looks simple, but is the code simple? Yes, indeed it is! Using Vue, the page manages the contents of the fields almost magically. Here is the code:

<!DOCTYPE html>
<html lang="en" prefix="og: http://ogp.me/ns#">
  <!-- define microdata scope and type -->
  <head itemscope itemtype="http://schema.org/Article">
        <title>Tweet Keeper</title>
        <style>
            body {
                margin: 2em;
            }
            .entryart {
                border: solid 1px navy;
                width: 80%;
                padding: 2px;
                padding-left: 6px;
                margin-bottom: 3px;
                background-color: #EEF4EE;
            }
        </style>
        https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js
    </head>
    <body onload="GetTweets()">  <!-- some old fashioned handling -->

        <!-- The Vue app starts here. This is the HTML part of the Vue object -->
        

mangage tweets

My personal Tweet engine. This page accesses a personal tweet page that belongs to {{tweetOwner}}.

<!-- Here is a Vue loop for generating a lit --> <ol> <li v-for="tweet in tweets"> <!-- here is the first tweet represented as an object with a lable and tweet text -->
<!-- here is the second tweet in the slot. But, notice that it is optional. -->
1">
</li> </ol> </div> var twtApp = new Vue({ el: '#tweetAppDiv', data: { tweets: [ // Where is the data? Still on the server.s ], tweetOwner : "Lucky Dude" // picked a name for demo } }); </body> </html> // Notice that you don’t have to do everything in the Vue framework. // Here we are using some native API calls var gDefaultPostInfo = { // there server is beyond simple - an example from node.js docs method: 'POST', // or 'PUT' mode: "cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "same-origin", // include, *same-origin, omit redirect: "follow", // manual, *follow, error referrer: "no-referrer", // no-referrer, *client body: "", headers:{ 'Content-Type': 'application/json' } } // // // recall the "onload" function GetTweets(event) { var url = "http://localhost:8080/twitlist1.json" // We have a fixed file name. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. twtApp.tweets = newData // the page update right away with new data. }); }); } function sendTweets() { // recall the button up above. This is not a Vue style button, but still in the Vue app. var url = "http://localhost:8080/" var data = twtApp.tweets; // GET THE DATA OUT OF VUE. That’s all folks. // // so happens that Vue pulls out the right data and stringifies it. var jdata = JSON.stringify(data); // data can be `string` or {object}! // gDefaultPostInfo.body = jdata; // that’s for fetch - not Vue related // fetch(url,gDefaultPostInfo).then(res => { // We use fetch to POST as well as GET res.json() }).then(response => { console.log('Success:', JSON.stringify(response)) // promises }).catch(error => { console.error('Error:', error) }); } // // //

So, just to highlight the amazing lines that speak to the power of the framework, let’s repeat here:

A. This is pulling the data out.

postOptionsObject.body = JSON.stringify(twtApp.tweets);

B. This is putting the data into Vue and seeing the screen update:

twtApp.tweets = JSON.parse(text)  // text is the server response

How much work is that?

It looks like there is going to be a nice way to express how data will update panels for IoT.

Now, let’s turn the tweets into clickable icons designed to fetch components from the web server.

From Tweets to Panel Fetching Icons

People like to use SVG for icons. They like that use for SVG more than for other things as far as I can tell. I am only going on the number of web sites that sell or give away icons made in SVG. The selling point is that line graphics has fewer bytes than images. And, if I were going to ask for lists of pictures with button-like behavior, I might have grabbed for PNGs or JPEGs in the days SVG was in iframes. But, we can even find libraries in the Vue contributor lists that help us to a serving of icons.

We can turn the tweets page into an icon list returned as a search result. Just a little code has to be changed. Of course, there are a few things to be careful about if we want SVG icons to be loaded as buttons. Vue provides mechanisms for putting HTML into the application. These mechanisms have to be used or DOM elements fetched from the server don’t get interpreted.

Here is the kind of rendering you can get from view if you follow your first impulse in creating a handlebars style variable location in the application DOM.

Vue will quote the HTML an insert it as text.

Vue will quote the HTML an insert it as text. (Large preview)

Here is the code that produces the result in the picture:

{{icon}}
</div> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } });

Notice that we have gone from looping over tweets to looping over icons. tweet in tweets changed into icon in iconList. Our twtApp hooks into the DOM element #tweetAppDiv, while our iconApp hooks into the DOM element #iconAppTry. Within the Vue option object, the data subobject has a tweets in the first app, and iconList in the second. The fields are both empty arrays that receive data when the fetch routine does its job.

But, we have imitated our tweet app too closely. In the code above, the iconList is an array, and the server is expected to send an array of strings. So, let’s say the server has sent us HTML, and we have it properly decoded with the array assigned to data.iconList. Then, the picture above can be seen.

Now, let’s change the code just a little. In this revised code, we can see the following:

v-html="icon">

Vue responds to the v-html syntax by putting in the DOM of the icon element. Notice that the syntax is included after the loop directive as another attribute to the span tag.

By removing the handlebars syntax and using v-html, our picture changes to something more comprehensible:

 
</div> var iconApp = new Vue({ el: '#iconAppTry2', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } });

Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics.

Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics. (Large preview)

While v-html is a quick way to do things, the Vue team recommends using components to get the desired HTML into the page. That seems like a good idea, and we shall soon set about doing that.

But, let’s use the v-html syntax for our next example.

It’s time to set up our working example for fetching SVG icons. Let’s have those icons be responsive to a button click. Once those are working, we can get the panels associated with an icon.

Let’s suppose that the SVG required for icons is stored in a database. For our example, we can just fetch a JSON file from the server. The grown-up version of the icon server would store many such files in a database, and deliver them to the page with the same mechanisms.

Also, it’s best if the SVG arrives on the page URL encoded since we will be using JSON parse. The SVG can be decoded by calling JavaScript’s decodeURIComponent function.

In order to simulate the response to searching, we can make use of several JSON files. The page can have one button for each file. Here is the code for the page:

<!DOCTYPE html>
<html lang="en" prefix="og: http://ogp.me/ns#">
  <!-- define microdata scope and type -->
  <head itemscope itemtype="http://schema.org/Article">
        <title>Search Bar</title>
        <style>
            body {
                margin: 2em;
            }
            div {
                margin: 6px;
            }
            .entryart {
                border: solid 1px navy;
                width: 80%;
                padding: 2px;
                padding-left: 6px;
                margin: 2px;
                margin-bottom: 3px;
                background-color: #EEF4EE;
            }
            .oneItem {
                background-color: #EEFFFF;
                margin: 2px;
                padding: 4px;
                border: solid 1px purple;
            }
        </style>
        https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js
    </head>
    <body>  <!-- some old fashioned handling -->

        <!-- The Vue app starts here. This is the HTML part of the Vue object -->
        

Request MCU Groups

These are groups satistfying this query: {{queryToken}}.

<!-- Here is a Vue loop for generating a lit -->

Here is one display of icons that have been fetched from the server:

Icons that might be returned from a search for MCU groups.

An artistic idea suggesting how search could return icons indicating certain groups of MCU’s to interact with. (Large preview)

The data being sent is an array with the following kind of structure:

{
 "style" : {
     "color" : "red",
     "backgroundColor" : "yellow"
 },
 "icon" : svg1,
 "name" : "thermos"
},

Here, svg1 is SVG taken from a file. Of course, a righteous server would have taken the structure from a database, where the SVG would be stored in the structure.

Here is a snippet from the above code. This is the code that fetches the JSON and places the array of structures into the Vue app. You can see the promise structure of fetch in use. The text is parsed, and in the next line, the encoded SVG is decoded. One more line, and Vue updates the page. The number of buttons in the button bar will be equal to the length of the JSON array.

fetch(url).then((response) => {  // this is now browser native
    response.text().then((text) => {
             var newData = JSON.parse(text);  // DATA UPDATE! This is it.
                newData = newData.map(obj => {
                           obj.icon = decodeURIComponent(obj.icon);
                           return(obj)
                       });
             // the page update right away with new data.  
             iconApp.iconList = newData;  
        });
});

Now, just two more snippets. The Vue app. The reader will notice that the @click directive has been included on the buttons. The data element, iconEntry.name, is passed to a method within quotes.

The method is defined within the Vue app:

Here is the snippet for the definition of methods. The methods object is added just after the data object within the app parameter object:

,
methods: {
  goGetPanel: (pname) => {
      // `this` inside methods points to the Vue instance
      alert('Hello ' + pname + '!')
  }
}

The reader should find the goGetPanel definition, and the use of it was pointed out for the @click handler. In our final application, the alert call can be replaced by a function that fetches panels from the server.

A Component Library For IoT Panels

We could just decide that panels that we fetch from the server can be HMTL or just SVG drawings, but if there are going to be many kinds of panels, we would hope that the job of creating panels could be simplified by having libraries of components to choose from. We can imagine that SVG editors could be improved to allow library components to be dropped onto pictures as part of editing. Then, if the SVG editor could output a version of the picture with component tags, then the use of Vue would allow the picture to be created while ensuring that the JavaScript automation and animation is neatly woven together. For our discussion, some hand editing can help us get there.

If we want to create panels out of Vue components, then we had better figure out how to make the components and then collect them together into something useful. We will have to switch to using command line tools provided by Vue and organize our workflow.

Components

The Vue documentation points out that the component data section (subobject) of the component definition needs to be a function that returns data. The reason for this is that Vue needs to keep data separate among the instances. So, in going from a Vue application initialization to a component definition there is another small code change.

In this first snippet of code a Vue application is being initialized:

var iconApp = new Vue({
      el: '#iconApp',
      data: {  // this is the data field that can be easily updated
      },
      methods : {
        ...
      }
});

In this new snippet of code, a component is being defined and registered. First, notice that instead of creating a new Vue instance, a component named iconic is being registered. Then, the data field returns custom data for any iconic instance that the Vue app makes. Finally, the template field is present at the end of the component registration. Any HTML that might have been written on the web page to display the component can be part of the template.

Vue.component('iconic',
          data: () => { 
            var instanceData = {
                // data fields named for the 
                // variables appearing in the template
                onevar : "test"
            }
            return(instanceData);
          },
          methods : {
            ...
          },
          template: '
This appears in every instance {{onevar}}
' });

So, we can imagine a panel with thermometers. So, if someone provided a thermometer component, we would expect a component definition somewhere in our code. As such:

Vue.component('thermometer',
          data: () => { 
            var instanceData = {
                // data fields named for the 
                // variables appearing in the template
                temperature : 0
            }
            return(instanceData);
          },
          methods : {
            ...
          },
          template: '
Some SVG will go here
' });

We are trying to create something that looks like this:

Animated thermometer application in Vue before exploring components.

Animated thermometer application in Vue before exploring components. (Large preview)

The thermometer component is very similar to the first components that you will come across in the Vue tutorials. But, it’s a little tricky to figure out how to update it. There is a better way of defining the component for reactivity using properties. And, that is in the following:

Vue.component('thermometer', {
    props: ['temperature'],
    computed : {
        y: function() {
            var t = this.temperature/100;
            var h = 54.724472;
            var y_bar = 41.176476  // starts near the top
            // pretend the scale is 1 to 100, so that the temperature is a precentage
            return((1 - t)*h + y_bar)
        },
        height : function() {
            var t = this.temperature/100;
            var h = 54.724472; // as high as the whole range
            var y_bar = 41.176476
            // pretend the scale is 1 to 100, so that the temperature is a precentage
            return(t*h)
        }
    },
    template: '#thermometer-template'
})

So, instead of representing temperature as a data element. It is represented as a property under props. Then, there is a new section, computed, that provides variables that are functions of the property. We see this.temperature being used for both y and height. These computed variables are being used in the SVG as attributes for a rectangle.

In SVG, y grows from the top down. So, when we want the rectangle to be small at the bottom of the thermometer, the y of the red box has to be lower, and the height has to be reduced so that (y + height) stays at the thermometer zero.

Notice the template field in the definition of the components. It is in fact, a document element ID. The element being referred to is a script section with the special type: type="text/x-template". The script element is where the SVG for the thermometers is. And, the SVG makes use of Vue variables and control terms so that reactivity can be defined.

Here is some of the SVG:



  
    
      
      
      
        
        

The reader can find id="thermometer-template" at the top, and looking further down to the rect elements, the computed variables can be found.

Here the variable uses are separated out. The Vue shorthand syntax for v-bind is in use, with :height="height" and the same for y:

 x="111.90748"
         :height="height"
         :y="y"

When the parent of the SVG elements sets variables that act as input to the thermometer property temperature, Vue recalculates height and y. As a result, the position and height of the red box change.

It helps to have a listing of the Vue app that makes use of the thermometer.


    
    

Set Temperature

These are groups satistfying this query: {{queryToken}}.

var thermoApp = new Vue({ el: '#thermoApp', data: { temp1 : 30, temp2 : 60, queryToken : "HEAT" }, methods : { updateTemp: function (tval1,tval2) { this.temp1 = tval1; this.temp2 = tval2; } } }); </body>

That is the whole thing. There are three buttons which call the updateTemp method of the thermoApp Vue application. The data section has two temperature variables. And, each thermometer updates its temperature when the values change.

The code for the two thermometers called out below can be found on the HTML assigned to the Vue app.

<thermometer :temperature="temp1" ></thermometer>
        <thermometer :temperature="temp2" ></thermometer>

Notice that application uses the function formalism for the method definition. Defining updateTemp this way updateTemp: function (tval1,tval2) allows for the instance variable this to be accessed.

Also, defining updateTemp this way updateTemp: (tval1,tval2) => assigns this to an internal data structure that does not react and update the view.

Assembling a Panel

Each IoT panel can be a component. Vue provides a way of defining components with subcomponents. Alternatively, there is a slot mechanism that can be used to yield a component that can wrap around any HTML content.

In the following few paragraphs, let’s look at making a panel out of subcomponents. There are two forms that follow quickly from our examples. In one case, the thermometers can be subcomponents called out in JavaScript. In another case, the components are defined independently but are mentioned in the HTML.

In both cases, the same HTML can be used for the template. Here is our panel as a template:


    

The only difference between the first detailing of the application is that a div element is surrounding the two thermometers. Vue will throw an error if the template is missing a top level DOM element. The div passes the Vue requirement, and the multiple elements may be included inside of it.

Now, we may see the two thermometers side by side. Passing the temperatures from the top to the final thermometer has values cascading down. At the top level, the panel joins the application when a single line is included in the application DOM.

<themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>

The template for the panel, although simple, seems to indicate that panels can be easily designed in term of components. It’s as if a language for just IoT components is possible.

Now, the template definition for the panel is simple enough. Here it is with the subcomponents defined independently:

Vue.component('thermo-panel', {
              props: ['temp1','temp2'],
              template: '#thermo-panel-template'
            });

That is about as much as is required to make the panel functional. It is true that this version relies on a long list of properties for defining values to be updated as messages come into the page. But, this is a good start. Updating the data object at the top level does the job of animating the thermometers. However, as the panels become complicated, there may need to be another method for showing change.

Having made mention to the other ways of specifying subcomponents, for the panel, we should take a look at it. Here it is:

Vue.component('thermo-panel', {
              props: ['temp1','temp2'],
              template: '#thermo-panel-template',
              components: {
                // a sub component for the labels
                'thermometer': {
                  props: {
                    temperature: Number,
                  },
                  template: '#thermometer-template',
                  computed : {
                    y: function() {
                        var t = this.temperature/100;
                        var h = 54.724472;
                        var y_bar = 41.176476  // starts near the top
                        // pretend the scale is 1 to 100, so that the temperature is a precentage
                        return((1 - t)*h + y_bar)
                    },
                    height : function() {
                        var t = this.temperature/100;
                        var h = 54.724472; // as high as the whole range
                        var y_bar = 41.176476
                        // pretend the scale is 1 to 100, so that the temperature is a precentage
                        return(t*h)
                    }
                  }
              }
            }
        });

There is certainly more code, but that is because the JavaScript for the thermometer component is included within the components list of thermo-panel. The two approaches do the same job, but they offer different ways of packaging component definitions.

At the moment, my preference is for the first way. It should be considerably easier to revise panels and have them retrieved dynamically if only changing template and properties is required. To this end, the independently defined components form a component library. But, although that seems better, in the following it becomes more convenient to use the second, seemingly more verbose way.

Given that we can make responsive panels out of components in clearly defined ways, I’ll explain how we can manage them as a database that can make simple queries in the next part of my article. Stay tuned!

Smashing Editorial
(dm, yk, il)

Source: Smashing Magazine, SVG Web Page Components For IoT And Makers (Part 1)