<div class="stage">
  <i class="target" id="raw"></i>
  <span class="label">Raw value</span>
</div>
<div class="stage">
  <i class="target" id="interpolated"></i>
  <span class="label">Interpolated value</span>
</div>
body {
  background-color: rgb(2, 62, 80);
  display: flex;
  min-height: 100vh;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  color: #fff;
  font-size: 14px;
}

.stage {
  width: 40vw;
  height: 40vw;
  border: 1px solid #fff;
  margin: 1vw;
  position: relative;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3E%3Cpath d='M0 0v10h10' stroke='rgba(255,255,255,0.15)' fill='none'/%3E%3C/svg%3E");
}

.target {
  width: 5%;
  height: 5%;
  background: #fff;
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  transition-property: top, left;
  transition-duration: 200ms;
  transition-timing-function: ease-out;
}

.label {
  position: absolute;
  bottom: calc(100% + 0.5vw);
  left: 0;
  right: 0;
  text-align: center;
}
interface Coordinates {
  lat: number;
  lng: number;
};


const interpolateCoordinates = (interpolation: number = 0.5): {
  get: () => Coordinates | null;
  set: (newValue: Coordinates) => Coordinates;
} => {
  // Initial states
  let lastValue: Coordinates | null = null;
  let currentValue: Coordinates | null = null;
  
  /**
   * Gets the interpolated coordinates between the last and current values
   */
  const get = (): Coordinates | null => {
    if (!lastValue || !currentValue) return null;
    
    // Calculate difference in stored values
    const latDiff = (currentValue.lat - lastValue.lat);
    const lngDiff = (currentValue.lng - lastValue.lng);
    
    // Calculate interpolated values
    return {
      lat: lastValue.lat + (latDiff * interpolation),
      lng: lastValue.lng + (lngDiff * interpolation),
    };
  };
  
  /**
   * Stores the current interpolation as the last value and updates the current value
   */
  const set = (newValue: Coordinates): Coordinates => {
    // Update last value with current interpolated value if available
    const interpolatedValue = get() ?? newValue;
    lastValue = {...interpolatedValue};
    
    // Update current value
    currentValue = {...newValue};
    
    // Return new interpolated value
    return get();
  };
  
  
  return {
    get,
    set,
  };
};


// Demo
const coordinates = interpolateCoordinates(0.1);

const targetRaw = document.getElementById('raw');
const targetInterpolated = document.getElementById('interpolated');

setInterval(() => {
  // Generate random coordinates
  const newCoordinates: Coordinates = {
    lat: Math.random() * 100,
    lng: Math.random() * 100,
  };
  
  // Use raw new coordinates
  targetRaw.style.top = `${newCoordinates.lat}%`;
  targetRaw.style.left = `${newCoordinates.lng}%`;
  
  // Interpolate coordinates
  const interpolated = coordinates.set(newCoordinates);
  targetInterpolated.style.top = `${interpolated.lat}%`;
  targetInterpolated.style.left = `${interpolated.lng}%`;
}, 200);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.