diff --git a/demos/06_text.html b/demos/06_text.html
index 52c44ea774..79f636e663 100644
--- a/demos/06_text.html
+++ b/demos/06_text.html
@@ -25,22 +25,24 @@ const scene = new L7.Scene({
mapStyle: 'dark', // 样式URL
center: [ 120.19382669582967, 30.258134 ],
pitch: 0,
- zoom: 3
+ zoom: 1
});
window.scene = scene;
scene.on('loaded', () => {
$.get('./data/provincePoint.geojson', data => {
+ // data.features = data.features.slice(0,1);
scene.PointLayer({
zIndex: 2
})
.source(data)
.shape('name', 'text')
+ .active(true)
.size(12) // default 1
- .color('#fff')
+ .color('name')
.style({
stroke: '#999',
- strokeWidth: 2,
- opacity: 0.85
+ strokeWidth: 0,
+ opacity: 1.0
})
.render();
});
diff --git a/package.json b/package.json
index 94993685ce..7dc407177f 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/l7",
- "version": "1.1.6",
+ "version": "1.1.7",
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
"main": "build/l7.js",
"browser": "build/l7.js",
diff --git a/src/core/controller/layer.js b/src/core/controller/layer.js
deleted file mode 100644
index 9002769ca4..0000000000
--- a/src/core/controller/layer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-
-export class layerControl {
-}
diff --git a/src/core/controller/map.js b/src/core/controller/map.js
deleted file mode 100644
index 3068e61cfe..0000000000
--- a/src/core/controller/map.js
+++ /dev/null
@@ -1,24 +0,0 @@
-
-import { getMap } from '../../map';
-import Base from '../base';
-export default class MapContorller extends Base {
- constructor(cfg, engine, scene) {
- super(cfg);
- this._engine = engine;
- this.scene = scene;
- }
- _init() {
- const mapType = this.get('mapType');
- const mapCfg = this.get('mapCfg');
- this.map = new getMap(mapType)(mapCfg);
- this.map('mapLoad', this._mapload.bind(this));
- }
- _mapload() {
- this.map.asyncCamera(this._engine);
- this.emit('loaded');
- }
- _bindMapMethod() {
-
- }
-
-}
diff --git a/src/core/engine/index.js b/src/core/engine/index.js
index a08bc77d76..9f04690f43 100644
--- a/src/core/engine/index.js
+++ b/src/core/engine/index.js
@@ -31,7 +31,6 @@ export default class Engine extends EventEmitter {
}
run() {
-
this.update();
this.engineID = requestAnimationFrame(this.run.bind(this));
}
diff --git a/src/core/layer.js b/src/core/layer.js
index 4852e0afb7..1403fee10e 100644
--- a/src/core/layer.js
+++ b/src/core/layer.js
@@ -112,6 +112,8 @@ export default class Layer extends Base {
if (type === 'fill') {
this._addPickMesh(object);// 不对边界线进行拾取
}
+ this.scene._engine.update();
+ setTimeout(() => this.scene._engine.update(), 500);
}
remove(object) {
if (object.type === 'composer') {
diff --git a/src/core/scene.js b/src/core/scene.js
index 0ab5e653f5..5d22c4e67d 100644
--- a/src/core/scene.js
+++ b/src/core/scene.js
@@ -2,6 +2,7 @@ import Engine from './engine';
import { LAYER_MAP } from '../layer';
import Base from './base';
import LoadImage from './image';
+import FontAtlasManager from '../geom/buffer/point/text/font-manager';
// import WorkerPool from './worker';
// import { MapProvider } from '../map/AMap';
import { getMap } from '../map/index';
@@ -16,12 +17,14 @@ export default class Scene extends Base {
this._initMap();
// this._initAttribution(); // 暂时取消,后面作为组件去加载
this.addImage();
+ this.fontAtlasManager = new FontAtlasManager();
this._layers = [];
+ this.animateCount = 0;
}
_initEngine(mapContainer) {
this._engine = new Engine(mapContainer, this);
- this._engine.run();
+ this.registerMapEvent();
// this.workerPool = new WorkerPool();
compileBuiltinModules();
}
@@ -38,8 +41,8 @@ export default class Scene extends Base {
this._container = document.getElementById(Map.container);
// const Map = new MapProvider(this.mapContainer, this._attrs);
Map.on('mapLoad', () => {
- this._initEngine(Map.renderDom);
this.map = Map.map;
+ this._initEngine(Map.renderDom);
Map.asyncCamera(this._engine);
this.initLayer();
this._registEvents();
@@ -115,5 +118,31 @@ export default class Scene extends Base {
layer.destroy();
layer = null;
}
+ startAnimate() {
+ if (this.animateCount === 0) {
+ this.unRegsterMapEvent();
+ this._engine.run();
+ }
+ this.animateCount++;
+ }
+ stopAnimate() {
+ if (this.animateCount === 1) {
+ this._engine.stop();
+ this.registerMapEvent();
+ }
+ this.animateCount++;
+ }
+ // 地图状态变化时更新可视化渲染
+ registerMapEvent() {
+ this._updateRender = () => this._engine.update();
+ this.map.on('mousemove', this._updateRender);
+ this.map.on('mapmove', this._updateRender);
+ this.map.on('camerachange', this._updateRender);
+ }
+ unRegsterMapEvent() {
+ this.map.off('mousemove', this._updateRender);
+ this.map.off('mapmove', this._updateRender);
+ this.map.off('camerachange', this._updateRender);
+ }
}
diff --git a/src/core/three.js b/src/core/three.js
index 63c37b9ac8..f832dfbf66 100644
--- a/src/core/three.js
+++ b/src/core/three.js
@@ -14,7 +14,9 @@ export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
export { OrthographicCamera } from 'three/src/cameras/OrthographicCamera.js';
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
+export { InstancedBufferGeometry } from 'three/src/core/InstancedBufferGeometry';
export { PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
+export { BoxBufferGeometry } from 'three/src/geometries/BoxGeometry.js';
export { Raycaster } from 'three/src/core/Raycaster.js';
export { UniformsUtils } from 'three/src/renderers/shaders/UniformsUtils.js';
export { Matrix4 } from 'three/src/math/Matrix4.js';
@@ -39,4 +41,5 @@ export {
BufferAttribute
} from 'three/src/core/BufferAttribute.js';
+export { InstancedBufferAttribute } from 'three/src/core/InstancedBufferAttribute'
// export * from '../../build/three.js';
diff --git a/src/geom/buffer/point/sdfCommonWords.js b/src/geom/buffer/point/sdfCommonWords.js
deleted file mode 100644
index 3567025d13..0000000000
--- a/src/geom/buffer/point/sdfCommonWords.js
+++ /dev/null
@@ -1,246 +0,0 @@
-// const SDFCommonWordsKey = '_AMap_sdf_com_words';
-
-// /**
-// * SDF 常用字获取/存储/check
-// *
-// */
-// const SDFCommonWords = {
-
-// store() {
-
-// },
-
-// /**
-// * 检查一个字符是否在常用字中
-// * @param {*} charcode 汉字
-// */
-// check(charcode) {
-// const range = this.range || [];
-// const info = this.info || {};
-
-// if (typeof charcode !== 'number') {
-
-// charcode = charcode.substr(0).charCodeAt(0);
-// }
-
-// for (let i = 0; i < range.length; i++) {
-// const curRange = range[i];
-// const [ rangeStart, rangeEnd ] = curRange.split('-');
-
-// if (charcode >= rangeStart && charcode <= rangeEnd) {
-
-// const curInfo = info[curRange] && info[curRange].info || {};
-
-// if (curInfo[charcode]) {
-
-// return true;
-// }
-// }
-// }
-
-// return false;
-// },
-
-// /**
-// * 获取纹理和位置信息
-// * @param list
-// * @param cb
-// */
-// getImagesAndInfo(list, cb) {
-// const range = this.range;
-
-
-// },
-
-// loadCanvas(url, range, done) {
-
-// try {
-// const xhr = new XMLHttpRequest();
-// xhr.open('GET', url);
-
-// // 直接用 blob 格式 load 图片文件,方便直接转换成 base64
-// // 转成 base64 便于存储
-// // 使用 canvas 转换 base64 容易有损
-// xhr.responseType = 'blob';
-// xhr.onerror = function() {
-// done({ code: 0 });
-// };
-
-// xhr.onload = function() {
-
-// if (xhr.status === 200) {
-// const reader = new FileReader();
-
-// reader.onload = () => {
-
-// done(reader.result, range);
-// };
-
-// reader.readAsDataURL(xhr.response);
-// } else {
-// done({ code: 0 });
-// }
-// };
-
-// xhr.send();
-// } catch (err) {
-
-// done({ code: 0 });
-// }
-// },
-
-// loadImages(urls = []) {
-// const deferred = $.Deferred();
-// const totalNumbers = urls.length;
-// const localInfo = this.info;
-// let loadPicNum = 0;
-
-// for (let i = 0; i < urls.length; i++) {
-// const { url, range } = urls[i];
-
-// this.loadCanvas(url, range, (base64, range) => {
-
-// // image to base64
-// loadPicNum++;
-
-// !localInfo[range] && (localInfo[range] = {});
-
-// localInfo[range].pic = base64;
-
-// this.info = localInfo;
-
-// // todo: temp 暂时用 localstorage 存储,因为数据比较大,最好使用 indexDB
-// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
-
-// if (loadPicNum === totalNumbers) {
-
-// deferred.resolve();
-// }
-// });
-// }
-
-// return deferred;
-// },
-
-// loadInfo(urls) {
-// const deferred = $.Deferred();
-// const totalNumbers = urls.length;
-// const localInfo = this.info;
-// let loadInfoNum = 0;
-
-// for (let i = 0; i < urls.length; i++) {
-// const { url, range } = urls[i];
-
-// $.ajax({
-// url,
-// dataType: 'json',
-// success: data => {
-// loadInfoNum++;
-
-// !localInfo[range] && (localInfo[range] = {});
-
-// localInfo[range].info = data;
-
-// this.info = localInfo;
-
-// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
-
-// if (loadInfoNum === totalNumbers) {
-
-// deferred.resolve();
-// }
-// },
-// error: () => {
-
-// }
-// });
-// }
-
-// return deferred;
-
-// },
-
-// getTotalAssets(info, cb) {
-// const { range = [], urlPrefix } = info;
-// const picUrls = [];
-// const infoUrls = [];
-
-// this.range = range;
-
-// for (let i = 0; i < range.length; i++) {
-// const curRange = range[i];
-// const baseUrl = urlPrefix + curRange;
-// const picUrl = baseUrl + '.png';
-// const infoUrl = baseUrl + '.json';
-
-// picUrls.push({ range: curRange, url: picUrl });
-// infoUrls.push({ range: curRange, url: infoUrl });
-// }
-
-// const imageDeferred = this.loadImages(picUrls);
-// const infoDeferred = this.loadInfo(infoUrls);
-
-// $.when(imageDeferred, infoDeferred)
-// .then(() => {
-
-// // all info load complete
-// // console.log("all info load complete", " -- ", 1);
-// cb && cb(this.info);
-// }, () => {
-
-// // fail
-// });
-// },
-// // 获取数据
-// getData(cb) {
-
-// if (!_.isEmpty(this.info)) {
-
-// cb && cb(this.info);
-// } else {
-
-// this.getRemoteData(cb);
-// }
-// },
-
-// /**
-// * 从服务获取数据,什么时候强制去取一回数据?过期?
-// * @param cb
-// */
-// getRemoteData(cb) {
-// const self = this;
-
-// $.ajax({
-// url: '/getcommonwords',
-// dataType: 'json',
-// success: data => {
-
-// if (data.code == 1) {
-
-// const info = data.data;
-
-// self.getTotalAssets(info, cb);
-// }
-// }
-// });
-// },
-
-// destroy() {
-
-// },
-
-// init() {
-// let info = localStorage.getItem(SDFCommonWordsKey);
-// this.range = [];
-// this.info = {};
-
-// if (info) {
-// info = JSON.parse(info);
-// this.range = Object.keys(info);
-// this.info = info;
-// }
-
-// this.info = info || {};
-// }
-// };
-// export default SDFCommonWords;
diff --git a/src/geom/buffer/point/text.js b/src/geom/buffer/point/text.js
new file mode 100644
index 0000000000..2552bdf894
--- /dev/null
+++ b/src/geom/buffer/point/text.js
@@ -0,0 +1,131 @@
+export default function TextBuffer(layerData, fontAtlasManager) {
+ const characterSet = [];
+ layerData.forEach(element => {
+ let text = element.shape || '';
+ text = text.toString();
+ for (let j = 0; j < text.length; j++) {
+ if (characterSet.indexOf(text[j]) === -1) {
+ characterSet.push(text[j]);
+ }
+ }
+ });
+ fontAtlasManager.setProps({
+ characterSet
+ });
+ const attr = drawGlyph(layerData, fontAtlasManager);
+ return attr;
+}
+function drawGlyph(layerData, fontAtlasManager) {
+ const attributes = {
+ originPoints: [],
+ textSizes: [],
+ textOffsets: [],
+ colors: [],
+ textureElements: [],
+ pickingIds: []
+ };
+ const { texture, fontAtlas, mapping, scale } = fontAtlasManager;
+ layerData.forEach(function(element) {
+ const size = element.size;
+ const pos = element.coordinates;
+ let text = element.shape || '';
+ const pen = {
+ x: (-text.length * size) / 2,
+ y: 0
+ };
+ text = text.toString();
+
+ for (let i = 0; i < text.length; i++) {
+ const metric = mapping[text[i]];
+ const { x, y, width, height } = metric;
+ const color = element.color;
+ const offsetX = pen.x;
+ const offsetY = pen.y;
+ attributes.pickingIds.push(
+ element.id,
+ element.id,
+ element.id,
+ element.id,
+ element.id,
+ element.id
+ );
+ attributes.textOffsets.push(
+ // 文字在词语的偏移量
+ offsetX,
+ offsetY,
+ offsetX,
+ offsetY,
+ offsetX,
+ offsetY,
+ offsetX,
+ offsetY,
+ offsetX,
+ offsetY,
+ offsetX,
+ offsetY
+ );
+ attributes.originPoints.push(
+ // 词语的经纬度坐标
+ pos[0],
+ pos[1],
+ 0,
+ pos[0],
+ pos[1],
+ 0,
+ pos[0],
+ pos[1],
+ 0,
+ pos[0],
+ pos[1],
+ 0,
+ pos[0],
+ pos[1],
+ 0,
+ pos[0],
+ pos[1],
+ 0
+ );
+ attributes.textSizes.push(
+ size,
+ size * scale,
+ 0,
+ size * scale,
+ 0,
+ 0,
+ size,
+ size * scale,
+ 0,
+ 0,
+ size,
+ 0
+ );
+ attributes.colors.push(
+ ...color,
+ ...color,
+ ...color,
+ ...color,
+ ...color,
+ ...color
+ );
+ attributes.textureElements.push(
+ // 文字纹理坐标
+ x + width,
+ y,
+ x,
+ y,
+ x,
+ y + height,
+ x + width,
+ y,
+ x,
+ y + height,
+ x + width,
+ y + height
+ );
+ pen.x = pen.x + size;
+ }
+ });
+ attributes.texture = texture;
+ attributes.fontAtlas = fontAtlas;
+ return attributes;
+}
diff --git a/src/geom/buffer/point/text/font-manager.js b/src/geom/buffer/point/text/font-manager.js
new file mode 100644
index 0000000000..0fdb8bb53f
--- /dev/null
+++ b/src/geom/buffer/point/text/font-manager.js
@@ -0,0 +1,227 @@
+import TinySDF from '@mapbox/tiny-sdf';
+import { buildMapping } from '../../../../util/font-util';
+import * as THREE from '../../../../core/three';
+import LRUCache from './lru-cache';
+export const DEFAULT_CHAR_SET = getDefaultCharacterSet();
+export const DEFAULT_FONT_FAMILY = 'sans-serif';
+export const DEFAULT_FONT_WEIGHT = 'normal';
+export const DEFAULT_FONT_SIZE = 24;
+export const DEFAULT_BUFFER = 3;
+export const DEFAULT_CUTOFF = 0.25;
+export const DEFAULT_RADIUS = 8;
+const MAX_CANVAS_WIDTH = 1024;
+const BASELINE_SCALE = 0.9;
+const HEIGHT_SCALE = 1.2;
+const CACHE_LIMIT = 3;
+const cache = new LRUCache(CACHE_LIMIT);
+
+const VALID_PROPS = [
+ 'fontFamily',
+ 'fontWeight',
+ 'characterSet',
+ 'fontSize',
+ 'sdf',
+ 'buffer',
+ 'cutoff',
+ 'radius'
+];
+
+function getDefaultCharacterSet() {
+ const charSet = [];
+ for (let i = 32; i < 128; i++) {
+ charSet.push(String.fromCharCode(i));
+ }
+ return charSet;
+}
+
+function setTextStyle(ctx, fontFamily, fontSize, fontWeight) {
+ ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = '#000';
+ ctx.textBaseline = 'baseline';
+ ctx.textAlign = 'left';
+}
+function getNewChars(key, characterSet) {
+ const cachedFontAtlas = cache.get(key);
+ if (!cachedFontAtlas) {
+ return characterSet;
+ }
+
+ const newChars = [];
+ const cachedMapping = cachedFontAtlas.mapping;
+ let cachedCharSet = Object.keys(cachedMapping);
+ cachedCharSet = new Set(cachedCharSet);
+
+ let charSet = characterSet;
+ if (charSet instanceof Array) {
+ charSet = new Set(charSet);
+ }
+
+ charSet.forEach(char => {
+ if (!cachedCharSet.has(char)) {
+ newChars.push(char);
+ }
+ });
+
+ return newChars;
+}
+
+function populateAlphaChannel(alphaChannel, imageData) {
+ // populate distance value from tinySDF to image alpha channel
+ for (let i = 0; i < alphaChannel.length; i++) {
+ imageData.data[4 * i + 3] = alphaChannel[i];
+ }
+}
+
+export default class FontAtlasManager {
+ constructor() {
+
+ // font settings
+ this.props = {
+ fontFamily: DEFAULT_FONT_FAMILY,
+ fontWeight: DEFAULT_FONT_WEIGHT,
+ characterSet: DEFAULT_CHAR_SET,
+ fontSize: DEFAULT_FONT_SIZE,
+ buffer: DEFAULT_BUFFER,
+ // sdf only props
+ // https://github.com/mapbox/tiny-sdf
+ sdf: true,
+ cutoff: DEFAULT_CUTOFF,
+ radius: DEFAULT_RADIUS
+ };
+
+ // key is used for caching generated fontAtlas
+ this._key = null;
+ this._texture = new THREE.Texture();
+ }
+
+ get texture() {
+ return this._texture;
+ }
+
+ get mapping() {
+ const data = cache.get(this._key);
+ return data && data.mapping;
+ }
+
+ get scale() {
+ return HEIGHT_SCALE;
+ }
+
+ get fontAtlas() {
+ return this._fontAtlas;
+ }
+
+ setProps(props = {}) {
+ VALID_PROPS.forEach(prop => {
+ if (prop in props) {
+ this.props[prop] = props[prop];
+ }
+ });
+
+ // update cache key
+ const oldKey = this._key;
+ this._key = this._getKey();
+
+ const charSet = getNewChars(this._key, this.props.characterSet);
+ const cachedFontAtlas = cache.get(this._key);
+
+ // if a fontAtlas associated with the new settings is cached and
+ // there are no new chars
+ if (cachedFontAtlas && charSet.length === 0) {
+ // update texture with cached fontAtlas
+ if (this._key !== oldKey) {
+ this._updateTexture(cachedFontAtlas);
+ }
+ return;
+ }
+
+ // update fontAtlas with new settings
+ const fontAtlas = this._generateFontAtlas(this._key, charSet, cachedFontAtlas);
+ this._fontAtlas = fontAtlas;
+ this._updateTexture(fontAtlas);
+
+ // update cache
+ cache.set(this._key, fontAtlas);
+ }
+
+ _updateTexture({ data: canvas }) {
+ this._texture = new THREE.CanvasTexture(canvas);
+ this._texture.wrapS = THREE.ClampToEdgeWrapping;
+ this._texture.wrapT = THREE.ClampToEdgeWrapping;
+ this._texture.minFilter = THREE.LinearFilter;
+ this._texture.flipY = false;
+ this._texture.needUpdate = true;
+ }
+
+ _generateFontAtlas(key, characterSet, cachedFontAtlas) {
+ const { fontFamily, fontWeight, fontSize, buffer, sdf, radius, cutoff } = this.props;
+ let canvas = cachedFontAtlas && cachedFontAtlas.data;
+ if (!canvas) {
+ canvas = document.createElement('canvas');
+ canvas.width = MAX_CANVAS_WIDTH;
+ }
+ const ctx = canvas.getContext('2d');
+
+ setTextStyle(ctx, fontFamily, fontSize, fontWeight);
+
+ // 1. build mapping
+ const { mapping, canvasHeight, xOffset, yOffset } = buildMapping(
+ Object.assign(
+ {
+ getFontWidth: char => ctx.measureText(char).width,
+ fontHeight: fontSize * HEIGHT_SCALE,
+ buffer,
+ characterSet,
+ maxCanvasWidth: MAX_CANVAS_WIDTH
+ },
+ cachedFontAtlas && {
+ mapping: cachedFontAtlas.mapping,
+ xOffset: cachedFontAtlas.xOffset,
+ yOffset: cachedFontAtlas.yOffset
+ }
+ )
+ );
+
+ // 2. update canvas
+ // copy old canvas data to new canvas only when height changed
+ if (canvas.height !== canvasHeight) {
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ canvas.height = canvasHeight;
+ ctx.putImageData(imageData, 0, 0);
+ }
+ setTextStyle(ctx, fontFamily, fontSize, fontWeight);
+
+ // 3. layout characters
+ if (sdf) {
+ const tinySDF = new TinySDF(fontSize, buffer, radius, cutoff, fontFamily, fontWeight);
+ // used to store distance values from tinySDF
+ // tinySDF.size equals `fontSize + buffer * 2`
+ const imageData = ctx.getImageData(0, 0, tinySDF.size, tinySDF.size);
+
+ for (const char of characterSet) {
+ populateAlphaChannel(tinySDF.draw(char), imageData);
+ ctx.putImageData(imageData, mapping[char].x - buffer, mapping[char].y - buffer);
+ }
+ } else {
+ for (const char of characterSet) {
+ ctx.fillText(char, mapping[char].x, mapping[char].y + fontSize * BASELINE_SCALE);
+ }
+ }
+ return {
+ xOffset,
+ yOffset,
+ mapping,
+ data: canvas,
+ width: canvas.width,
+ height: canvas.height
+ };
+ }
+
+ _getKey() {
+ const { fontFamily, fontWeight, fontSize, buffer, sdf, radius, cutoff } = this.props;
+ if (sdf) {
+ return `${fontFamily} ${fontWeight} ${fontSize} ${buffer} ${radius} ${cutoff}`;
+ }
+ return `${fontFamily} ${fontWeight} ${fontSize} ${buffer}`;
+ }
+}
diff --git a/src/geom/buffer/point/text/lru-cache.js b/src/geom/buffer/point/text/lru-cache.js
new file mode 100644
index 0000000000..8b417e53e2
--- /dev/null
+++ b/src/geom/buffer/point/text/lru-cache.js
@@ -0,0 +1,71 @@
+/**
+ * LRU Cache class with limit
+ *
+ * Update order for each get/set operation
+ * Delete oldest when reach given limit
+ */
+
+export default class LRUCache {
+ constructor(limit = 5) {
+ this.limit = limit;
+
+ this.clear();
+ }
+
+ clear() {
+ this._cache = {};
+ // access/update order, first item is oldest, last item is newest
+ this._order = [];
+ }
+
+ get(key) {
+ const value = this._cache[key];
+ if (value) {
+ // update order
+ this._deleteOrder(key);
+ this._appendOrder(key);
+ }
+ return value;
+ }
+
+ set(key, value) {
+ if (!this._cache[key]) {
+ // if reach limit, delete the oldest
+ if (Object.keys(this._cache).length === this.limit) {
+ this.delete(this._order[0]);
+ }
+
+ this._cache[key] = value;
+ this._appendOrder(key);
+ } else {
+ // if found in cache, delete the old one, insert new one to the first of list
+ this.delete(key);
+
+ this._cache[key] = value;
+ this._appendOrder(key);
+ }
+ }
+
+ delete(key) {
+ const value = this._cache[key];
+ if (value) {
+ this._deleteCache(key);
+ this._deleteOrder(key);
+ }
+ }
+
+ _deleteCache(key) {
+ delete this._cache[key];
+ }
+
+ _deleteOrder(key) {
+ const index = this._order.findIndex(o => o === key);
+ if (index >= 0) {
+ this._order.splice(index, 1);
+ }
+ }
+
+ _appendOrder(key) {
+ this._order.push(key);
+ }
+}
diff --git a/src/geom/buffer/point/textBuffer.js b/src/geom/buffer/point/textBuffer.js
deleted file mode 100644
index 211dc00ff6..0000000000
--- a/src/geom/buffer/point/textBuffer.js
+++ /dev/null
@@ -1,181 +0,0 @@
-
-
-import { getJSON } from '../../../util/ajax';
-import EventEmitter from 'wolfy87-eventemitter';
-import Global from '../../../global';
-// const Space = 1;
-const metrics = {
- buffer: 3,
- family: 'ios9',
- size: 24
-};
-export default function TextBuffer(layerData, style) {
- EventEmitter.call(this);
- const attributes = {
- originPoints: [],
- textSizes: [],
- textOffsets: [],
- colors: [],
- textureElements: []
- };
- const { textOffset = [ 0, 0 ] } = style;
- const chars = [];
- const textChars = {};
- layerData.forEach(element => {
- let text = element.shape || '';
- text = text.toString();
- for (let j = 0; j < text.length; j++) {
- const code = text.charCodeAt(j);
- textChars[text] = 0;
- if (chars.indexOf(code) === -1) {
- chars.push(text.charCodeAt(j));
- }
- }
- });
- loadTextInfo(chars, (chars, texture) => {
- layerData.forEach(element => {
- const size = element.size;
- const pos = layerData.coordinates;
- const pen = { x: textOffset[0], y: textOffset[1] };
- let text = element.shape || '';
- text = text.toString();
- for (let i = 0; i < text.length; i++) {
- const color = element.color;
- drawGlyph(chars, pos, text[i], pen, size, attributes.colors, attributes.textureElements, attributes.originPoints, attributes.textSizes, attributes.textOffsets, color);
- }
- this.emit('completed', { attributes, texture });
- });
- });
-}
-
-function loadTextInfo(chars, done) {
- getJSON({
- url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
- }, (e, info) => {
- loadTextTexture(info.url, texture => {
- done(info.info, texture);
- });
- });
-}
-function loadTextTexture(url, cb) {
-
-
- const img = new Image();
- img.crossOrigin = 'anonymous';
-
- img.onload = () => {
- const textTexture = this._creatTexture(img);
- cb(textTexture);
- };
- img.src = url;
-
-}
-/**
- * 计算每个标注词语的位置
- * @param {*} chars 文本信息
- * @param {*} pos 文字三维空间坐标
- * @param {*} text 字符
- * @param {*} pen 字符在词语的偏移量
- * @param {*} size 字体大小
- * @param {*} colors 颜色
- * @param {*} textureElements 纹理坐标
- * @param {*} originPoints 初始位置数据
- * @param {*} textSizes 文字大小数组
- * @param {*} textOffsets 字体偏移量数据
- * @param {*} color 文字颜色
- */
-function drawGlyph(chars, pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
- const chr = text.charCodeAt(0);
- const metric = chars[chr];
- if (!metric) return;
- const scale = size / metrics.size;
-
- let width = metric[0];
- let height = metric[1];
- const posX = metric[5];
- const posY = metric[6];
- const buffer = metrics.buffer;
- if (width > 0 && height > 0) {
- width += buffer * 2;
- height += buffer * 2;
- const originX = 0;
- const originY = 0;
- const offsetX = pen.x;
- const offsetY = pen.y;
- originPoints.push(
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- );
- const bx = 0;
- const by = metrics.size / 2 + buffer;
- textSizes.push(
- ((bx - buffer + width) * scale), (height - by) * scale,
- ((bx - buffer) * scale), (height - by) * scale,
- ((bx - buffer) * scale), -by * scale,
-
- ((bx - buffer + width) * scale), (height - by) * scale,
- ((bx - buffer) * scale), -by * scale,
- ((bx - buffer + width) * scale), -by * scale,
- );
-
-
- textOffsets.push(
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- );
-
- colors.push(
- ...color,
- ...color,
- ...color,
- ...color,
- ...color,
- ...color,
- );
- textureElements.push(
-
- posX + width, posY,
- posX, posY,
- posX, posY + height,
-
- posX + width, posY,
- posX, posY + height,
- posX + width, posY + height
- );
- }
- pen.x = pen.x + size * 1.8;
-
-}
-
-
-// function measureText(text, size) {
-// const dimensions = {
-// advance: 0
-// };
-// const metrics = this.metrics;
-// const scale = size / metrics.size;
-// for (let i = 0; i < text.length; i++) {
-// const code = text.charCodeAt(i);
-// const horiAdvance = metrics.chars[code][4];
-
-// dimensions.advance += (horiAdvance + Space) * scale;
-// }
-
-// return dimensions;
-// }
-// function creatTexture(image) {
-// this.bufferStruct.textSize = [ image.width, image.height ];
-// const texture = new THREE.Texture(image);
-// texture.minFilter = THREE.LinearFilter;
-// texture.magFilter = THREE.ClampToEdgeWrapping;
-// texture.needsUpdate = true;
-// return texture;
-// }
diff --git a/src/geom/buffer/text.js b/src/geom/buffer/text.js
deleted file mode 100644
index 4680ffeafe..0000000000
--- a/src/geom/buffer/text.js
+++ /dev/null
@@ -1,276 +0,0 @@
-import BufferBase from './bufferBase';
-import { getJSON } from '../../util/ajax';
-import * as THREE from '../../core/three';
-import TinySDF from '@mapbox/tiny-sdf';
-
-import Global from '../../global';
-const Space = 1;
-export default class TextBuffer extends BufferBase {
-
- geometryBuffer() {
- this.metrics = {
- buffer: 3,
- family: 'ios9',
- size: 24
- };
- const layerData = this.get('layerData');
- const { textOffset = [ 0, 0 ] } = this.get('style');
- const chars = [];
- const textChars = {};
- layerData.forEach(element => {
- let text = element.shape || '';
- text = text.toString();
- for (let j = 0; j < text.length; j++) {
- const code = text.charCodeAt(j);
- textChars[text] = 0;
- if (chars.indexOf(code) === -1) {
- chars.push(text.charCodeAt(j));
- }
- }
- });
- const sdfTexture = this._updateSdf(Object.keys(textChars).join(''));
- this.sdfTexture = sdfTexture;
-
- this._loadTextInfo(chars);
- this.on('SourceLoaded', () => {
- const textureElements = [];
- const colors = [];
- const originPoints = [];
- const textSizes = [];
- const textOffsets = [];
- layerData.forEach(element => {
- const size = element.size;
- const pos = element.coordinates;
- // const pen = { x: pos[0] - dimensions.advance / 2, y: pos[1] };
- const pen = { x: textOffset[0], y: textOffset[1] };
- let text = element.shape || '';
- text = text.toString();
- for (let i = 0; i < text.length; i++) {
-
-
- const color = element.color;
- this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
- }
- });
- this.bufferStruct.style = layerData;
- this.attributes = {
- originPoints,
- textSizes,
- textOffsets,
- colors,
- textureElements
- };
- this.emit('completed');
- });
-
- }
-
- _loadTextInfo(chars) {
- getJSON({
- url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
- }, (e, info) => {
- this.metrics.chars = info.info;
-
- this._loadTextTexture(info.url);
- });
- }
- _loadTextTexture(url) {
-
-
- const img = new Image();
- img.crossOrigin = 'anonymous';
-
-
- img.onload = () => {
- this.bufferStruct.textTexture = this._creatTexture(this.sdfTexture.texure);
- this.emit('SourceLoaded');
- };
- img.src = url;
-
- }
- /**
- * 计算每个标注词语的位置
- * @param {*} pos 文字三维空间坐标
- * @param {*} text 字符
- * @param {*} pen 字符在词语的偏移量
- * @param {*} size 字体大小
- * @param {*} colors 颜色
- * @param {*} textureElements 纹理坐标
- * @param {*} originPoints 初始位置数据
- * @param {*} textSizes 文字大小数组
- * @param {*} textOffsets 字体偏移量数据
- * @param {*} color 文字颜色
- */
- _drawGlyph(pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
- const metrics = this.metrics;
- const chr = text.charCodeAt(0);
- const metric = metrics.chars[chr];
- if (!metric) return;
- const info = this.sdfTexture.info;
- const { x, y } = info[text];
- const scale = size / metrics.size;
-
- let width = 24; // metric[0];
- let height = 24;// metric[1];
-
- // const horiBearingX = metric[2];
- // const horiBearingY = metric[3];
-
- // const horiAdvance = metric[4];
- // const posX = metric[5];
- // const posY = metric[6];
- const posX = x;
- const posY = y;
-
- const buffer = metrics.buffer;
-
- if (width > 0 && height > 0) {
- width += buffer * 2;
- height += buffer * 2;
-
- // Add a quad (= two triangles) per glyph.
- // const originX = (horiBearingX - buffer + width / 2) * scale;
- // const originY = -(height - horiBearingY) * scale;
- const originX = 0;
- const originY = 0;
-
- // const offsetWidth = width / 2 * scale / (1.0 - horiBearingX * 1.5 / horiAdvance);
- // const offsetHeight = (horiAdvance / 2) * scale;
-
- // const offsetWidth = width/2 * scale;
- // const offsetHeight = height / 2 * scale;
- // const offsetHeight = height * scale;
-
- const offsetX = pen.x;
- const offsetY = pen.y;
- originPoints.push(
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- pos[0] + originX, pos[1] + originY, 0,
- );
-
- // textSizes.push(
- // offsetWidth, offsetHeight,
- // -offsetWidth, offsetHeight,
- // -offsetWidth, -offsetHeight,
- // offsetWidth, offsetHeight,
- // -offsetWidth, -offsetHeight,
- // offsetWidth, -offsetHeight,
- // );
- const bx = 0;
- const by = metrics.size / 2 + buffer;
- textSizes.push(
-
-
- ((bx - buffer + width) * scale), (height - by) * scale,
- ((bx - buffer) * scale), (height - by) * scale,
- ((bx - buffer) * scale), -by * scale,
-
- ((bx - buffer + width) * scale), (height - by) * scale,
- ((bx - buffer) * scale), -by * scale,
- ((bx - buffer + width) * scale), -by * scale,
-
-
- );
-
-
- textOffsets.push(
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- offsetX, offsetY,
- );
-
- colors.push(
- ...color,
- ...color,
- ...color,
- ...color,
- ...color,
- ...color,
- );
- textureElements.push(
-
- posX + width, posY,
- posX, posY,
- posX, posY + height,
-
- posX + width, posY,
- posX, posY + height,
- posX + width, posY + height
- );
- }
-
- // pen.x = pen.x + (horiAdvance + Space) * scale;
- pen.x = pen.x + size * 1.8;
-
- }
-
-
- _measureText(text, size) {
- const dimensions = {
- advance: 0
- };
- const metrics = this.metrics;
- const scale = size / metrics.size;
- for (let i = 0; i < text.length; i++) {
- const code = text.charCodeAt(i);
- const horiAdvance = metrics.chars[code][4];
-
- dimensions.advance += (horiAdvance + Space) * scale;
- }
-
- return dimensions;
- }
- _creatTexture(image) {
- this.bufferStruct.textSize = [ image.width, image.height ];
- const texture = new THREE.Texture(image);
- texture.minFilter = THREE.LinearFilter;
- texture.magFilter = THREE.ClampToEdgeWrapping;
- texture.needsUpdate = true;
- return texture;
- }
- _updateSdf(chars) {
- const canvas = document.createElement('canvas');
- const ctx = canvas.getContext('2d');
- const sdfs = {};
-
-
- const fontSize = 24;
- const fontWeight = 100;
- const buffer = fontSize / 8;
- const radius = fontSize / 3;
- const canvasSize = Math.floor(Math.pow(chars.length, 0.5)) * (fontSize + buffer + radius);
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- const sdf = new TinySDF(fontSize, buffer, radius, null, null, fontWeight);
- for (let y = 0, i = 0; y + sdf.size <= canvas.height && i < chars.length; y += sdf.size) {
- for (let x = 0; x + sdf.size <= canvas.width && i < chars.length; x += sdf.size) {
- ctx.putImageData(this._makeRGBAImageData(ctx, sdf.draw(chars[i]), sdf.size), x, y);
- sdfs[chars[i]] = { x, y };
- i++;
- }
- }
- return {
- info: sdfs,
- texure: canvas
- };
- }
- _makeRGBAImageData(ctx, alphaChannel, size) {
- const imageData = ctx.createImageData(size, size);
- const data = imageData.data;
- for (let i = 0; i < alphaChannel.length; i++) {
- data[4 * i + 0] = alphaChannel[i];
- data[4 * i + 1] = alphaChannel[i];
- data[4 * i + 2] = alphaChannel[i];
- data[4 * i + 3] = 255;
- }
- return imageData;
- }
-}
diff --git a/src/geom/material/rainPass.js b/src/geom/material/rainPass.js
deleted file mode 100644
index d80b0b0fc5..0000000000
--- a/src/geom/material/rainPass.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import { UniformSemantic, DataType, RenderState, BlendFunc } from '@ali/r3-base';
-import { Material, RenderTechnique } from '@ali/r3-material';
-import point_frag from '../shader/rainPass_frag.glsl';
-import point_vert from '../shader/rainPass_vert.glsl';
-export class RainPassMaterial extends Material {
- constructor(opt) {
- super(opt.name);
-
- // this._generateTechnique();
-
- for (const item in opt) {
- if (item.substr(0, 2) === 'u_') {
- this.setValue(item, opt[item]);
- }
- }
- }
- _generateTechnique() {
-
- const VERT_SHADER = point_vert;
- // 片元着色器
- const FRAG_SHADER = point_frag;
- // Technique 配置信息
- const cfg = {
- attributes: {
- a_position: {
- name: 'a_position',
- semantic: 'POSITION',
- type: DataType.FLOAT_VEC3
- },
- a_uv: {
- name: 'a_uv',
- semantic: 'TEXCOORD_0',
- type: DataType.FLOAT_VEC2
- }
- },
- uniforms: {
- matModelViewProjection: {
- name: 'matModelViewProjection',
- semantic: UniformSemantic.MODELVIEWPROJECTION,
- type: DataType.FLOAT_MAT4
- },
- u_texture: {
- name: 'u_texture',
- type: DataType.SAMPLER_2D
- },
- u_colorTexture: {
- name: 'u_colorTexture',
- type: DataType.SAMPLER_2D
- }
-
- }
- };
-
- // 创建 Technique
- const tech = new RenderTechnique('PointMaterial');
- tech.states = {
- disable: [ RenderState.CULL_FACE, RenderState.DEPTH_TEST ],
- enable: [ RenderState.BLEND ],
- functions: { blendFunc: [ BlendFunc.SRC_ALPHA, BlendFunc.ONE_MINUS_SRC_ALPHA ] }
- };
- tech.isValid = true;
- tech.uniforms = cfg.uniforms;
- tech.attributes = cfg.attributes;
- tech.vertexShader = VERT_SHADER;
- tech.fragmentShader = FRAG_SHADER;
- tech.customMacros = this._macros;
- this._technique = tech;
- }
-
- prepareDrawing(camera, component, primitive) {
-
- this.getAttributeDefines(camera, component, primitive);
- if (!this._technique) { this._generateTechnique(); }
- super.prepareDrawing(camera, component, primitive);
-
- }
- getAttributeDefines(camera, component, primitive) {
- this._macros = [];
- if (!primitive) return this._macros;
-
- const attribNames = Object.keys(primitive.vertexAttributes);
- if (attribNames.indexOf('SHAPE') !== -1) {
- this._macros.push('SHAPE');
- }
- if (attribNames.indexOf('TEXCOORD_0') !== -1) {
- this._macros.push('TEXCOORD_0');
- }
-
- }
-
-}
diff --git a/src/geom/material/textMaterial.js b/src/geom/material/textMaterial.js
index b0c51bc4b4..7e9d52ca1b 100644
--- a/src/geom/material/textMaterial.js
+++ b/src/geom/material/textMaterial.js
@@ -9,12 +9,13 @@ export default function TextMaterial(options) {
u_texture: { value: options.u_texture },
u_strokeWidth: { value: options.u_strokeWidth },
u_stroke: { value: options.u_stroke },
- u_textSize: { value: options.u_textSize },
+ u_textTextureSize: { value: options.u_textTextureSize },
u_scale: { value: options.u_scale },
u_gamma: { value: options.u_gamma },
u_buffer: { value: options.u_buffer },
- u_color: { value: options.u_color },
- u_glSize: { value: options.u_glSize }
+ u_glSize: { value: options.u_glSize },
+ u_activeId: { value: options.u_activeId || 0 },
+ u_activeColor: { value: options.u_activeColor }
},
vertexShader: vs,
diff --git a/src/geom/shader/polygon_frag1.glsl b/src/geom/shader/polygon_frag1.glsl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/geom/shader/polygon_vert1.glsl b/src/geom/shader/polygon_vert1.glsl
deleted file mode 100644
index 9c8508c674..0000000000
--- a/src/geom/shader/polygon_vert1.glsl
+++ /dev/null
@@ -1,48 +0,0 @@
-precision highp float;
-#define ambientRatio 0.5
-#define diffuseRatio 0.4
-#define specularRatio 0.1
-attribute vec4 a_color;
-attribute vec4 a_idColor;
-attribute vec2 faceUv;
-attribute vec3 a_shape;
-attribute vec3 a_size;
-uniform float u_zoom;
-varying vec2 v_texCoord;
-varying vec4 v_color;
-varying float v_lightWeight;
-varying float v_size;
-
-void main() {
- float scale = pow(2.0,(20.0 - u_zoom));
- mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
- vec3 newposition = position;
- #ifdef SHAPE
- newposition =position + a_size * scale* a_shape;
- #endif
- v_texCoord = faceUv;
- if(normal == vec3(0.,0.,1.)){
- v_color = a_color;
- gl_Position = matModelViewProjection * vec4(newposition, 1.0);
- return;
- }
-
- vec3 worldPos = vec3(vec4(newposition,1.0) * modelMatrix);
- vec3 worldNormal = vec3(vec4(normal,1.0) * modelMatrix);
- // //cal light weight
- vec3 viewDir = normalize(cameraPosition - worldPos);
- //vec3 lightDir = normalize(vec3(1, -10.5, 12));
- vec3 lightDir = normalize(vec3(0.,-10.,1.));
- vec3 halfDir = normalize(viewDir+lightDir);
- // //lambert
- float lambert = dot(worldNormal, lightDir);
- //specular
- float specular = pow( max(0.0, dot(worldNormal, halfDir)), 32.0);
- //sum to light weight
- float lightWeight = ambientRatio + diffuseRatio * lambert + specularRatio * specular;
- v_texCoord = faceUv;
- v_lightWeight = lightWeight;
- // v_size = a_size;
- v_color =vec4(a_color.rgb*lightWeight, a_color.w);
- gl_Position = matModelViewProjection * vec4(newposition, 1.0);
-}
\ No newline at end of file
diff --git a/src/geom/shader/rainPass_frag.glsl b/src/geom/shader/rainPass_frag.glsl
deleted file mode 100644
index 555ee65f21..0000000000
--- a/src/geom/shader/rainPass_frag.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-precision mediump float;
-uniform sampler2D u_texture;
-varying float v_time;
-varying vec2 v_texCoord;
-
-
-void main() {
- vec4 color = texture2D(u_texture, v_texCoord);
- if(color.w ==0.)
- discard;
- gl_FragColor = texture2D(u_texture, v_texCoord);
-
-}
\ No newline at end of file
diff --git a/src/geom/shader/rainPass_vert.glsl b/src/geom/shader/rainPass_vert.glsl
deleted file mode 100644
index 531a4b1557..0000000000
--- a/src/geom/shader/rainPass_vert.glsl
+++ /dev/null
@@ -1,20 +0,0 @@
-precision highp float;
-attribute vec3 a_position;
-attribute vec2 a_uv;
-uniform mat4 matModelViewProjection;
-uniform float u_time;
-// varying float v_time;
-
-varying vec2 v_texCoord;
-varying vec4 v_color;
-float random (in float x) {
- return fract(sin(x)*1e4);
-}
-
-void main() {
- v_texCoord = a_uv;
- float z = a_position.z;
- z = z - mod(u_time * 1000000.0, 5000000.0);
- gl_Position = matModelViewProjection * vec4(vec2(a_position), z, 1.0);
- gl_PointSize = 3.0;
-}
\ No newline at end of file
diff --git a/src/geom/shader/rain_frag.glsl b/src/geom/shader/rain_frag.glsl
deleted file mode 100644
index 350368fdab..0000000000
--- a/src/geom/shader/rain_frag.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-precision mediump float;
-uniform sampler2D u_texture;
-uniform sampler2D u_colorTexture;
-uniform vec2 u_wind_min;
-uniform vec2 u_wind_max;
-varying float v_time;
-varying vec2 v_texCoord;
-
-void main() {
- vec2 velocity = mix(u_wind_min, u_wind_max, texture2D(u_texture, v_texCoord).rg);
- float speed_t = length(velocity) / length(u_wind_max);
- vec2 ramp_pos = vec2(
- fract(16.0 * speed_t),
- floor(16.0 * speed_t) / 16.0);
- gl_FragColor = texture2D(u_colorTexture, ramp_pos);
-
-}
\ No newline at end of file
diff --git a/src/geom/shader/rain_vert.glsl b/src/geom/shader/rain_vert.glsl
deleted file mode 100644
index 69b4129d2d..0000000000
--- a/src/geom/shader/rain_vert.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-precision highp float;
-attribute vec3 a_position;
-attribute vec2 a_uv;
-uniform mat4 matModelViewProjection;
-uniform float u_time;
-// varying float v_time;
-
-varying vec2 v_texCoord;
-varying vec4 v_color;
-float random (in float x) {
- return fract(sin(x)*1e4);
-}
-
-void main() {
- v_texCoord = a_uv;
- gl_Position = matModelViewProjection * vec4(a_position, 1.0);
- gl_PointSize = 1.0;
-}
\ No newline at end of file
diff --git a/src/geom/shader/text_frag.glsl b/src/geom/shader/text_frag.glsl
index 886403db72..f29d97a435 100644
--- a/src/geom/shader/text_frag.glsl
+++ b/src/geom/shader/text_frag.glsl
@@ -1,32 +1,28 @@
precision mediump float;
uniform sampler2D u_texture;
-varying vec4 v_color;
+varying vec4 v_color;
uniform vec4 u_stroke;
uniform float u_strokeWidth;
uniform float u_buffer;
uniform float u_gamma;
-
+uniform float u_opacity;
varying vec2 v_texcoord;
-
-void main() {
-
- float dist =texture2D(u_texture, vec2(v_texcoord.x,1.0-v_texcoord.y)).r;
+void main(){
+ float dist=texture2D(u_texture,vec2(v_texcoord.x,v_texcoord.y)).a;
float alpha;
- if(u_strokeWidth == 0.0){
- alpha = smoothstep(u_buffer - u_gamma, u_buffer + u_gamma, dist);
- gl_FragColor = vec4(v_color.rgb, alpha * v_color.a);
+ if(u_strokeWidth==0.){
+ alpha=smoothstep(u_buffer-u_gamma,u_buffer+u_gamma,dist);
+ gl_FragColor=vec4(v_color.rgb,alpha*v_color.a);
}else{
-
- if(dist <= u_buffer - u_gamma){
-
- alpha = smoothstep(u_strokeWidth - u_gamma, u_strokeWidth+ u_gamma, dist);
- gl_FragColor = vec4(u_stroke.rgb, alpha * u_stroke.a);
- }else if(dist < u_buffer){
- alpha = smoothstep(u_buffer - u_gamma, u_buffer+u_gamma, dist);
- gl_FragColor = vec4(alpha * v_color.rgb + (1.0 - alpha) * u_stroke.rgb, 1.0 * v_color.a * alpha + (1.0 - alpha) * u_stroke.a);
+ if(dist<=u_buffer-u_gamma){
+ alpha=smoothstep(u_strokeWidth-u_gamma,u_strokeWidth+u_gamma,dist);
+ gl_FragColor=vec4(u_stroke.rgb,alpha*u_stroke.a);
+ }else if(dist 0 && this.animateDuration < this.scene._engine.clock.getElapsedTime()) {
this.layerMesh.material.setDefinesvalue('ANIMATE', false);
this.emit('animateEnd');
+ this.scene.stopAnimate();
this.animateDuration = Infinity;
}
}
diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js
index b9a5817c12..de3cbf3a57 100644
--- a/src/layer/pointLayer.js
+++ b/src/layer/pointLayer.js
@@ -1,10 +1,9 @@
import Layer from '../core/layer';
-import * as THREE from '../core/three';
import * as drawPoint from '../layer/render/point';
+import TextBuffer from '../geom/buffer/point/text';
+import DrawText from './render/point/drawText';
import Global from '../global';
// import PointBuffer from '../geom/buffer/point';
-import TextBuffer from '../geom/buffer/text';
-import TextMaterial from '../geom/material/textMaterial';
import * as PointBuffer from '../geom/buffer/point/index';
const { pointShape } = Global;
/**
@@ -15,26 +14,22 @@ const { pointShape } = Global;
*/
export default class PointLayer extends Layer {
-
render() {
this.type = 'point';
-
this.init();
if (!this._hasRender) {
this._prepareRender(this.shapeType);
this._hasRender = true;
} else {
this._initAttrs();
- (this._needUpdateFilter || this._needUpdateColor) ? this._updateFilter() : null;
+ this._needUpdateFilter || this._needUpdateColor
+ ? this._updateFilter()
+ : null;
}
return this;
}
_prepareRender() {
const { stroke, fill } = this.get('styleOptions');
- if (this.shapeType === 'text') { // 绘制文本图层
- this._textPoint();
- return;
- }
const style = this.get('styleOptions');
const activeOption = this.get('activedOptions');
const config = {
@@ -42,36 +37,55 @@ export default class PointLayer extends Layer {
activeColor: activeOption.fill
};
const pointShapeType = this._getShape();
-
switch (pointShapeType) {
- case 'fill' :// 填充图形
- {
- if (fill !== 'none') { // 是否填充
- const attributes = PointBuffer.FillBuffer(this.layerData, style);
- const meshfill = drawPoint.DrawFill(attributes, config);
- this.add(meshfill);
- }
- if (stroke !== 'none') { // 是否绘制边界
- const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style);
- const meshStroke = drawPoint.DrawStroke(lineAttribute, config);
- this.add(meshStroke, 'line');
- }
- break;
+ case 'fill': { // 填充图形
+ if (fill !== 'none') {
+ // 是否填充
+ const attributes = PointBuffer.FillBuffer(this.layerData, style);
+ const meshfill = drawPoint.DrawFill(attributes, config);
+ this.add(meshfill);
}
- case 'image':// 绘制图片标注
- {
- const imageAttribute = PointBuffer.ImageBuffer(this.layerData, { imagePos: this.scene.image.imagePos });
- const imageMesh = drawPoint.DrawImage(imageAttribute, { ...style, texture: this.scene.image.texture });
- this.add(imageMesh);
- break;
- }
- case 'normal' : // 原生点
- {
- const normalAttribute = PointBuffer.NormalBuffer(this.layerData, style);
- const normalPointMesh = drawPoint.DrawNormal(normalAttribute, config);
- this.add(normalPointMesh);
- break;
+ if (stroke !== 'none') {
+ // 是否绘制边界
+ const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style);
+ const meshStroke = drawPoint.DrawStroke(lineAttribute, config);
+ this.add(meshStroke, 'line');
}
+ break;
+ }
+ case 'image': { // 绘制图片标注
+ const imageAttribute = PointBuffer.ImageBuffer(this.layerData, {
+ imagePos: this.scene.image.imagePos
+ });
+ const imageMesh = drawPoint.DrawImage(imageAttribute, {
+ ...style,
+ texture: this.scene.image.texture
+ });
+ this.add(imageMesh);
+ break;
+ }
+ case 'normal': { // 原生点
+ const normalAttribute = PointBuffer.NormalBuffer(this.layerData, style);
+ const normalPointMesh = drawPoint.DrawNormal(normalAttribute, config);
+ this.add(normalPointMesh);
+ break;
+ }
+ case 'text': { // 原生点
+ const { width, height } = this.scene.getSize();
+ const textCfg = {
+ ...style,
+ width,
+ height,
+ activeColor: activeOption.fill
+ };
+ const buffer = new TextBuffer(
+ this.layerData,
+ this.scene.fontAtlasManager
+ );
+ const mesh = new DrawText(buffer, textCfg);
+ this.add(mesh);
+ break;
+ }
default:
return null;
}
@@ -88,51 +102,14 @@ export default class PointLayer extends Layer {
break;
}
}
- if (pointShape['2d'].indexOf(shape) !== -1 || pointShape['3d'].indexOf(shape) !== -1) {
+ if (
+ pointShape['2d'].indexOf(shape) !== -1 ||
+ pointShape['3d'].indexOf(shape) !== -1
+ ) {
return 'fill';
- } else if (shape === 'text') {
- return 'text';
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
return 'image';
}
- return 'normal';
-
-
+ return 'text';
}
- _textPoint() {
- const styleOptions = this.get('styleOptions');
- const buffer = new TextBuffer({
- type: this.shapeType,
- layerData: this.layerData,
- style: this.get('styleOptions')
- });
-
- buffer.on('completed', () => {
- const { color, stroke } = styleOptions;
- const geometry = new THREE.BufferGeometry();
- geometry.addAttribute('position', new THREE.Float32BufferAttribute(buffer.attributes.originPoints, 3));
- geometry.addAttribute('uv', new THREE.Float32BufferAttribute(buffer.attributes.textureElements, 2));
- geometry.addAttribute('a_txtsize', new THREE.Float32BufferAttribute(buffer.attributes.textSizes, 2));
- geometry.addAttribute('a_txtOffsets', new THREE.Float32BufferAttribute(buffer.attributes.textOffsets, 2));
- geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(buffer.attributes.colors, 4));
- const { width, height } = this.scene.getSize();
- const material = new TextMaterial({
- name: this.layerId,
- u_texture: buffer.bufferStruct.textTexture,
- u_strokeWidth: styleOptions.strokeWidth,
- u_stroke: stroke,
- u_textSize: buffer.bufferStruct.textSize,
- u_gamma: 2 * 1.4142 / 64,
- u_buffer: 0.65,
- u_color: color,
- u_glSize: [ width, height ]
- });
- const mesh = new THREE.Mesh(geometry, material);
- this.add(mesh);
-
- });
-
- }
-
}
-
diff --git a/src/layer/polygonLayer.js b/src/layer/polygonLayer.js
index bea74f5975..17c95244ef 100644
--- a/src/layer/polygonLayer.js
+++ b/src/layer/polygonLayer.js
@@ -44,6 +44,7 @@ export default class PolygonLayer extends Layer {
return drawPolygon.DrawLine(attributes, style);
} else if (animateOptions.enable) {
const { near, far } = this.map.getCameraState();
+ this.scene.startAnimate();
return drawPolygon.DrawAnimate(attributes, { ...style, near, far });
}
return drawPolygon.DrawFill(attributes, config);
diff --git a/src/layer/render/point/drawText.js b/src/layer/render/point/drawText.js
index 0be1854239..0604938e61 100644
--- a/src/layer/render/point/drawText.js
+++ b/src/layer/render/point/drawText.js
@@ -1,23 +1,48 @@
-// import * as THREE from '../../../core/three';
-// import TextMaterial from '../../../geom/material/textMaterial';
-// export default function DawText(attributes, texture, style) {
-// const geometry = new THREE.BufferGeometry();
-// const { strokeWidth, stroke, opacity } = style;
-// geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.originPoints, 3));
-// geometry.addAttribute('uv', new THREE.Float32BufferAttribute(attributes.textureElements, 2));
-// geometry.addAttribute('a_txtsize', new THREE.Float32BufferAttribute(attributes.textSizes, 2));
-// geometry.addAttribute('a_txtOffsets', new THREE.Float32BufferAttribute(attributes.textOffsets, 2));
-// geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
-// const material = new TextMaterial({
-// name: this.layerId,
-// u_texture: texture,
-// u_strokeWidth: 1,
-// u_stroke: stroke,
-// u_textSize: buffer.bufferStruct.textSize,
-// u_gamma: 0.11,
-// u_buffer: 0.8,
-// u_color: color,
-// u_glSize: [ width, height ]
-// });
-// const mesh = new THREE.Mesh(geometry, material);
-// }
+import * as THREE from '../../../core/three';
+import TextMaterial from '../../../geom/material/textMaterial';
+
+export default function DrawText(attributes, style) {
+ const geometry = new THREE.BufferGeometry();
+ geometry.addAttribute(
+ 'position',
+ new THREE.Float32BufferAttribute(attributes.originPoints, 3)
+ );
+ geometry.addAttribute(
+ 'uv',
+ new THREE.Float32BufferAttribute(attributes.textureElements, 2)
+ );
+ geometry.addAttribute(
+ 'a_txtsize',
+ new THREE.Float32BufferAttribute(attributes.textSizes, 2)
+ );
+ geometry.addAttribute(
+ 'a_txtOffsets',
+ new THREE.Float32BufferAttribute(attributes.textOffsets, 2)
+ );
+ geometry.addAttribute(
+ 'a_color',
+ new THREE.Float32BufferAttribute(attributes.colors, 4)
+ );
+ geometry.addAttribute(
+ 'pickingId',
+ new THREE.Float32BufferAttribute(attributes.pickingIds, 1)
+ );
+ const { strokeWidth, width, stroke, height, opacity, activeColor } = style;
+ const material = new TextMaterial({
+ name: this.layerId,
+ u_texture: attributes.texture,
+ u_strokeWidth: strokeWidth,
+ u_stroke: stroke,
+ u_textTextureSize: [
+ attributes.fontAtlas.width,
+ attributes.fontAtlas.height
+ ],
+ u_gamma: 0.2,
+ u_buffer: 0.75,
+ u_opacity: opacity,
+ u_glSize: [ width, height ],
+ u_activeColor: activeColor
+ });
+ const mesh = new THREE.Mesh(geometry, material);
+ return mesh;
+}
diff --git a/src/util/font-util.js b/src/util/font-util.js
new file mode 100644
index 0000000000..1e0b96a98d
--- /dev/null
+++ b/src/util/font-util.js
@@ -0,0 +1,43 @@
+export function nextPowOfTwo(number) {
+ return Math.pow(2, Math.ceil(Math.log2(number)));
+}
+
+export function buildMapping({
+ characterSet,
+ getFontWidth,
+ fontHeight,
+ buffer,
+ maxCanvasWidth,
+ mapping = {},
+ xOffset = 0,
+ yOffset = 0
+}) {
+ let row = 0;
+ let x = xOffset;
+ Array.from(characterSet).forEach((char, i) => {
+ if (!mapping[char]) {
+ const width = getFontWidth(char, i);
+ if (x + width + buffer * 2 > maxCanvasWidth) {
+ x = 0;
+ row++;
+ }
+ mapping[char] = {
+ x: x + buffer,
+ y: yOffset + row * (fontHeight + buffer * 2) + buffer,
+ width,
+ height: fontHeight,
+ mask: true
+ };
+ x += width + buffer * 2;
+ }
+ });
+
+ const rowHeight = fontHeight + buffer * 2;
+
+ return {
+ mapping,
+ xOffset: x,
+ yOffset: yOffset + row * rowHeight,
+ canvasHeight: nextPowOfTwo(yOffset + (row + 1) * rowHeight)
+ };
+}