diff --git a/README.md b/README.md index d2297e37..dc772438 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,10 @@ Once complete, you can view the component in your browser at [localhost:9966](http://localhost:9966). Any changes you make will automatically run the compiler to build the files again. +### Testing + +It's particularly difficult to write tests for this component beacuse it uses WebGL. There are some tests in `test/` but for the most part, as new features are added, we typically test drive them by running `npm run start` and play with the demos. + # CHANGE LOG ### 0.6 diff --git a/example/examples/style-diffing.react.js b/example/examples/style-diffing.react.js new file mode 100644 index 00000000..c6e9eb20 --- /dev/null +++ b/example/examples/style-diffing.react.js @@ -0,0 +1,126 @@ +// Copyright (c) 2015 Uber Technologies, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +'use strict'; + +var assign = require('object-assign'); +var React = require('react'); +var r = require('r-dom'); +var Immutable = require('immutable'); +var MapGL = require('../../src/index.js'); +var window = require('global/window'); + +// San Francisco +var location = require('./../data/cities.json')[0]; + +function buildStyle(opts) { + opts = assign({ + fill: 'red', + stroke: 'blue' + }, opts); + return Immutable.fromJS({ + version: 8, + name: 'Example raster tile source', + sources: { + 'my-geojson-polygon-source': { + type: 'geojson', + data: require('./../data/feature-example-sf.json') + } + }, + layers: [ + { + id: 'geojson-polygon-fill', + source: 'my-geojson-polygon-source', + type: 'fill', + paint: {'fill-color': opts.fill, 'fill-opacity': 0.4} + }, { + id: 'geojson-polygon-stroke', + source: 'my-geojson-polygon-source', + type: 'line', + paint: {'line-color': opts.stroke, 'line-width': 4} + } + ] + }); +} + +var StyleDiffingExample = React.createClass({ + + displayName: 'StyleDiffingExample', + + PropTypes: { + width: React.PropTypes.number.isRequired, + height: React.PropTypes.number.isRequired + }, + + getInitialState: function getInitialState() { + return { + viewport: { + latitude: location.latitude, + longitude: location.longitude, + zoom: 11, + startDragLngLat: null, + isDragging: false + }, + mapStyle: buildStyle({stroke: '#FF00FF', fill: 'green'}) + }; + }, + + componentDidMount: function componentDidMount() { + var i = 0; + var colors = ['red', 'green', 'blue']; + window.setInterval(function interval() { + this.setState({ + mapStyle: buildStyle({ + stroke: colors[i % colors.length], + fill: colors[(i + 1) % colors.length] + }) + }); + i = i + 1; + }.bind(this), 2000); + }, + + _onChangeViewport: function _onChangeViewport(opt) { + if (this.props.onChangeViewport) { + return this.props.onChangeViewport(opt); + } + this.setState({ + viewport: { + latitude: opt.latitude, + longitude: opt.longitude, + zoom: opt.zoom, + startDragLngLat: opt.startDragLngLat, + isDragging: opt.isDragging + } + }); + }, + + render: function render() { + var viewport = assign({ + mapStyle: this.state.mapStyle + }, this.state.viewport, this.props); + return r(MapGL, assign({}, viewport, { + onChangeViewport: this._onChangeViewport, + // setting to `true` should cause the map to flicker because all sources + // and layers need to be reloaded without diffing enabled. + preventStyleDiffing: false + })); + } +}); + +module.exports = StyleDiffingExample; diff --git a/example/main.js b/example/main.js index 89d0593b..62028df3 100644 --- a/example/main.js +++ b/example/main.js @@ -31,6 +31,8 @@ var CustomExample = require('./examples/custom.react'); var GeodataCreator = require('./examples/geodata-creator.react'); var ScatterplotExample = require('./examples/scatterplot.react'); var RouteExample = require('./examples/route.react'); +var StyleDiffingExample = require('./examples/style-diffing.react'); +var process = require('global/process'); function getAccessToken() { var match = window.location.search.match(/access_token=([^&\/]*)/); @@ -65,7 +67,8 @@ var App = React.createClass({ r(ChoroplethExample, common), r(CustomExample, common), r(GeodataCreator, common), - r(NotInteractiveExample, common) + r(NotInteractiveExample, common), + r(StyleDiffingExample, common) ]); } }); diff --git a/src/map.react.js b/src/map.react.js index 81f69869..b7b6617e 100644 --- a/src/map.react.js +++ b/src/map.react.js @@ -159,7 +159,13 @@ var MapGL = React.createClass({ * Passed to Mapbox Map constructor which passes it to the canvas context. * This is unseful when you want to export the canvas as a PNG. */ - preserveDrawingBuffer: React.PropTypes.bool + preserveDrawingBuffer: React.PropTypes.bool, + + /** + * There are still known issues with style diffing. As a temporary stopgap, + * add the option to prevent style diffing. + */ + preventStyleDiffing: React.PropTypes.bool }, getDefaultProps: function getDefaultProps() { @@ -439,7 +445,11 @@ var MapGL = React.createClass({ var mapStyle = this.state.mapStyle; if (mapStyle !== this.state.prevMapStyle) { if (mapStyle instanceof Immutable.Map) { - this._setDiffStyle(this.state.prevMapStyle, mapStyle); + if (this.props.preventStyleDiffing) { + this._getMap().setStyle(mapStyle.toJS()); + } else { + this._setDiffStyle(this.state.prevMapStyle, mapStyle); + } } else { this._getMap().setStyle(mapStyle); }