- Jump To … +
  ./source/core/animation-loop.js ./source/core/display-cycle.js ./source/core/document-root-elements.js ./source/core/document.js ./source/core/events.js ./source/core/init.js ./source/core/library.js ./source/core/random-seed.js ./source/core/shared-vars.js ./source/core/snippets.js ./source/core/system-flags.js ./source/core/user-interaction.js ./source/core/utilities.js ./source/factory/action.js ./source/factory/anchor.js ./source/factory/animation.js ./source/factory/array-pool.js ./source/factory/bezier.js ./source/factory/block.js ./source/factory/canvas.js ./source/factory/cell-fragment.js ./source/factory/cell.js ./source/factory/cog.js ./source/factory/color.js ./source/factory/conic-gradient.js ./source/factory/coordinate.js ./source/factory/crescent.js ./source/factory/drag-zone.js ./source/factory/element.js ./source/factory/emitter.js ./source/factory/filter-engine-bluenoise-data.js ./source/factory/filter-engine.js ./source/factory/filter.js ./source/factory/font-attributes.js ./source/factory/gradient.js ./source/factory/grid.js ./source/factory/group.js ./source/factory/image-asset.js ./source/factory/keyboard-zone.js ./source/factory/line-spiral.js ./source/factory/line.js ./source/factory/loom.js ./source/factory/mesh.js ./source/factory/net.js ./source/factory/noise-asset.js ./source/factory/observe-update.js ./source/factory/oval.js ./source/factory/palette.js ./source/factory/particle-force.js ./source/factory/particle-history.js ./source/factory/particle-spring.js ./source/factory/particle-world.js ./source/factory/particle.js ./source/factory/pattern.js ./source/factory/phrase.js ./source/factory/picture.js ./source/factory/polygon.js ./source/factory/polyline.js ./source/factory/quadratic.js ./source/factory/quaternion.js ./source/factory/radial-gradient.js ./source/factory/raw-asset.js ./source/factory/reaction-diffusion-asset.js ./source/factory/rectangle.js ./source/factory/render-animation.js ./source/factory/shape.js ./source/factory/spiral.js ./source/factory/sprite-asset.js ./source/factory/stack.js ./source/factory/star.js ./source/factory/state.js ./source/factory/tetragon.js ./source/factory/ticker.js ./source/factory/tracer.js ./source/factory/tween.js ./source/factory/unstacked-element.js ./source/factory/vector.js ./source/factory/video-asset.js ./source/factory/wheel.js ./source/mixin/anchor.js ./source/mixin/asset-advanced-functionality.js ./source/mixin/asset-consumer.js ./source/mixin/asset.js ./source/mixin/base.js ./source/mixin/cascade.js ./source/mixin/cell-key-functions.js ./source/mixin/delta.js ./source/mixin/display-shape.js ./source/mixin/dom.js ./source/mixin/entity.js ./source/mixin/filter.js ./source/mixin/mimic.js ./source/mixin/path.js ./source/mixin/pattern.js ./source/mixin/pivot.js ./source/mixin/position.js ./source/mixin/shape-basic.js ./source/mixin/shape-curve.js ./source/mixin/shape-path-calculation.js ./source/mixin/styles.js ./source/mixin/tween.js

- §

  # Wheel factory

  Wheel entitys are circles and part-circles rendered onto a DOM <canvas> element using the Canvas 2D API’s Path2D interface - specifically the arc() and lineTo() methods.

  - Positioning functionality for the Wheel is supplied by the position mixin, while rendering functionality comes from the entity mixin.
  - Wheel dimensions are tied closely to its radius attribute; relative dimensions are calculated using the Wheel’s Cell container’s width.
  - Wheels can use CSS color Strings for their fillStyle and strokeStyle values, alongside Gradient, RadialGradient, Color and Pattern objects.
  - They will also accept Filter objects.
  - They can use Anchor objects for user navigation.
  - They can be rendered to the canvas by including them in a Cell object’s Group.
  - They can be animated directly, or using delta animation, or act as the target for Tween animations.
  - Wheels can be cloned, and killed.
- §

  #### Demos:

  - Canvas-001 - Block and Wheel entitys (make, clone, method); drag and drop block and wheel entitys
  - Canvas-005 - Cell-locked, and Entity-locked, gradients; animating gradients by delta, and by tween
  - Canvas-007 - Apply filters at the entity, group and cell level
  - Packets-002 - Scrawl-canvas packets; save and load a range of different entitys
- §

  #### Imports

      import { constructors } from '../core/library.js';

      import { addStrings, doCreate, isa_number, mergeOver, xt, xto, Ωempty } from '../core/utilities.js';

      import baseMix from '../mixin/base.js';
      import entityMix from '../mixin/entity.js';

      import { _radian, DIMENSIONS, ENTITY, PC, T_WHEEL } from '../core/shared-vars.js';

- §

  ensureFloat - return the value provided as a floating point number of given precision; return 0 if not a number

      const ensureFloat = (val, precision) => {

          val = parseFloat(val);

          if (!isa_number(val)) val = 0;
          if (!isa_number(precision)) precision = 0;

          return parseFloat(val.toFixed(precision));
      };

- §

  #### Wheel constructor

      const Wheel = function (items = Ωempty) {

          if (!xto(items.dimensions, items.width, items.height, items.radius)) items.radius = 5;

          this.entityInit(items);

          return this;
      };

- §

  #### Wheel prototype

      const P = Wheel.prototype = doCreate();
      P.type = T_WHEEL;
      P.lib = ENTITY;
      P.isArtefact = true;
      P.isAsset = false;

- §

  #### Mixins

  - base
  - entity

      baseMix(P);
      entityMix(P);

- §

  #### Wheel attributes

  - Attributes defined in the base mixin: name.
  - Attributes defined in the position mixin: group, visibility, order, calculateOrder, stampOrder, start, startX, startY, handle, handleX, handleY, offset, offsetX, offsetY, dimensions, width, height, pivoted, mimicked, lockTo, lockXTo, lockYTo, scale, roll, noUserInteraction, noPositionDependencies, noCanvasEngineUpdates, noFilters, noPathUpdates, purge, bringToFrontOnDrag.
  - Attributes defined in the delta mixin: delta, noDeltaUpdates.
  - Attributes defined in the pivot mixin: pivot, pivotCorner, addPivotHandle, addPivotOffset, addPivotRotation.
  - Attributes defined in the mimic mixin: mimic, useMimicDimensions, useMimicScale, useMimicStart, useMimicHandle, useMimicOffset, useMimicRotation, useMimicFlip, addOwnDimensionsToMimic, addOwnScaleToMimic, addOwnStartToMimic, addOwnHandleToMimic, addOwnOffsetToMimic, addOwnRotationToMimic.
  - Attributes defined in the path mixin: path, pathPosition, addPathHandle, addPathOffset, addPathRotation, constantPathSpeed.
  - Attributes defined in the entity mixin: method, pathObject, winding, flipReverse, flipUpend, scaleOutline, lockFillStyleToEntity, lockStrokeStyleToEntity, onEnter, onLeave, onDown, onUp, fillStyle, strokeStyle, globalAlpha, globalCompositeOperation, lineWidth, lineCap, lineJoin, lineDash, lineDashOffset, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, filter.
  - Attributes defined in the anchor mixin: anchor.
  - Attributes defined in the filter mixin: filters, isStencil.

      const defaultAttributes = {

- §

  radius - the circle’s radius measured in Number pixels, or as a String% - `’10%’ - of the Cell’s width

          radius: 5,

- §

  startAngle, endAngle - the Number angles at which the rendered arc starts and ends, in degrees (not radians), with 0° and 360° set horizontally to the right (+ve x axis) of the circle’s center.

          startAngle: 0,
          endAngle: 360,

- §

  clockwise - a Boolean flag which, when true, draws the arc in a clockwise rotation between the start and end angles; a false value causes the arc to be drawn in an anti-clockwise direction.

          clockwise: true,

- §

  includeCenter - a Boolean flag which, when true, draws a line from the end angle to the center of the circle

          includeCenter: false,

- §

  closed - a Boolean flag which, when true, draws a line from the end angle to the start angle. If includeCenter has been set to true, the line will be drawn from the center of the circle to the start angle position on the circle circumference.

          closed: true,
      };
      P.defs = mergeOver(P.defs, defaultAttributes);

- §

  #### Packet management

  No additional packet functionality required

- §

  #### Clone management

  No additional clone functionality required

- §

  #### Kill management

  No additional kill functionality required

- §

  #### Get, Set, deltaSet

      const S = P.setters,
          D = P.deltaSetters;

- §

  width and height (and dimensions) values are largely irrelevant to Wheel entitys; they get used internally purely as part of the Display cycle stamp functionality.

- §

  If they are used to (delta)set the entity’s values then the radius will be set to half the supplied value with String% values calculated from the entity’s host’s width, while height and width will equalize to maintain dimensional integrity.

      S.width = function (val) {

          if (val != null) {

              const dims = this.dimensions;

              dims[0] = dims[1] = val;
              this.dimensionsHelper();
          }
      };
      D.width = function (val) {

          const dims = this.dimensions;

          dims[0] = dims[1] = addStrings(dims[0], val);
          this.dimensionsHelper();
      };

      S.height = function (val) {

          if (val != null) {

              const dims = this.dimensions;

              dims[0] = dims[1] = val;
              this.dimensionsHelper();
          }
      };
      D.height = function (val) {

          const dims = this.dimensions;

          dims[0] = dims[1] = addStrings(dims[0], val);
          this.dimensionsHelper();
      };

      S.dimensions = function (w, h) {

          this.setCoordinateHelper(DIMENSIONS, w, h);
          this.dimensionsHelper();
      };
      D.dimensions = function (w, h) {

          this.setDeltaCoordinateHelper(DIMENSIONS, w, h);
          this.dimensionsHelper();
      }

- §

  Setters for attributes specific to the Wheel entity

      S.radius = function (val) {

          this.radius = val;
          this.radiusHelper();
      };
      D.radius = function (val) {

          this.radius = addStrings(this.radius, val);
          this.radiusHelper();
      };

      S.startAngle = function (val) {

          this.startAngle = ensureFloat(val, 4);
          this.dirtyPathObject = true;
          this.dirtyFilterIdentifier = true;
      };
      D.startAngle = function (val) {

          this.startAngle += ensureFloat(val, 4);
          this.dirtyPathObject = true;
          this.dirtyFilterIdentifier = true;
      };

      S.endAngle = function (val) {

          this.endAngle = ensureFloat(val, 4);
          this.dirtyPathObject = true;
          this.dirtyFilterIdentifier = true;
      };
      D.endAngle = function (val) {

          this.endAngle += ensureFloat(val, 4);
          this.dirtyPathObject = true;
          this.dirtyFilterIdentifier = true;
      };

      S.closed = function (bool) {

          if(xt(bool)) {

              this.closed = !!bool;
              this.dirtyPathObject = true;
              this.dirtyFilterIdentifier = true;
          }
      };

      S.includeCenter = function (bool) {

          if(xt(bool)) {

              this.includeCenter = !!bool;
              this.dirtyPathObject = true;
              this.dirtyFilterIdentifier = true;
          }
      };

      S.clockwise = function (bool) {

          if(xt(bool)) {

              this.clockwise = !!bool;
              this.dirtyPathObject = true;
              this.dirtyFilterIdentifier = true;
          }
      };

- §

  #### Prototype functions

- §

  Internal functions for reconciling dimensions and radius attribute values

      P.dimensionsHelper = function () {

          const width = this.dimensions[0];

          if (width.substring) this.radius = `${(parseFloat(width) / 2)}%`;
          else this.radius = (width / 2);

          this.dirtyDimensions = true;
          this.dirtyFilterIdentifier = true;
      };
      P.radiusHelper = function () {

          const radius = this.radius,
              dims = this.dimensions;

          if (radius.substring) dims[0] = dims[1] = (parseFloat(radius) * 2) + PC;
          else dims[0] = dims[1] = (radius * 2);

          this.dirtyDimensions = true;
          this.dirtyFilterIdentifier = true;
      };

- §

  Dimensions calculations - overwrites mixin/position.js function

      P.cleanDimensionsAdditionalActions = function () {

          const radius = this.radius,
              dims = this.currentDimensions,
              calculatedRadius = (radius.substring) ? (parseFloat(radius) / 100) * dims[0] : radius;

          if (dims[0] !== calculatedRadius * 2) {

              dims[1] = dims[0];
              this.currentRadius = dims[0] / 2;
          }
          else this.currentRadius = calculatedRadius;
      };

- §

  Calculate the Wheel entity’s Path2D object

      P.cleanPathObject = function () {

          this.dirtyPathObject = false;

          if (!this.noPathUpdates || !this.pathObject) {

              const p = this.pathObject = new Path2D();

              const handle = this.currentStampHandlePosition,
                  scale = this.currentScale,
                  radius = this.currentRadius * scale,
                  x = radius - (handle[0] * scale),
                  y = radius - (handle[1] * scale),
                  starts = this.startAngle * _radian,
                  ends = this.endAngle * _radian;

              p.arc(x, y, radius, starts, ends, !this.clockwise);

              if (this.includeCenter) {

                  p.lineTo(x, y);
                  p.closePath();
              }
              else if (this.closed) p.closePath();
          }
      };

- §

  #### Factory

      scrawl.makeWheel({

          name: 'mywheel-fill',
          radius: 50,
          startAngle: 15,
          endAngle: -15,
          includeCenter: true,

          startX: 475,
          startY: 475,

          fillStyle: 'purple',
          strokeStyle: 'gold',

          lineWidth: 6,
          lineJoin: 'round',
          shadowOffsetX: 4,
          shadowOffsetY: 4,
          shadowBlur: 2,
          shadowColor: 'black',

      }).clone({

          name: 'mywheel-draw',
          startX: 325,

          method: 'draw',
          sharedState: true,
      });

      export const makeWheel = function (items) {

          if (!items) return false;
          return new Wheel(items);
      };

      constructors.Wheel = Wheel;