From a186e6a27d79ca3ed1eb6fadce656df5e0e2b89f Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 28 Aug 2019 13:34:11 +0300 Subject: [node] Add support for feature state APIs --- platform/node/src/node_feature.cpp | 6 + platform/node/src/node_map.cpp | 221 +++++++++++++++++++++++++++++++++++++ platform/node/src/node_map.hpp | 4 + 3 files changed, 231 insertions(+) diff --git a/platform/node/src/node_feature.cpp b/platform/node/src/node_feature.cpp index 2dfab686a7..646cc23338 100644 --- a/platform/node/src/node_feature.cpp +++ b/platform/node/src/node_feature.cpp @@ -167,6 +167,12 @@ v8::Local toJS(const Feature& feature) { Nan::Set(result, Nan::New("id").ToLocalChecked(), FeatureIdentifier::visit(feature.id, ToValue())); } + Nan::Set(result, Nan::New("source").ToLocalChecked(), toJS(feature.source)); + if (!feature.sourceLayer.empty()) { + Nan::Set(result, Nan::New("sourceLayer").ToLocalChecked(), toJS(feature.sourceLayer)); + } + Nan::Set(result, Nan::New("state").ToLocalChecked(), toJS(feature.state)); + return scope.Escape(result); } diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 641816dc00..d9bee1c840 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -117,6 +117,9 @@ ParseError)JS").ToLocalChecked()).ToLocalChecked(); Nan::SetPrototypeMethod(tpl, "setAxonometric", SetAxonometric); Nan::SetPrototypeMethod(tpl, "setXSkew", SetXSkew); Nan::SetPrototypeMethod(tpl, "setYSkew", SetYSkew); + Nan::SetPrototypeMethod(tpl, "setFeatureState", SetFeatureState); + Nan::SetPrototypeMethod(tpl, "getFeatureState", GetFeatureState); + Nan::SetPrototypeMethod(tpl, "removeFeatureState", RemoveFeatureState); Nan::SetPrototypeMethod(tpl, "dumpDebugLogs", DumpDebugLogs); Nan::SetPrototypeMethod(tpl, "queryRenderedFeatures", QueryRenderedFeatures); @@ -1099,6 +1102,224 @@ void NodeMap::SetYSkew(const Nan::FunctionCallbackInfo& info) { info.GetReturnValue().SetUndefined(); } +void NodeMap::SetFeatureState(const Nan::FunctionCallbackInfo& info) { + using namespace mbgl; + using namespace mbgl::style::conversion; + + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() < 2) { + return Nan::ThrowTypeError("Two arguments required"); + } + + if (!info[0]->IsObject() || !info[1]->IsObject()) { + return Nan::ThrowTypeError("Both arguments must be objects"); + } + + std::string sourceID, featureID; + mbgl::optional sourceLayerID; + auto feature = Nan::To(info[0]).ToLocalChecked(); + if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) { + auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked(); + if (!sourceOption->IsString()) { + return Nan::ThrowTypeError("Requires feature.source property to be a string"); + } + sourceID = *Nan::Utf8String(sourceOption); + } else { + return Nan::ThrowTypeError("SetFeatureState: Requires feature.source property"); + } + + if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) { + auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked(); + if (!sourceLayerOption->IsString()) { + return Nan::ThrowTypeError("SetFeatureState: Requires feature.sourceLayer property to be a string"); + } + sourceLayerID = { *Nan::Utf8String(sourceLayerOption) }; + } + + if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) { + auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked(); + if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) { + return Nan::ThrowTypeError("Requires feature.id property to be a string or a number"); + } + featureID = *Nan::Utf8String(idOption); + } else { + return Nan::ThrowTypeError("SetFeatureState: Requires feature.id property"); + } + + Convertible state(info[1]); + + if (!isObject(state)) { + return Nan::ThrowTypeError("Feature state must be an object"); + } + + std::string sourceLayer = sourceLayerID.value_or(std::string()); + std::string stateKey; + Value stateValue; + bool valueParsed = false; + FeatureState newState; + + const std::function (const std::string&, const Convertible&)> convertFn = [&] (const std::string& k, const Convertible& v) -> optional { + optional value = toValue(v); + if (value) { + stateValue = std::move(*value); + valueParsed = true; + } else if (isArray(v)) { + std::vector array; + std::size_t length = arrayLength(v); + array.reserve(length); + for (size_t i = 0; i < length; ++i) { + optional arrayVal = toValue(arrayMember(v, i)); + if (arrayVal) { + array.emplace_back(*arrayVal); + } + } + std::unordered_map result; + result[k]= std::move(array); + stateValue = std::move(result); + valueParsed = true; + return {}; + + } else if (isObject(v)) { + eachMember(v, convertFn); + + } + if (!valueParsed) { + Nan::ThrowTypeError("Could not get feature state value"); + return nullopt; + } + stateKey = k; + newState[stateKey] = stateValue; + return nullopt; + }; + + eachMember(state, convertFn); + + try { + nodeMap->frontend->getRenderer()->setFeatureState(sourceID, sourceLayerID, featureID, newState); + } catch (const std::exception &ex) { + return Nan::ThrowError(ex.what()); + } + + info.GetReturnValue().SetUndefined(); +} + +void NodeMap::GetFeatureState(const Nan::FunctionCallbackInfo& info) { + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() < 1) { + return Nan::ThrowTypeError("One argument required"); + } + + if (!info[0]->IsObject() || !info[1]->IsObject()) { + return Nan::ThrowTypeError("Argument must be object"); + } + + std::string sourceID, featureID; + mbgl::optional sourceLayerID; + auto feature = Nan::To(info[0]).ToLocalChecked(); + if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) { + auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked(); + if (!sourceOption->IsString()) { + return Nan::ThrowTypeError("Requires feature.source property to be a string"); + } + sourceID = *Nan::Utf8String(sourceOption); + } else { + return Nan::ThrowTypeError("GetFeatureState: Requires feature.source property"); + } + + if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) { + auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked(); + if (!sourceLayerOption->IsString()) { + return Nan::ThrowTypeError("GetFeatureState: Requires feature.sourceLayer property to be a string"); + } + sourceLayerID = { *Nan::Utf8String(sourceLayerOption) }; + } + + if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) { + auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked(); + if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) { + return Nan::ThrowTypeError("Requires feature.id property to be a string or a number"); + } + featureID = *Nan::Utf8String(idOption); + } else { + return Nan::ThrowTypeError("GetFeatureState: Requires feature.id property"); + } + + mbgl::FeatureState state; + try { + nodeMap->frontend->getRenderer()->getFeatureState(state, sourceID, sourceLayerID, featureID); + } catch (const std::exception &ex) { + return Nan::ThrowError(ex.what()); + } + + info.GetReturnValue().SetUndefined(); +} + +void NodeMap::RemoveFeatureState(const Nan::FunctionCallbackInfo& info) { + auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() < 1) { + return Nan::ThrowTypeError("At least one argument required"); + } + + if (!info[0]->IsObject()) { + return Nan::ThrowTypeError("Argument 1 must be object"); + } + + if (info.Length() == 2 && !info[1]->IsString()) { + return Nan::ThrowTypeError("argument 2 must be string"); + } + + std::string sourceID; + mbgl::optional sourceLayerID, featureID, stateKey; + auto feature = Nan::To(info[0]).ToLocalChecked(); + if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) { + auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked(); + if (!sourceOption->IsString()) { + return Nan::ThrowTypeError("Requires feature.source property to be a string"); + } + sourceID = *Nan::Utf8String(sourceOption); + } else { + return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.source property"); + } + + if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) { + auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked(); + if (!sourceLayerOption->IsString()) { + return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.sourceLayer property to be a string"); + } + sourceLayerID = { *Nan::Utf8String(sourceLayerOption) }; + } + + if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) { + auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked(); + if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) { + return Nan::ThrowTypeError("Requires feature.id property to be a string or a number"); + } + featureID = { *Nan::Utf8String(idOption) }; + } + + if (info.Length() == 2) { + auto keyParam = Nan::To(info[1]).ToLocalChecked(); + if (!keyParam->IsString()) { + return Nan::ThrowTypeError("RemoveFeatureState: Requires feature key property to be a string"); + } + stateKey = { *Nan::Utf8String(keyParam) }; + } + + try { + nodeMap->frontend->getRenderer()->removeFeatureState(sourceID, sourceLayerID, featureID, stateKey); + } catch (const std::exception &ex) { + return Nan::ThrowError(ex.what()); + } + + info.GetReturnValue().SetUndefined(); +} + void NodeMap::DumpDebugLogs(const Nan::FunctionCallbackInfo& info) { auto nodeMap = Nan::ObjectWrap::Unwrap(info.Holder()); if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 486754c1c3..381e10381b 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -64,6 +64,10 @@ public: static void DumpDebugLogs(const Nan::FunctionCallbackInfo&); static void QueryRenderedFeatures(const Nan::FunctionCallbackInfo&); + static void SetFeatureState(const Nan::FunctionCallbackInfo&); + static void GetFeatureState(const Nan::FunctionCallbackInfo&); + static void RemoveFeatureState(const Nan::FunctionCallbackInfo&); + static v8::Local ParseError(const char* msg); void startRender(RenderOptions options); -- cgit v1.2.1