diff --git a/CHANGELOG.md b/CHANGELOG.md
index b570a29352..a26f46cab5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 ### Improvements
 - Points with small radii or thin strokes are rendered better (#1021)
+- When only updating point styles, don't recompute geometry transforms (#1022)
 
 ## Version 0.19.6
 
diff --git a/src/webgl/pointFeature.js b/src/webgl/pointFeature.js
index 9b751ae316..972802b4ab 100644
--- a/src/webgl/pointFeature.js
+++ b/src/webgl/pointFeature.js
@@ -128,8 +128,11 @@ var webgl_pointFeature = function (arg) {
 
   /**
    * Create and style the data needed to render the points.
+   *
+   * @param {boolean} onlyStyle if true, use the existing geoemtry and just
+   *    recalculate the style.
    */
-  function createGLPoints() {
+  function createGLPoints(onlyStyle) {
     // unit and associated data is not used when drawing sprite
     var i, j, numPts = m_this.data().length,
         unit = pointPolygon(0, 0, 1, 1),
@@ -158,31 +161,38 @@ var webgl_pointFeature = function (arg) {
     fillOpacityFunc = m_this.style.get('fillOpacity');
     fillColorFunc = m_this.style.get('fillColor');
 
-    /* It is more efficient to do a transform on a single array rather than on
-     * an array of arrays or an array of objects. */
-    for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
-      posVal = posFunc(data[i], i);
-      position[i3] = posVal.x;
-      position[i3 + 1] = posVal.y;
-      // ignore the z values until we support them
-      position[i3 + 2] = 0;  // posVal.z || 0;
-    }
-    position = transform.transformCoordinates(
-      m_this.gcs(), m_this.layer().map().gcs(), position, 3);
-    m_origin = new Float32Array(m_this.style.get('origin')(position));
-    if (m_origin[0] || m_origin[1] || m_origin[2]) {
+    if (!onlyStyle) {
+      /* It is more efficient to do a transform on a single array rather than on
+       * an array of arrays or an array of objects. */
       for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
-        position[i3] -= m_origin[0];
-        position[i3 + 1] -= m_origin[1];
-        position[i3 + 2] -= m_origin[2];
+        posVal = posFunc(data[i], i);
+        position[i3] = posVal.x;
+        position[i3 + 1] = posVal.y;
+        // ignore the z values until we support them
+        position[i3 + 2] = 0;  // posVal.z || 0;
       }
-    }
-    m_modelViewUniform.setOrigin(m_origin);
+      position = transform.transformCoordinates(
+        m_this.gcs(), m_this.layer().map().gcs(), position, 3);
+      m_origin = new Float32Array(m_this.style.get('origin')(position));
+      if (m_origin[0] || m_origin[1] || m_origin[2]) {
+        for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
+          position[i3] -= m_origin[0];
+          position[i3 + 1] -= m_origin[1];
+          position[i3 + 2] -= m_origin[2];
+        }
+      }
+      m_modelViewUniform.setOrigin(m_origin);
 
-    posBuf = util.getGeomBuffer(geom, 'pos', vpf * numPts * 3);
+      posBuf = util.getGeomBuffer(geom, 'pos', vpf * numPts * 3);
 
-    if (m_primitiveShape !== 'sprite') {
-      unitBuf = util.getGeomBuffer(geom, 'unit', vpf * numPts * 2);
+      if (m_primitiveShape !== 'sprite') {
+        unitBuf = util.getGeomBuffer(geom, 'unit', vpf * numPts * 2);
+      }
+      indices = geom.primitive(0).indices();
+      if (!(indices instanceof Uint16Array) || indices.length !== vpf * numPts) {
+        indices = new Uint16Array(vpf * numPts);
+        geom.primitive(0).setIndices(indices);
+      }
     }
 
     radius = util.getGeomBuffer(geom, 'radius', vpf * numPts);
@@ -193,17 +203,14 @@ var webgl_pointFeature = function (arg) {
     fill = util.getGeomBuffer(geom, 'fill', vpf * numPts);
     fillOpacity = util.getGeomBuffer(geom, 'fillOpacity', vpf * numPts);
     fillColor = util.getGeomBuffer(geom, 'fillColor', vpf * numPts * 3);
-    indices = geom.primitive(0).indices();
-    if (!(indices instanceof Uint16Array) || indices.length !== vpf * numPts) {
-      indices = new Uint16Array(vpf * numPts);
-      geom.primitive(0).setIndices(indices);
-    }
 
     for (i = ivpf = ivpf3 = iunit = i3 = 0; i < numPts; i += 1, i3 += 3) {
       item = data[i];
-      if (m_primitiveShape !== 'sprite') {
-        for (j = 0; j < unit.length; j += 1, iunit += 1) {
-          unitBuf[iunit] = unit[j];
+      if (!onlyStyle) {
+        if (m_primitiveShape !== 'sprite') {
+          for (j = 0; j < unit.length; j += 1, iunit += 1) {
+            unitBuf[iunit] = unit[j];
+          }
         }
       }
       /* We can ignore the indicies (they will all be zero) */
@@ -216,9 +223,11 @@ var webgl_pointFeature = function (arg) {
       fillOpacityVal = fillOpacityFunc(item, i);
       fillColorVal = fillColorFunc(item, i);
       for (j = 0; j < vpf; j += 1, ivpf += 1, ivpf3 += 3) {
-        posBuf[ivpf3] = position[i3];
-        posBuf[ivpf3 + 1] = position[i3 + 1];
-        posBuf[ivpf3 + 2] = position[i3 + 2];
+        if (!onlyStyle) {
+          posBuf[ivpf3] = position[i3];
+          posBuf[ivpf3 + 1] = position[i3 + 1];
+          posBuf[ivpf3 + 2] = position[i3 + 2];
+        }
         radius[ivpf] = radiusVal;
         stroke[ivpf] = strokeVal;
         strokeWidth[ivpf] = strokeWidthVal;
@@ -234,9 +243,20 @@ var webgl_pointFeature = function (arg) {
       }
     }
 
-    geom.boundsDirty(true);
-    m_mapper.modified();
-    m_mapper.boundsDirtyTimestamp().modified();
+    if (!onlyStyle) {
+      geom.boundsDirty(true);
+      m_mapper.modified();
+      m_mapper.boundsDirtyTimestamp().modified();
+    } else {
+      m_mapper.updateSourceBuffer('radius');
+      m_mapper.updateSourceBuffer('stroke');
+      m_mapper.updateSourceBuffer('strokeWidth');
+      m_mapper.updateSourceBuffer('strokeColor');
+      m_mapper.updateSourceBuffer('strokeOpacity');
+      m_mapper.updateSourceBuffer('fill');
+      m_mapper.updateSourceBuffer('fillColor');
+      m_mapper.updateSourceBuffer('fillOpacity');
+    }
   }
 
   /**
@@ -468,7 +488,7 @@ var webgl_pointFeature = function (arg) {
    * @returns {this}
    */
   this._build = function () {
-    createGLPoints();
+    createGLPoints(m_this.dataTime().timestamp() < m_this.buildTime().timestamp());
     if (!m_this.renderer().contextRenderer().hasActor(m_actor)) {
       m_this.renderer().contextRenderer().addActor(m_actor);
     }
diff --git a/src/webgl/pointFeaturePoly.frag b/src/webgl/pointFeaturePoly.frag
index 35c06e7043..284e20445c 100644
--- a/src/webgl/pointFeaturePoly.frag
+++ b/src/webgl/pointFeaturePoly.frag
@@ -8,21 +8,19 @@ varying vec4 fillColorVar;
 varying vec4 strokeColorVar;
 varying float radiusVar;
 varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
 varying vec3 unitVar;  // distinct for square/triangle
 
 void main () {
   vec4 strokeColor, fillColor;
   float endStep;
   // No stroke or fill implies nothing to draw
-  if (fillVar == 0.0 && strokeVar == 0.0)
+  if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0)
     discard;
   float rad = length(unitVar.xy); // distinct for square/triangle
   if (rad > 1.0)
     discard;
   // If there is no stroke, the fill region should transition to nothing
-  if (strokeVar == 0.0) {
+  if (strokeColorVar.a == 0.0) {
     strokeColor = vec4(fillColorVar.rgb, 0.0);
     endStep = 1.0;
   } else {
@@ -30,7 +28,7 @@ void main () {
     endStep = radiusVar / (radiusVar + strokeWidthVar);
   }
   // Likewise, if there is no fill, the stroke should transition to nothing
-  if (fillVar == 0.0)
+  if (fillColorVar.a == 0.0)
     fillColor = vec4(strokeColor.rgb, 0.0);
   else
     fillColor = fillColorVar;
diff --git a/src/webgl/pointFeaturePoly.vert b/src/webgl/pointFeaturePoly.vert
index 07e5a41b35..a145f59fbd 100644
--- a/src/webgl/pointFeaturePoly.vert
+++ b/src/webgl/pointFeaturePoly.vert
@@ -20,35 +20,29 @@ varying vec4 fillColorVar;
 varying vec4 strokeColorVar;
 varying float radiusVar;
 varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
 attribute vec2 unit; // for non-sprite
 varying vec3 unitVar; // for non-sprite
 
 void main(void)
 {
   strokeWidthVar = strokeWidth;
+  fillColorVar = vec4(fillColor, fillOpacity);
+  strokeColorVar = vec4(strokeColor, strokeOpacity);
   // No stroke or fill implies nothing to draw
   if (stroke < 1.0 || strokeWidth <= 0.0 || strokeOpacity <= 0.0) {
-    strokeVar = 0.0;
+    strokeColorVar.a = 0.0;
     strokeWidthVar = 0.0;
   }
-  else
-    strokeVar = 1.0;
   if (fill < 1.0 || radius <= 0.0 || fillOpacity <= 0.0)
-    fillVar = 0.0;
-  else
-    fillVar = 1.0;
+    fillColorVar.a = 0.0;
   /* If the point has no visible pixels, skip doing computations on it. */
-  if (fillVar == 0.0 && strokeVar == 0.0) {
+  if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0) {
     gl_Position = vec4(2, 2, 0, 1);
     return;
   }
-  fillColorVar = vec4 (fillColor, fillOpacity);
-  strokeColorVar = vec4 (strokeColor, strokeOpacity);
   radiusVar = radius;
   // for non-sprite
-  unitVar = vec3 (unit, 1.0);
+  unitVar = vec3(unit, 1.0);
   vec4 p = (projectionMatrix * modelViewMatrix * vec4(pos, 1.0)).xyzw;
   if (p.w != 0.0) {
     p = p / p.w;
diff --git a/src/webgl/pointFeatureSprite.frag b/src/webgl/pointFeatureSprite.frag
index fcaf263797..f463897315 100644
--- a/src/webgl/pointFeatureSprite.frag
+++ b/src/webgl/pointFeatureSprite.frag
@@ -8,21 +8,19 @@ varying vec4 fillColorVar;
 varying vec4 strokeColorVar;
 varying float radiusVar;
 varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
 // the square/triangle shade defines unitVar
 
 void main () {
   vec4 strokeColor, fillColor;
   float endStep;
   // No stroke or fill implies nothing to draw
-  if (fillVar == 0.0 && strokeVar == 0.0)
+  if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0)
     discard;
   float rad = 2.0 * length(gl_PointCoord - vec2(0.5));  // distinct for sprite
   if (rad > 1.0)
     discard;
   // If there is no stroke, the fill region should transition to nothing
-  if (strokeVar == 0.0) {
+  if (strokeColorVar.a == 0.0) {
     strokeColor = vec4(fillColorVar.rgb, 0.0);
     endStep = 1.0;
   } else {
@@ -30,7 +28,7 @@ void main () {
     endStep = radiusVar / (radiusVar + strokeWidthVar);
   }
   // Likewise, if there is no fill, the stroke should transition to nothing
-  if (fillVar == 0.0)
+  if (fillColorVar.a == 0.0)
     fillColor = vec4(strokeColor.rgb, 0.0);
   else
     fillColor = fillColorVar;
diff --git a/src/webgl/pointFeatureSprite.vert b/src/webgl/pointFeatureSprite.vert
index 572100e042..e9069c0674 100644
--- a/src/webgl/pointFeatureSprite.vert
+++ b/src/webgl/pointFeatureSprite.vert
@@ -20,31 +20,25 @@ varying vec4 fillColorVar;
 varying vec4 strokeColorVar;
 varying float radiusVar;
 varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
 // non-sprite has ither definitions.
 
 void main(void)
 {
   strokeWidthVar = strokeWidth;
+  fillColorVar = vec4(fillColor, fillOpacity);
+  strokeColorVar = vec4(strokeColor, strokeOpacity);
   // No stroke or fill implies nothing to draw
   if (stroke < 1.0 || strokeWidth <= 0.0 || strokeOpacity <= 0.0) {
-    strokeVar = 0.0;
+    strokeColorVar.a = 0.0;
     strokeWidthVar = 0.0;
   }
-  else
-    strokeVar = 1.0;
   if (fill < 1.0 || radius <= 0.0 || fillOpacity <= 0.0)
-    fillVar = 0.0;
-  else
-    fillVar = 1.0;
+    fillColorVar.a = 0.0;
   /* If the point has no visible pixels, skip doing computations on it. */
-  if (fillVar == 0.0 && strokeVar == 0.0) {
+  if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0) {
     gl_Position = vec4(2, 2, 0, 1);
     return;
   }
-  fillColorVar = vec4 (fillColor, fillOpacity);
-  strokeColorVar = vec4 (strokeColor, strokeOpacity);
   radiusVar = radius;
   // for sprite
   gl_Position = (projectionMatrix * modelViewMatrix * vec4(pos, 1.0)).xyzw;