Merge pull request #235 from mapbox/transitions
support for style transitions
This commit is contained in:
@@ -5,12 +5,34 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
// Stores a premultiplied color, with all four channels ranging from 0..1
|
||||
typedef std::array<float, 4> Color;
|
||||
|
||||
struct PropertyTransition {
|
||||
uint16_t duration = 0;
|
||||
uint16_t delay = 0;
|
||||
};
|
||||
|
||||
enum class TransitionablePropertyKey {
|
||||
Translate = 1,
|
||||
FillColor = 2,
|
||||
StrokeColor = 3,
|
||||
Opacity = 4,
|
||||
Width = 5,
|
||||
Offset = 6,
|
||||
Color = 7,
|
||||
DashArray = 8,
|
||||
Radius = 9,
|
||||
Blur = 10,
|
||||
Halo = 11,
|
||||
HaloRadius = 12,
|
||||
HaloBlur = 13,
|
||||
};
|
||||
|
||||
enum class Winding {
|
||||
EvenOdd = 1,
|
||||
NonZero = 2
|
||||
@@ -63,13 +85,19 @@ struct FunctionProperty {
|
||||
struct IconClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
PropertyTransition translate_transition;
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
FunctionProperty size;
|
||||
Color color = {{ 1, 1, 1, 1 }};
|
||||
PropertyTransition color_transition;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::string image;
|
||||
FunctionProperty radius = 0;
|
||||
PropertyTransition radius_transition;
|
||||
FunctionProperty blur = 0;
|
||||
PropertyTransition blur_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct IconProperties {
|
||||
@@ -87,12 +115,19 @@ struct IconProperties {
|
||||
struct LineClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
PropertyTransition translate_transition;
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
FunctionProperty width;
|
||||
PropertyTransition width_transition;
|
||||
FunctionProperty offset;
|
||||
PropertyTransition offset_transition;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
PropertyTransition color_transition;
|
||||
std::array<FunctionProperty, 2> dash_array = {{ 1, -1 }};
|
||||
PropertyTransition dash_array_transition;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct LineProperties {
|
||||
@@ -109,13 +144,18 @@ struct LineProperties {
|
||||
struct FillClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
PropertyTransition translate_transition;
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Winding winding = Winding::NonZero;
|
||||
FunctionProperty antialias = true;
|
||||
Color fill_color = {{ 0, 0, 0, 1 }};
|
||||
PropertyTransition fill_color_transition;
|
||||
Color stroke_color = {{ 0, 0, 0, std::numeric_limits<float>::infinity() }};
|
||||
PropertyTransition stroke_color_transition;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::string image;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct FillProperties {
|
||||
@@ -133,15 +173,22 @@ struct FillProperties {
|
||||
struct TextClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
PropertyTransition translate_transition;
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
PropertyTransition color_transition;
|
||||
Color halo = {{ 1, 1, 1, 0.75 }};
|
||||
PropertyTransition halo_transition;
|
||||
FunctionProperty halo_radius = 0.25f;
|
||||
PropertyTransition halo_radius_transition;
|
||||
FunctionProperty halo_blur = 1.0f;
|
||||
PropertyTransition halo_blur_transition;
|
||||
FunctionProperty size = 12.0f;
|
||||
FunctionProperty rotate = 0.0f;
|
||||
FunctionProperty alwaysVisible = false;
|
||||
FunctionProperty always_visible = false;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct TextProperties {
|
||||
@@ -154,13 +201,16 @@ struct TextProperties {
|
||||
float halo_blur = 1.0f;
|
||||
float size = 12.0f;
|
||||
float rotate = 0.0f;
|
||||
bool alwaysVisible = false;
|
||||
bool always_visible = false;
|
||||
float opacity = 1.0;
|
||||
};
|
||||
|
||||
struct BackgroundClass {
|
||||
Color color = {{ 1, 1, 1, 1 }};
|
||||
PropertyTransition color_transition;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct BackgroundProperties {
|
||||
@@ -171,7 +221,10 @@ struct BackgroundProperties {
|
||||
struct RasterClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
PropertyTransition translate_transition;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct RasterProperties {
|
||||
@@ -183,6 +236,8 @@ struct RasterProperties {
|
||||
struct CompositeClass {
|
||||
FunctionProperty enabled = true;
|
||||
FunctionProperty opacity = 1;
|
||||
PropertyTransition opacity_transition;
|
||||
std::set<std::string> specifiers;
|
||||
};
|
||||
|
||||
struct CompositeProperties {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <llmr/style/layer_description.hpp>
|
||||
#include <llmr/style/class_description.hpp>
|
||||
#include <llmr/geometry/sprite_atlas.hpp>
|
||||
#include <llmr/util/transition.hpp>
|
||||
#include <llmr/util/uv.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -32,6 +34,12 @@ public:
|
||||
size_t layerCount() const;
|
||||
void cascade(float z);
|
||||
|
||||
bool needsTransition() const;
|
||||
void updateTransitions(time now);
|
||||
void cancelTransitions();
|
||||
|
||||
void setDefaultTransitionDuration(uint64_t duration = 0);
|
||||
|
||||
public:
|
||||
std::shared_ptr<Sprite> sprite;
|
||||
|
||||
@@ -40,8 +48,7 @@ public:
|
||||
std::vector<LayerDescription> layers;
|
||||
std::map<std::string, ClassDescription> classes;
|
||||
|
||||
|
||||
// This are applied settings.
|
||||
// Currently applied settings.
|
||||
std::set<std::string> appliedClasses;
|
||||
struct {
|
||||
BackgroundProperties background;
|
||||
@@ -51,7 +58,47 @@ public:
|
||||
std::map<std::string, TextProperties> texts;
|
||||
std::map<std::string, RasterProperties> rasters;
|
||||
std::map<std::string, CompositeProperties> composites;
|
||||
std::map<std::string, std::map<TransitionablePropertyKey, std::string>> effective_classes;
|
||||
} computed;
|
||||
|
||||
private:
|
||||
bool transitionInProgress(std::string layer_name, TransitionablePropertyKey key);
|
||||
bool transitionExists(std::string layer_name, TransitionablePropertyKey key);
|
||||
bool inNeedOfTransition(std::string layer_name, TransitionablePropertyKey key);
|
||||
uint64_t transitionDuration(std::string layer_name, TransitionablePropertyKey key);
|
||||
uint64_t transitionDelay(std::string layer_name, TransitionablePropertyKey key);
|
||||
|
||||
private:
|
||||
// Last applied settings.
|
||||
struct {
|
||||
BackgroundProperties background;
|
||||
std::map<std::string, FillProperties> fills;
|
||||
std::map<std::string, LineProperties> lines;
|
||||
std::map<std::string, IconProperties> icons;
|
||||
std::map<std::string, TextProperties> texts;
|
||||
std::map<std::string, RasterProperties> rasters;
|
||||
std::map<std::string, CompositeProperties> composites;
|
||||
std::map<std::string, std::map<TransitionablePropertyKey, std::string>> effective_classes;
|
||||
} previous;
|
||||
|
||||
// Settings values currently being transitioned.
|
||||
struct {
|
||||
BackgroundProperties background;
|
||||
std::map<std::string, FillProperties> fills;
|
||||
std::map<std::string, LineProperties> lines;
|
||||
std::map<std::string, IconProperties> icons;
|
||||
std::map<std::string, TextProperties> texts;
|
||||
std::map<std::string, RasterProperties> rasters;
|
||||
std::map<std::string, CompositeProperties> composites;
|
||||
} transitioning;
|
||||
|
||||
std::map<std::string, std::map<TransitionablePropertyKey, PropertyTransition>> properties_to_transition;
|
||||
std::map<std::string, std::map<TransitionablePropertyKey, std::shared_ptr<util::transition>>> transitions;
|
||||
uint64_t default_transition_duration = 0;
|
||||
bool initial_render_complete = false;
|
||||
|
||||
mutable uv::rwlock mtx;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
Value parseValue(JSVal value);
|
||||
FunctionProperty::fn parseFunctionType(JSVal type);
|
||||
FunctionProperty parseFunction(JSVal value);
|
||||
PropertyTransition parseTransition(JSVal value, std::string property_name);
|
||||
|
||||
private:
|
||||
std::map<std::string, const rapidjson::Value *> constants;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
#include <llmr/util/time.hpp>
|
||||
#include <llmr/style/properties.hpp>
|
||||
|
||||
namespace llmr {
|
||||
namespace util {
|
||||
@@ -19,39 +20,45 @@ public:
|
||||
duration(duration) {}
|
||||
|
||||
inline float progress(time now) const {
|
||||
if (duration == 0) return 1;
|
||||
if (start > now) return 0;
|
||||
|
||||
return (float)(now - start) / duration;
|
||||
}
|
||||
|
||||
virtual state update(time now) const = 0;
|
||||
virtual ~transition();
|
||||
|
||||
protected:
|
||||
double interpolateDouble(double from, double to, double t) const;
|
||||
float interpolateFloat(float from, float to, double t) const;
|
||||
Color interpolateColor(Color from, Color to, double t) const;
|
||||
std::array<float, 2> interpolateFloatArray(std::array<float, 2> from, std::array<float, 2> to, double t) const;
|
||||
|
||||
protected:
|
||||
const time start, duration;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ease_transition : public transition {
|
||||
public:
|
||||
// Disable automatic casts.
|
||||
template <typename T1, typename T2>
|
||||
inline ease_transition(double from, double to, double& value, T1 start, T2 duration) = delete;
|
||||
ease_transition(T from, T to, T& value, time start, time duration)
|
||||
: transition(start, duration),
|
||||
from(from),
|
||||
to(to),
|
||||
value(value) {}
|
||||
|
||||
// Actual constructor.
|
||||
ease_transition(double from, double to, double& value, time start, time duration);
|
||||
state update(time now) const;
|
||||
|
||||
private:
|
||||
const double from, to;
|
||||
double& value;
|
||||
const T from, to;
|
||||
T& value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class timeout : public transition {
|
||||
public:
|
||||
// Disable automatic casts.
|
||||
template <typename T1, typename T2>
|
||||
inline timeout(T final_value, T& value, T1 start, T2 duration) = delete;
|
||||
|
||||
// Actual constructor.
|
||||
timeout(T final_value, T& value, time start, time duration)
|
||||
: transition(start, duration),
|
||||
final_value(final_value),
|
||||
|
||||
@@ -374,17 +374,15 @@ bool Map::getDebug() const {
|
||||
}
|
||||
|
||||
void Map::toggleRaster() {
|
||||
style.setDefaultTransitionDuration(300);
|
||||
style.cancelTransitions();
|
||||
|
||||
auto it = sources.find("satellite");
|
||||
if (it != sources.end()) {
|
||||
Source &satellite_source = *it->second;
|
||||
|
||||
if (satellite_source.enabled) {
|
||||
satellite_source.enabled = false;
|
||||
|
||||
auto style_class = style.appliedClasses.find("satellite");
|
||||
if (style_class != style.appliedClasses.end()) {
|
||||
style.appliedClasses.erase(style_class);
|
||||
}
|
||||
style.appliedClasses.erase("satellite");
|
||||
} else {
|
||||
satellite_source.enabled = true;
|
||||
style.appliedClasses.insert("satellite");
|
||||
@@ -458,6 +456,12 @@ void Map::prepare() {
|
||||
style.cascade(state.getNormalizedZoom());
|
||||
}
|
||||
|
||||
animationTime = util::now();
|
||||
if (style.needsTransition()) {
|
||||
style.updateTransitions(animationTime);
|
||||
update();
|
||||
}
|
||||
|
||||
// Allow the sprite atlas to potentially pull new sprite images if needed.
|
||||
if (style.sprite && style.sprite->isLoaded()) {
|
||||
spriteAtlas.update(*style.sprite);
|
||||
|
||||
@@ -59,9 +59,9 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) {
|
||||
// Use a common start time for all of the transitions to avoid divergent transitions.
|
||||
time start = util::now();
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition>(current.x, final.x, current.x, start, duration));
|
||||
std::make_shared<util::ease_transition<double>>(current.x, final.x, current.x, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition>(current.y, final.y, current.y, start, duration));
|
||||
std::make_shared<util::ease_transition<double>>(current.y, final.y, current.y, start, duration));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,12 +250,12 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
|
||||
} else {
|
||||
// Use a common start time for all of the transitions to avoid divergent transitions.
|
||||
time start = util::now();
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition>(
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition<double>>(
|
||||
current.scale, final.scale, current.scale, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition>(current.x, final.x, current.x, start, duration));
|
||||
std::make_shared<util::ease_transition<double>>(current.x, final.x, current.x, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition>(current.y, final.y, current.y, start, duration));
|
||||
std::make_shared<util::ease_transition<double>>(current.y, final.y, current.y, start, duration));
|
||||
}
|
||||
|
||||
const double s = final.scale * util::tileSize;
|
||||
@@ -335,7 +335,7 @@ void Transform::_setAngle(double new_angle, const time duration) {
|
||||
current.angle = final.angle;
|
||||
} else {
|
||||
time start = util::now();
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition>(
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition<double>>(
|
||||
current.angle, final.angle, current.angle, start, duration));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -477,42 +477,82 @@ FunctionProperty StyleParser::parseFunction(JSVal value) {
|
||||
return property;
|
||||
}
|
||||
|
||||
PropertyTransition StyleParser::parseTransition(JSVal value, std::string property_name) {
|
||||
uint16_t duration = 0, delay = 0;
|
||||
std::string transition_property = std::string("transition-").append(property_name);
|
||||
if (value.HasMember(transition_property.c_str())) {
|
||||
JSVal elements = value[transition_property.c_str()];
|
||||
if (elements.IsObject()) {
|
||||
if (elements.HasMember("duration") && elements["duration"].IsNumber()) {
|
||||
duration = elements["duration"].GetUint();
|
||||
}
|
||||
if (elements.HasMember("delay") && elements["delay"].IsNumber()) {
|
||||
delay = elements["delay"].GetUint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyTransition transition;
|
||||
|
||||
transition.duration = duration;
|
||||
transition.delay = delay;
|
||||
|
||||
return transition;
|
||||
}
|
||||
|
||||
FillClass StyleParser::parseFillClass(JSVal value) {
|
||||
FillClass klass;
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate")) {
|
||||
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
klass.translate_transition = parseTransition(value, "translate");
|
||||
klass.specifiers.insert("translate");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
klass.specifiers.insert("translate-anchor");
|
||||
}
|
||||
|
||||
if (value.HasMember("winding")) {
|
||||
throw std::runtime_error("winding in stylesheets not yet supported");
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.fill_color = parseColor(value["color"]);
|
||||
klass.fill_color_transition = parseTransition(value, "color");
|
||||
klass.specifiers.insert("color");
|
||||
}
|
||||
|
||||
if (value.HasMember("stroke")) {
|
||||
klass.stroke_color = parseColor(value["stroke"]);
|
||||
klass.stroke_color_transition = parseTransition(value, "stroke");
|
||||
klass.specifiers.insert("stroke");
|
||||
} else {
|
||||
klass.stroke_color = klass.fill_color;
|
||||
klass.specifiers.insert("stroke");
|
||||
}
|
||||
|
||||
if (value.HasMember("antialias")) {
|
||||
klass.antialias = parseBoolean(value["antialias"]);
|
||||
klass.specifiers.insert("antialias");
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
klass.specifiers.insert("image");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -523,32 +563,44 @@ LineClass StyleParser::parseLineClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate")) {
|
||||
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
klass.translate_transition = parseTransition(value, "translate");
|
||||
klass.specifiers.insert("translate");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
klass.specifiers.insert("translate-anchor");
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
klass.color_transition = parseTransition(value, "color");
|
||||
klass.specifiers.insert("color");
|
||||
}
|
||||
|
||||
if (value.HasMember("width")) {
|
||||
klass.width = parseFunction(value["width"]);
|
||||
klass.width_transition = parseTransition(value, "width");
|
||||
klass.specifiers.insert("width");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
if (value.HasMember("dasharray")) {
|
||||
std::vector<FunctionProperty> values = parseArray(value["dasharray"], 2);
|
||||
klass.dash_array = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
klass.dash_array_transition = parseTransition(value, "dasharray");
|
||||
klass.specifiers.insert("dasharray");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -559,39 +611,53 @@ IconClass StyleParser::parseIconClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate")) {
|
||||
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
klass.translate_transition = parseTransition(value, "translate");
|
||||
klass.specifiers.insert("translate");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
klass.specifiers.insert("translate-anchor");
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
klass.color_transition = parseTransition(value, "color");
|
||||
klass.specifiers.insert("color");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
if (value.HasMember("image")) {
|
||||
klass.image = parseString(value["image"]);
|
||||
klass.specifiers.insert("image");
|
||||
}
|
||||
|
||||
if (value.HasMember("size")) {
|
||||
klass.size = parseFunction(value["size"]);
|
||||
klass.specifiers.insert("size");
|
||||
}
|
||||
|
||||
if (value.HasMember("radius")) {
|
||||
klass.radius = parseFunction(value["radius"]);
|
||||
klass.radius_transition = parseTransition(value, "radius");
|
||||
klass.specifiers.insert("radius");
|
||||
}
|
||||
|
||||
if (value.HasMember("blur")) {
|
||||
klass.blur = parseFunction(value["blur"]);
|
||||
klass.blur_transition = parseTransition(value, "blur");
|
||||
klass.specifiers.insert("blur");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -602,43 +668,64 @@ TextClass StyleParser::parseTextClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate")) {
|
||||
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
klass.translate_transition = parseTransition(value, "translate");
|
||||
klass.specifiers.insert("translate");
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
klass.specifiers.insert("translate-anchor");
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
klass.color_transition = parseTransition(value, "color");
|
||||
klass.specifiers.insert("color");
|
||||
}
|
||||
|
||||
if (value.HasMember("stroke")) {
|
||||
klass.halo = parseColor(value["stroke"]);
|
||||
klass.halo_transition = parseTransition(value, "stroke");
|
||||
klass.specifiers.insert("stroke");
|
||||
}
|
||||
|
||||
if (value.HasMember("strokeWidth")) {
|
||||
klass.halo_radius = parseFunction(value["strokeWidth"]);
|
||||
klass.halo_radius_transition = parseTransition(value, "strokeWidth");
|
||||
klass.specifiers.insert("strokeWidth");
|
||||
}
|
||||
|
||||
if (value.HasMember("strokeBlur")) {
|
||||
klass.halo_blur = parseFunction(value["strokeBlur"]);
|
||||
klass.halo_blur_transition = parseTransition(value, "strokeBlur");
|
||||
klass.specifiers.insert("strokeBlur");
|
||||
}
|
||||
|
||||
if (value.HasMember("size")) {
|
||||
klass.size = parseFunction(value["size"]);
|
||||
klass.specifiers.insert("size");
|
||||
}
|
||||
|
||||
if (value.HasMember("rotate")) {
|
||||
klass.rotate = parseFunction(value["rotate"]);
|
||||
klass.specifiers.insert("rotate");
|
||||
}
|
||||
|
||||
if (value.HasMember("alwaysVisible")) {
|
||||
klass.alwaysVisible = parseFunction(value["alwaysVisible"]);
|
||||
klass.always_visible = parseFunction(value["alwaysVisible"]);
|
||||
klass.specifiers.insert("alwaysVisible");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -649,10 +736,13 @@ RasterClass StyleParser::parseRasterClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -663,10 +753,13 @@ CompositeClass StyleParser::parseCompositeClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("enabled")) {
|
||||
klass.enabled = parseFunction(value["enabled"]);
|
||||
klass.specifiers.insert("enabled");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
return klass;
|
||||
@@ -677,10 +770,14 @@ BackgroundClass StyleParser::parseBackgroundClass(JSVal value) {
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
klass.color_transition = parseTransition(value, "color");
|
||||
klass.specifiers.insert("color");
|
||||
}
|
||||
|
||||
if (value.HasMember("opacity")) {
|
||||
klass.opacity = parseFunction(value["opacity"]);
|
||||
klass.opacity_transition = parseTransition(value, "opacity");
|
||||
klass.specifiers.insert("opacity");
|
||||
}
|
||||
|
||||
return klass;
|
||||
|
||||
@@ -70,7 +70,7 @@ void Raster::bind(bool linear) {
|
||||
|
||||
void Raster::beginFadeInTransition() {
|
||||
time start = util::now();
|
||||
fade_transition = std::make_shared<util::ease_transition>(opacity, 1.0, opacity, start, 250_milliseconds);
|
||||
fade_transition = std::make_shared<util::ease_transition<double>>(opacity, 1.0, opacity, start, 250_milliseconds);
|
||||
}
|
||||
|
||||
bool Raster::needsTransition() const {
|
||||
|
||||
@@ -8,20 +8,69 @@ UnitBezier ease(0.25, 0.1, 0.25, 1);
|
||||
|
||||
transition::~transition() {}
|
||||
|
||||
ease_transition::ease_transition(double from, double to, double &value, time start, time duration)
|
||||
: transition(start, duration),
|
||||
from(from),
|
||||
to(to),
|
||||
value(value) {
|
||||
double transition::interpolateDouble(double from, double to, double t) const {
|
||||
return from + (to - from) * t;
|
||||
}
|
||||
|
||||
transition::state ease_transition::update(time now) const {
|
||||
float transition::interpolateFloat(float from, float to, double t) const {
|
||||
return from + (to - from) * (float)t;
|
||||
}
|
||||
|
||||
llmr::Color transition::interpolateColor(llmr::Color from, llmr::Color to, double t) const {
|
||||
return {{ interpolateFloat(from[0], to[0], t),
|
||||
interpolateFloat(from[1], to[1], t),
|
||||
interpolateFloat(from[2], to[2], t),
|
||||
interpolateFloat(from[3], to[3], t) }};
|
||||
}
|
||||
|
||||
std::array<float, 2> transition::interpolateFloatArray(std::array<float, 2> from, std::array<float, 2> to, double t) const {
|
||||
return {{ interpolateFloat(from[0], to[0], t), interpolateFloat(from[1], to[1], t) }};
|
||||
}
|
||||
|
||||
template <>
|
||||
transition::state ease_transition<double>::update(llmr::time now) const {
|
||||
float t = progress(now);
|
||||
if (t >= 1) {
|
||||
value = to;
|
||||
return complete;
|
||||
} else {
|
||||
value = from + (to - from) * ease.solve(t, 0.001);
|
||||
value = interpolateDouble(from, to, ease.solve(t, 0.001));
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
transition::state ease_transition<llmr::Color>::update(llmr::time now) const {
|
||||
float t = progress(now);
|
||||
if (t >= 1) {
|
||||
value = to;
|
||||
return complete;
|
||||
} else {
|
||||
value = interpolateColor(from, to, ease.solve(t, 0.001));
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
transition::state ease_transition<float>::update(llmr::time now) const {
|
||||
float t = progress(now);
|
||||
if (t >= 1) {
|
||||
value = to;
|
||||
return complete;
|
||||
} else {
|
||||
value = interpolateFloat(from, to, ease.solve(t, 0.001));
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
transition::state ease_transition<std::array<float, 2>>::update(llmr::time now) const {
|
||||
float t = progress(now);
|
||||
if (t >= 1) {
|
||||
value = to;
|
||||
return complete;
|
||||
} else {
|
||||
value = interpolateFloatArray(from, to, ease.solve(t, 0.001));
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user