diff --git a/package.json b/package.json
index 3cee983..7383f7c 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,8 @@
"immutable": "^3.8.1",
"mapbox-gl": "^0.24.0",
"mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#83b1a3e5837d785af582efd5ed1a212f2df6a4ae",
+ "ol-mapbox-style": "0.0.11",
+ "openlayers": "^3.19.1",
"randomcolor": "^0.4.4",
"react": "^15.4.0",
"react-addons-pure-render-mixin": "^15.4.0",
diff --git a/src/app.jsx b/src/app.jsx
index fe63388..ed9c602 100644
--- a/src/app.jsx
+++ b/src/app.jsx
@@ -6,7 +6,8 @@ import Container from 'rebass/dist/Container'
import Block from 'rebass/dist/Block'
import Fixed from 'rebass/dist/Fixed'
-import { Map } from './map.jsx'
+import { MapboxGlMap } from './gl.jsx'
+import { OpenLayers3Map } from './ol3.jsx'
import {Toolbar} from './toolbar.jsx'
import style from './style.js'
import { loadDefaultStyle, SettingsStore, StyleStore } from './stylestore.js'
@@ -116,7 +117,7 @@ export default class App extends React.Component {
accessToken={this.state.accessToken}
onAccessTokenChanged={this.onAccessTokenChanged.bind(this)}
/>
-
diff --git a/src/gl.jsx b/src/gl.jsx
new file mode 100644
index 0000000..965d899
--- /dev/null
+++ b/src/gl.jsx
@@ -0,0 +1,53 @@
+import React from 'react'
+import MapboxGl from 'mapbox-gl';
+import { fullHeight } from './theme.js'
+import style from './style.js'
+import { Map } from './map.jsx'
+import Immutable from 'immutable'
+import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
+
+export class MapboxGlMap extends Map {
+ componentWillReceiveProps(nextProps) {
+ const tokenChanged = nextProps.accessToken !== MapboxGl.accessToken
+
+ // If the id has changed a new style has been uplaoded and
+ // it is safer to do a full new render
+ // TODO: might already be handled in diff algorithm?
+ const mapIdChanged = this.props.mapStyle.get('id') !== nextProps.mapStyle.get('id')
+
+ if(mapIdChanged || tokenChanged) {
+ this.state.map.setStyle(style.toJSON(nextProps.mapStyle))
+ return
+ }
+
+ // TODO: If there is no map yet we need to apply the changes later?
+ if(this.state.map) {
+ style.diffStyles(this.props.mapStyle, nextProps.mapStyle).forEach(change => {
+
+ //TODO: Invalid outline color can cause map to freeze?
+ if(change.command === "setPaintProperty" && change.args[1] === "fill-outline-color" ) {
+ const value = change.args[2]
+ if(validateColor({value}).length > 0) {
+ return
+ }
+ }
+
+ console.log(change.command, ...change.args)
+ this.state.map[change.command].apply(this.state.map, change.args);
+ });
+ }
+ }
+
+ componentDidMount() {
+ MapboxGl.accessToken = this.props.accessToken
+
+ const map = new MapboxGl.Map({
+ container: this.container,
+ style: style.toJSON(this.props.mapStyle),
+ });
+
+ map.on("style.load", (...args) => {
+ this.setState({ map });
+ });
+ }
+}
diff --git a/src/map.jsx b/src/map.jsx
index e6634c0..5ab54e3 100644
--- a/src/map.jsx
+++ b/src/map.jsx
@@ -1,72 +1,24 @@
import React from 'react'
-import MapboxGl from 'mapbox-gl';
import { fullHeight } from './theme.js'
-import style from './style.js'
import Immutable from 'immutable'
-import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
export class Map extends React.Component {
- static propTypes = {
- mapStyle: React.PropTypes.instanceOf(Immutable.Map).isRequired,
- accessToken: React.PropTypes.string,
- }
+ static propTypes = {
+ mapStyle: React.PropTypes.instanceOf(Immutable.Map).isRequired,
+ accessToken: React.PropTypes.string,
+ }
- componentWillReceiveProps(nextProps) {
- const hasTokenChanged = nextProps.accessToken !== MapboxGl.accessToken
- MapboxGl.accessToken = nextProps.accessToken
+ shouldComponentUpdate(nextProps, nextState) {
+ //TODO: If we enable this React mixin for immutable comparison we can remove this?
+ return nextProps.mapStyle !== this.props.mapStyle
+ }
- // If the id has changed a new style has been uplaoded and
- // it is safer to do a full new render
- // TODO: might already be handled in diff algorithm?
- const mapIdChanged = this.props.mapStyle.get('id') !== nextProps.mapStyle.get('id')
-
- if(mapIdChanged || hasTokenChanged) {
- this.state.map.setStyle(style.toJSON(nextProps.mapStyle))
- return
- }
-
- // TODO: If there is no map yet we need to apply the changes later?
- if(this.state.map) {
- style.diffStyles(this.props.mapStyle, nextProps.mapStyle).forEach(change => {
-
- //TODO: Invalid outline color can cause map to freeze?
- if(change.command === "setPaintProperty" && change.args[1] === "fill-outline-color" ) {
- const value = change.args[2]
- if(validateColor({value}).length > 0) {
- return
- }
- }
-
- console.log(change.command, ...change.args)
- this.state.map[change.command].apply(this.state.map, change.args);
- });
- }
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- //TODO: If we enable this React mixin for immutable comparison we can remove this?
- return nextProps.mapStyle !== this.props.mapStyle
- }
-
- componentDidMount() {
- MapboxGl.accessToken = this.props.accessToken
-
- const map = new MapboxGl.Map({
- container: this.container,
- style: style.toJSON(this.props.mapStyle),
- });
-
- map.on("style.load", (...args) => {
- this.setState({ map });
- });
- }
-
- render() {
- return
this.container = x}
- style={{
- ...fullHeight,
- width: "100%",
- }}>
- }
+ render() {
+ return this.container = x}
+ style={{
+ ...fullHeight,
+ width: "100%",
+ }}>
+ }
}
diff --git a/src/ol3.jsx b/src/ol3.jsx
new file mode 100644
index 0000000..903c1c4
--- /dev/null
+++ b/src/ol3.jsx
@@ -0,0 +1,48 @@
+import React from 'react'
+import style from './style.js'
+import { Map } from './map.jsx'
+import ol from 'openlayers'
+import olms from 'ol-mapbox-style'
+
+export class OpenLayers3Map extends Map {
+ constructor(props) {
+ super(props)
+
+ const tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22})
+ this.resolutions = tilegrid.getResolutions()
+ this.layer = new ol.layer.VectorTile({
+ source: new ol.source.VectorTile({
+ attributions: '© Mapbox ' +
+ '© ' +
+ 'OpenStreetMap contributors',
+ format: new ol.format.MVT(),
+ tileGrid: tilegrid,
+ tilePixelRatio: 8,
+ url: 'http://osm2vectortiles-0.tileserver.com/v2/{z}/{x}/{y}.pbf'
+ })
+ })
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const jsonStyle = style.toJSON(nextProps.mapStyle)
+ const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
+ this.layer.setStyle(styleFunc)
+ this.state.map.render()
+ }
+
+
+ componentDidMount() {
+ const styleFunc = olms.getStyleFunction(style.toJSON(this.props.mapStyle), 'mapbox', this.resolutions)
+ this.layer.setStyle(styleFunc)
+
+ const map = new ol.Map({
+ target: this.container,
+ layers: [this.layer],
+ view: new ol.View({
+ center: [949282, 6002552],
+ zoom: 4
+ })
+ })
+ this.setState({ map });
+ }
+}
diff --git a/webpack.production.config.js b/webpack.production.config.js
index 8a9ef94..fbbfc71 100644
--- a/webpack.production.config.js
+++ b/webpack.production.config.js
@@ -8,88 +8,91 @@ var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
// local css modules
loaders.push({
- test: /[\/\\]src[\/\\].*\.css/,
- loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
+ test: /[\/\\]src[\/\\].*\.css/,
+ loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
});
// local scss modules
loaders.push({
- test: /[\/\\]src[\/\\].*\.scss/,
- loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'sass')
+ test: /[\/\\]src[\/\\].*\.scss/,
+ loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'sass')
});
// global css files
loaders.push({
- test: /[\/\\](node_modules|global)[\/\\].*\.css$/,
- loader: ExtractTextPlugin.extract('style', 'css')
+ test: /[\/\\](node_modules|global)[\/\\].*\.css$/,
+ loader: ExtractTextPlugin.extract('style', 'css')
});
module.exports = {
- entry: {
- app: './src/index.jsx',
- vendor: [
- 'file-saver',
- 'immutable',
- 'mapbox-gl',
- //TODO: Cannot resolve migrations file?
- //"mapbox-gl-style-spec",
- "randomcolor",
- 'react',
- "react-collapse",
- "react-dom",
- "react-file-reader-input",
- "react-height",
- //TODO: Icons raise multi vendor errors?
- //"react-icons",
- "react-motion",
- "rebass",
- ]
- },
- output: {
- path: path.join(__dirname, 'public'),
- filename: '[chunkhash].app.js'
- },
- resolve: {
- alias: {
- 'webworkify': 'webworkify-webpack',
- },
- extensions: ['', '.js', '.jsx']
- },
- module: {
- loaders,
- postLoaders: [{
- include: /node_modules\/mapbox-gl-shaders/,
- loader: 'transform',
- query: 'brfs'
- }]
- },
- node: {
- fs: "empty"
- },
- plugins: [
- new webpack.NoErrorsPlugin(),
- new webpack.optimize.CommonsChunkPlugin('vendor', '[chunkhash].vendor.js'),
- new WebpackCleanupPlugin(),
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: '"production"'
- }
- }),
- new webpack.optimize.UglifyJsPlugin({
- compress: {
- warnings: false,
- screw_ie8: true,
- drop_console: true,
- drop_debugger: true
- }
- }),
- new webpack.optimize.OccurenceOrderPlugin(),
- new ExtractTextPlugin('[contenthash].css', {
- allChunks: true
- }),
- new HtmlWebpackPlugin({
- template: './src/template.html',
- title: 'Maputnik'
- }),
- new webpack.optimize.DedupePlugin()
- ]
+ entry: {
+ app: './src/index.jsx',
+ vendor: [
+ 'file-saver',
+ 'immutable',
+ 'mapbox-gl',
+ //TODO: Cannot resolve migrations file?
+ //"mapbox-gl-style-spec",
+ "randomcolor",
+ 'react',
+ "react-collapse",
+ "react-dom",
+ "react-file-reader-input",
+ "react-height",
+ //TODO: Icons raise multi vendor errors?
+ //"react-icons",
+ "react-motion",
+ "rebass",
+ // Open Layers
+ 'openlayers',
+ 'ol-mapbox-style'
+ ]
+ },
+ output: {
+ path: path.join(__dirname, 'public'),
+ filename: '[chunkhash].app.js'
+ },
+ resolve: {
+ alias: {
+ 'webworkify': 'webworkify-webpack',
+ },
+ extensions: ['', '.js', '.jsx']
+ },
+ module: {
+ loaders,
+ postLoaders: [{
+ include: /node_modules\/mapbox-gl-shaders/,
+ loader: 'transform',
+ query: 'brfs'
+ }]
+ },
+ node: {
+ fs: "empty"
+ },
+ plugins: [
+ new webpack.NoErrorsPlugin(),
+ new webpack.optimize.CommonsChunkPlugin('vendor', '[chunkhash].vendor.js'),
+ new WebpackCleanupPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: '"production"'
+ }
+ }),
+ new webpack.optimize.UglifyJsPlugin({
+ compress: {
+ warnings: false,
+ screw_ie8: true,
+ drop_console: true,
+ drop_debugger: true
+ }
+ }),
+ new webpack.optimize.OccurenceOrderPlugin(),
+ new ExtractTextPlugin('[contenthash].css', {
+ allChunks: true
+ }),
+ new HtmlWebpackPlugin({
+ template: './src/template.html',
+ title: 'Maputnik'
+ }),
+ new webpack.optimize.DedupePlugin()
+ ]
};