123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- /**
- * Created by xdw on 2020/5/9.
- */
- //需要gl-matrix.js
- /*
- * popupTemplate={
- title: "{NAME}",
- content: "Population: {value}."
- }
- graphicsList=[
- {
- geometry: {
- type: "point",
- x: -80,
- y: 35
- },
- attributes: {
- NAME: "Los Angeles",
- value: 3792621
- }
- }
- ]
- *
- *
- * */
- var corrugatedPointlayer;
- function createCorrugatedPoint (popupTemplate,graphicsList,map) {
- require([
- "esri/core/watchUtils",
- "esri/core/promiseUtils",
- "esri/geometry/support/webMercatorUtils",
- "esri/layers/GraphicsLayer",
- "esri/views/2d/layers/BaseLayerViewGL2D"
- ], function(
- watchUtils,
- promiseUtils,
- webMercatorUtils,
- GraphicsLayer,
- BaseLayerViewGL2D
- ) {
- m_map.remove(corrugatedPointlayer);
- // Subclass the custom layer view from BaseLayerViewGL2D.
- var CustomLayerView2D = BaseLayerViewGL2D.createSubclass({
- // Locations of the two vertex attributes that we use. They will be bound to the shader program before linking.
- aPosition: 0,
- aOffset: 1,
- constructor: function() {
- // Geometrical transformations that must be recomputed from scratch at every frame.
- this.transform = mat3.create();
- this.translationToCenter = vec2.create();
- this.screenTranslation = vec2.create();
- // Geometrical transformations whose only a few elements must be updated per frame. Those elements are marked with NaN.
- this.display = mat3.fromValues(NaN, 0, 0, 0, NaN, 0, -1, 1, 1);
- this.screenScaling = vec3.fromValues(NaN, NaN, 1);
- // Whether the vertex and index buffers need to be updated due to a change in the layer data.
- this.needsUpdate = false;
- // We listen for changes to the graphics collection of the layer
- // and trigger the generation of new frames. A frame rendered while
- // `needsUpdate` is true may cause an update of the vertex and
- // index buffers.
- var requestUpdate = function() {
- this.needsUpdate = true;
- this.requestRender();
- }.bind(this);
- this.watcher = watchUtils.on(
- this,
- "layer.graphics",
- "change",
- requestUpdate,
- requestUpdate,
- requestUpdate
- );
- },
- // Called once a custom layer is added to the map.layers collection and this layer view is instantiated.
- attach: function() {
- var gl = this.context;
- // Define and compile shaders.
- var vertexSource =
- "precision highp float;" +
- "uniform mat3 u_transform;" +
- "uniform mat3 u_display;" +
- "attribute vec2 a_position;" +
- "attribute vec2 a_offset;" +
- "varying vec2 v_offset;" +
- "const float SIZE = 100.0;" +//直径
- "void main() {" +
- " gl_Position.xy = (u_display * (u_transform * vec3(a_position, 1.0) + vec3(a_offset * SIZE, 0.0))).xy;" +
- " gl_Position.zw = vec2(0.0, 1.0);" +
- " v_offset = a_offset;" +
- "}";
- var fragmentSource =
- "precision highp float;" +
- "uniform float u_current_time;" +
- "varying vec2 v_offset;" +
- "const float PI = 3.14159;" +
- "const float N_RINGS = 3.0;" +
- "const vec3 COLOR = vec3(0.23, 0.43, 0.70);" +//颜色修改
- "const float FREQ = 1.0;" +//频率
- "void main() {" +
- " float l = length(v_offset);" +
- " float intensity = clamp(cos(l * PI), 0.0, 1.0) * clamp(cos(2.0 * PI * (l * 2.0 * N_RINGS - FREQ * u_current_time)), 0.0, 1.0);" +
- " gl_FragColor = vec4(COLOR * intensity, intensity);" +
- "}";
- var vertexShader = gl.createShader(gl.VERTEX_SHADER);
- gl.shaderSource(vertexShader, vertexSource);
- gl.compileShader(vertexShader);
- var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
- gl.shaderSource(fragmentShader, fragmentSource);
- gl.compileShader(fragmentShader);
- // Create the shader program.
- this.program = gl.createProgram();
- gl.attachShader(this.program, vertexShader);
- gl.attachShader(this.program, fragmentShader);
- // Bind attributes.
- gl.bindAttribLocation(this.program, this.aPosition, "a_position");
- gl.bindAttribLocation(this.program, this.aOffset, "a_offset");
- // Link.
- gl.linkProgram(this.program);
- // Shader objects are not needed anymore.
- gl.deleteShader(vertexShader);
- gl.deleteShader(fragmentShader);
- // Retrieve uniform locations once and for all.
- this.uTransform = gl.getUniformLocation(
- this.program,
- "u_transform"
- );
- this.uDisplay = gl.getUniformLocation(this.program, "u_display");
- this.uCurrentTime = gl.getUniformLocation(
- this.program,
- "u_current_time"
- );
- // Create the vertex and index buffer. They are initially empty. We need to track the
- // size of the index buffer because we use indexed drawing.
- this.vertexBuffer = gl.createBuffer();
- this.indexBuffer = gl.createBuffer();
- // Number of indices in the index buffer.
- this.indexBufferSize = 0;
- // When certain conditions occur, we update the buffers and re-compute and re-encode
- // all the attributes. When buffer update occurs, we also take note of the current center
- // of the view state, and we reset a vector called `translationToCenter` to [0, 0], meaning that the
- // current center is the same as it was when the attributes were recomputed.
- this.centerAtLastUpdate = vec2.fromValues(
- this.view.state.center[0],
- this.view.state.center[1]
- );
- },
- // Called once a custom layer is removed from the map.layers collection and this layer view is destroyed.
- detach: function() {
- // Stop watching the `layer.graphics` collection.
- this.watcher.remove();
- var gl = this.context;
- // Delete buffers and programs.
- gl.deleteBuffer(this.vertexBuffer);
- gl.deleteBuffer(this.indexBuffer);
- gl.deleteProgram(this.program);
- },
- // Called every time a frame is rendered.
- render: function(renderParameters) {
- var gl = renderParameters.context;
- var state = renderParameters.state;
- // Update vertex positions. This may trigger an update of
- // the vertex coordinates contained in the vertex buffer.
- // There are three kinds of updates:
- // - Modification of the layer.graphics collection ==> Buffer update
- // - The view state becomes non-stationary ==> Only view update, no buffer update
- // - The view state becomes stationary ==> Buffer update
- this.updatePositions(renderParameters);
- // If there is nothing to render we return.
- if (this.indexBufferSize === 0) {
- return;
- }
- // Update view `transform` matrix; it converts from map units to pixels.
- mat3.identity(this.transform);
- this.screenTranslation[0] = (state.pixelRatio * state.size[0]) / 2;
- this.screenTranslation[1] = (state.pixelRatio * state.size[1]) / 2;
- mat3.translate(
- this.transform,
- this.transform,
- this.screenTranslation
- );
- mat3.rotate(
- this.transform,
- this.transform,
- (Math.PI * state.rotation) / 180
- );
- this.screenScaling[0] = state.pixelRatio / state.resolution;
- this.screenScaling[1] = -state.pixelRatio / state.resolution;
- mat3.scale(this.transform, this.transform, this.screenScaling);
- mat3.translate(
- this.transform,
- this.transform,
- this.translationToCenter
- );
- // Update view `display` matrix; it converts from pixels to normalized device coordinates.
- this.display[0] = 2 / (state.pixelRatio * state.size[0]);
- this.display[4] = -2 / (state.pixelRatio * state.size[1]);
- // Draw.
- gl.useProgram(this.program);
- gl.uniformMatrix3fv(this.uTransform, false, this.transform);
- gl.uniformMatrix3fv(this.uDisplay, false, this.display);
- gl.uniform1f(this.uCurrentTime, performance.now() / 1000.0);
- gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
- gl.enableVertexAttribArray(this.aPosition);
- gl.enableVertexAttribArray(this.aOffset);
- gl.vertexAttribPointer(this.aPosition, 2, gl.FLOAT, false, 16, 0);
- gl.vertexAttribPointer(this.aOffset, 2, gl.FLOAT, false, 16, 8);
- gl.enable(gl.BLEND);
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
- gl.drawElements(
- gl.TRIANGLES,
- this.indexBufferSize,
- gl.UNSIGNED_SHORT,
- 0
- );
- // Request new render because markers are animated.
- this.requestRender();
- },
- // Called by the map view or the popup view when hit testing is required.
- hitTest: function(x, y) {
- // The map view.
- var view = this.view;
- if (this.layer.graphics.length === 0) {
- // Nothing to do.
- return promiseUtils.resolve(null);
- }
- // Compute screen distance between each graphic and the test point.
- var distances = this.layer.graphics.map(function(graphic) {
- var graphicPoint = view.toScreen(graphic.geometry);
- return Math.sqrt(
- (graphicPoint.x - x) * (graphicPoint.x - x) +
- (graphicPoint.y - y) * (graphicPoint.y - y)
- );
- });
- // Find the minimum distance.
- var minIndex = 0;
- distances.forEach(function(distance, i) {
- if (distance < distances.getItemAt(minIndex)) {
- minIndex = i;
- }
- });
- var minDistance = distances.getItemAt(minIndex);
- // If the minimum distance is more than 35 pixel then nothing was hit.
- if (minDistance > 35) {
- return promiseUtils.resolve(null);
- }
- // Otherwise it is a hit; We set the layer as the source layer for the graphic
- // (required for the popup view to work) and we return a resolving promise to
- // the graphic.
- var graphic = this.layer.graphics.getItemAt(minIndex);
- graphic.sourceLayer = this.layer;
- return promiseUtils.resolve(graphic);
- },
- // Called internally from render().
- updatePositions: function(renderParameters) {
- var gl = renderParameters.context;
- var stationary = renderParameters.stationary;
- var state = renderParameters.state;
- // If we are not stationary we simply update the `translationToCenter` vector.
- if (!stationary) {
- vec2.sub(
- this.translationToCenter,
- this.centerAtLastUpdate,
- state.center
- );
- this.requestRender();
- return;
- }
- // If we are stationary, the `layer.graphics` collection has not changed, and
- // we are centered on the `centerAtLastUpdate`, we do nothing.
- if (
- !this.needsUpdate &&
- this.translationToCenter[0] === 0 &&
- this.translationToCenter[1] === 0
- ) {
- return;
- }
- // Otherwise, we record the new encoded center, which imply a reset of the `translationToCenter` vector,
- // we record the update time, and we proceed to update the buffers.
- this.centerAtLastUpdate.set(state.center);
- this.translationToCenter[0] = 0;
- this.translationToCenter[1] = 0;
- this.needsUpdate = false;
- var graphics = this.layer.graphics;
- // Generate vertex data.
- gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
- var vertexData = new Float32Array(16 * graphics.length);
- var i = 0;
- graphics.forEach(
- function(graphic) {
- var point = graphic.geometry;
- // The (x, y) position is relative to the encoded center.
- var x = point.x - this.centerAtLastUpdate[0];
- var y = point.y - this.centerAtLastUpdate[1];
- vertexData[i * 16 + 0] = x;
- vertexData[i * 16 + 1] = y;
- vertexData[i * 16 + 2] = -0.5;
- vertexData[i * 16 + 3] = -0.5;
- vertexData[i * 16 + 4] = x;
- vertexData[i * 16 + 5] = y;
- vertexData[i * 16 + 6] = 0.5;
- vertexData[i * 16 + 7] = -0.5;
- vertexData[i * 16 + 8] = x;
- vertexData[i * 16 + 9] = y;
- vertexData[i * 16 + 10] = -0.5;
- vertexData[i * 16 + 11] = 0.5;
- vertexData[i * 16 + 12] = x;
- vertexData[i * 16 + 13] = y;
- vertexData[i * 16 + 14] = 0.5;
- vertexData[i * 16 + 15] = 0.5;
- ++i;
- }.bind(this)
- );
- gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
- // Generates index data.
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
- var indexData = new Uint16Array(6 * graphics.length);
- for (var i = 0; i < graphics.length; ++i) {
- indexData[i * 6 + 0] = i * 4 + 0;
- indexData[i * 6 + 1] = i * 4 + 1;
- indexData[i * 6 + 2] = i * 4 + 2;
- indexData[i * 6 + 3] = i * 4 + 1;
- indexData[i * 6 + 4] = i * 4 + 3;
- indexData[i * 6 + 5] = i * 4 + 2;
- }
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);
- // Record number of indices.
- this.indexBufferSize = indexData.length;
- }
- });
- // Subclass the custom layer view from GraphicsLayer.
- var CustomLayer = GraphicsLayer.createSubclass({
- createLayerView: function(view) {
- // We only support MapView, so we only need to return a
- // custom layer view for the `2d` case.
- if (view.type === "2d") {
- return new CustomLayerView2D({
- view: view,
- layer: this
- });
- }
- }
- });
- // Create an instance of the custom layer with 4 initial graphics.
- corrugatedPointlayer = new CustomLayer({
- id:"corrugatedLayer",
- popupTemplate: popupTemplate,
- graphics: graphicsList
- });
- m_map.add(corrugatedPointlayer)
- });
- }
|