|  | <!DOCTYPE html> | 
|  | <!-- | 
|  | Licensed to the Apache Software Foundation (ASF) under one | 
|  | or more contributor license agreements.  See the NOTICE file | 
|  | distributed with this work for additional information | 
|  | regarding copyright ownership.  The ASF licenses this file | 
|  | to you under the Apache License, Version 2.0 (the | 
|  | "License"); you may not use this file except in compliance | 
|  | with the License.  You may obtain a copy of the License at | 
|  |  | 
|  | http://www.apache.org/licenses/LICENSE-2.0 | 
|  |  | 
|  | Unless required by applicable law or agreed to in writing, | 
|  | software distributed under the License is distributed on an | 
|  | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | KIND, either express or implied.  See the License for the | 
|  | specific language governing permissions and limitations | 
|  | under the License. | 
|  | --> | 
|  |  | 
|  |  | 
|  | <html> | 
|  | <head> | 
|  | <meta charset="utf-8"> | 
|  | <meta name="viewport" content="width=device-width, initial-scale=1" /> | 
|  | <script src="lib/simpleRequire.js"></script> | 
|  | <script src="lib/config.js"></script> | 
|  | <script src="../dist/echarts.js"></script> | 
|  | <script src="lib/jquery.min.js"></script> | 
|  | <script src="lib/facePrint.js"></script> | 
|  | <script src="lib/testHelper.js"></script> | 
|  | <link rel="stylesheet" href="lib/reset.css" /> | 
|  | </head> | 
|  | <body> | 
|  | <style> | 
|  | </style> | 
|  |  | 
|  |  | 
|  |  | 
|  | <div id="main-cluster-step"></div> | 
|  |  | 
|  |  | 
|  |  | 
|  | <script> | 
|  |  | 
|  | require(['echarts', 'ecStat'], function (echarts, ecStat) { | 
|  |  | 
|  | var originalData = [[3.275154, 2.957587], [-3.344465, 2.603513], [0.355083, -3.376585], [1.852435, 3.547351], [-2.078973, 2.552013], [-0.993756, -0.884433], [2.682252, 4.007573], [-3.087776, 2.878713], [-1.565978, -1.256985], [2.441611, 0.444826], [-0.659487, 3.111284], [-0.459601, -2.618005], [2.17768, 2.387793], [-2.920969, 2.917485], [-0.028814, -4.168078], [3.625746, 2.119041], [-3.912363, 1.325108], [-0.551694, -2.814223], [2.855808, 3.483301], [-3.594448, 2.856651], [0.421993, -2.372646], [1.650821, 3.407572], [-2.082902, 3.384412], [-0.718809, -2.492514], [4.513623, 3.841029], [-4.822011, 4.607049], [-0.656297, -1.449872], [1.919901, 4.439368], [-3.287749, 3.918836], [-1.576936, -2.977622], [3.598143, 1.97597], [-3.977329, 4.900932], [-1.79108, -2.184517], [3.914654, 3.559303], [-1.910108, 4.166946], [-1.226597, -3.317889], [1.148946, 3.345138], [-2.113864, 3.548172], [0.845762, -3.589788], [2.629062, 3.535831], [-1.640717, 2.990517], [-1.881012, -2.485405], [4.606999, 3.510312], [-4.366462, 4.023316], [0.765015, -3.00127], [3.121904, 2.173988], [-4.025139, 4.65231], [-0.559558, -3.840539], [4.376754, 4.863579], [-1.874308, 4.032237], [-0.089337, -3.026809], [3.997787, 2.518662], [-3.082978, 2.884822], [0.845235, -3.454465], [1.327224, 3.358778], [-2.889949, 3.596178], [-0.966018, -2.839827], [2.960769, 3.079555], [-3.275518, 1.577068], [0.639276, -3.41284]]; | 
|  | var DIM_CLUSTER_INDEX = 2; | 
|  | var DATA_DIM_IDX = [0, 1]; | 
|  | var CENTER_DIM_IDX = [3, 4]; | 
|  |  | 
|  | var step = ecStat.clustering.hierarchicalKMeans(originalData, { | 
|  | clusterCount: 6, | 
|  | outputType: 'single', | 
|  | outputClusterIndexDimension: DIM_CLUSTER_INDEX, | 
|  | outputCentroidDimensions: CENTER_DIM_IDX, | 
|  | stepByStep: true | 
|  | }); | 
|  |  | 
|  | var colorAll = [ | 
|  | '#bbb', '#37A2DA', '#e06343', '#37a354', '#b55dba', '#b5bd48', '#8378EA', '#96BFFF' | 
|  | ]; | 
|  | var ANIMATION_DURATION_UPDATE = 1500; | 
|  |  | 
|  | function renderItemPoint(params, api) { | 
|  | var coord = api.coord([api.value(0), api.value(1)]); | 
|  | var clusterIdx = api.value(2); | 
|  | if (clusterIdx == null || isNaN(clusterIdx)) { | 
|  | clusterIdx = 0; | 
|  | } | 
|  | var isNewCluster = clusterIdx === api.value(3); | 
|  |  | 
|  | var extra = { | 
|  | transition: [] | 
|  | }; | 
|  |  | 
|  | var contentColor = colorAll[clusterIdx]; | 
|  | // addColorTransition(extra, contentColor, 'content'); | 
|  |  | 
|  | return { | 
|  | type: 'circle', | 
|  | x: coord[0], | 
|  | y: coord[1], | 
|  | shape: { | 
|  | cx: 0, | 
|  | cy: 0, | 
|  | r: 10 | 
|  | }, | 
|  | extra: extra, | 
|  | style: { | 
|  | fill: contentColor, | 
|  | stroke: '#333', | 
|  | lineWidth: 1, | 
|  | shadowColor: contentColor, | 
|  | shadowBlur: isNewCluster ? 12 : 0, | 
|  | transition: ['shadowBlur', 'fill'] | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | function renderBoundary(params, api) { | 
|  | var xVal = api.value(0); | 
|  | var yVal = api.value(1); | 
|  | var maxDist = api.value(2); | 
|  | var center = api.coord([xVal, yVal]); | 
|  | var size = api.size([maxDist, maxDist]); | 
|  | var renderProgressStart; | 
|  |  | 
|  | return { | 
|  | type: 'ellipse', | 
|  | shape: { | 
|  | cx: isNaN(center[0]) ? 0 : center[0], | 
|  | cy: isNaN(center[1]) ? 0 : center[1], | 
|  | rx: isNaN(size[0]) ? 0 : size[0] + 15, | 
|  | ry: isNaN(size[1]) ? 0 : size[1] + 15 | 
|  | }, | 
|  | extra: { | 
|  | renderProgress: ++targetRenderProgress, | 
|  | enterFrom: { | 
|  | renderProgress: 0 | 
|  | }, | 
|  | transition: 'renderProgress' | 
|  | }, | 
|  | style: { | 
|  | fill: null, | 
|  | stroke: 'rgba(0,0,0,0.2)', | 
|  | lineDash: [4, 4], | 
|  | lineWidth: 4 | 
|  | }, | 
|  | during: function (apiDuring) { | 
|  | var currProgress = apiDuring.getExtra('renderProgress'); | 
|  | renderProgressStart == null && (renderProgressStart = currProgress); | 
|  | var opacity = (currProgress - renderProgressStart) | 
|  | / (targetRenderProgress - renderProgressStart); | 
|  | apiDuring.setStyle('opacity', opacity); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | function makeStepOption(option, data, centroids) { | 
|  | var newCluIdx = centroids ? centroids.length - 1 : -1; | 
|  | var maxDist = 0; | 
|  | for (var i = 0; i < data.length; i++) { | 
|  | var line = data[i]; | 
|  | if (line[DIM_CLUSTER_INDEX] === newCluIdx) { | 
|  | var dist0 = Math.pow(line[DATA_DIM_IDX[0]] - line[CENTER_DIM_IDX[0]], 2); | 
|  | var dist1 = Math.pow(line[DATA_DIM_IDX[1]] - line[CENTER_DIM_IDX[1]], 2); | 
|  | maxDist = Math.max(maxDist, dist0 + dist1); | 
|  | } | 
|  | } | 
|  | var boundaryData = centroids | 
|  | ? [ | 
|  | [ | 
|  | centroids[newCluIdx][0], | 
|  | centroids[newCluIdx][1], | 
|  | Math.sqrt(maxDist) | 
|  | ] | 
|  | ] | 
|  | : []; | 
|  |  | 
|  | option.options.push({ | 
|  | series: [{ | 
|  | type: 'custom', | 
|  | encode: { | 
|  | tooltip: [0, 1] | 
|  | }, | 
|  | renderItem: renderItemPoint, | 
|  | data: data | 
|  | }, { | 
|  | type: 'custom', | 
|  | renderItem: renderBoundary, | 
|  | animationDuration: 3000, | 
|  | silent: true, | 
|  | data: boundaryData | 
|  | }] | 
|  | }); | 
|  | } | 
|  |  | 
|  | var targetRenderProgress = 0; | 
|  |  | 
|  | var option = { | 
|  | timeline: { | 
|  | top: 'center', | 
|  | right: 50, | 
|  | height: 300, | 
|  | width: 10, | 
|  | inverse: true, | 
|  | autoPlay: false, | 
|  | playInterval: 2500, | 
|  | symbol: 'none', | 
|  | orient: 'vertical', | 
|  | axisType: 'category', | 
|  | label: { | 
|  | formatter: 'step {value}', | 
|  | position: 10 | 
|  | }, | 
|  | checkpointStyle: { | 
|  | color: '#555', | 
|  | borderWidth: 0, | 
|  | animationDuration: ANIMATION_DURATION_UPDATE | 
|  | }, | 
|  | data: [] | 
|  | }, | 
|  | baseOption: { | 
|  | animationDurationUpdate: ANIMATION_DURATION_UPDATE, | 
|  | tooltip: { | 
|  | }, | 
|  | xAxis: { | 
|  | type: 'value' | 
|  | }, | 
|  | yAxis: { | 
|  | type: 'value' | 
|  | }, | 
|  | series: [{ | 
|  | type: 'scatter' | 
|  | }] | 
|  | }, | 
|  | options: [] | 
|  | }; | 
|  |  | 
|  | makeStepOption(option, originalData); | 
|  | option.timeline.data.push('0'); | 
|  | for (var i = 1, stepResult; !(stepResult = step.next()).isEnd; i++) { | 
|  | makeStepOption( | 
|  | option, | 
|  | echarts.util.clone(stepResult.data), | 
|  | echarts.util.clone(stepResult.centroids) | 
|  | ); | 
|  | option.timeline.data.push(i + ''); | 
|  | } | 
|  |  | 
|  | var chart = testHelper.create(echarts, 'main-cluster-step', { | 
|  | title: [ | 
|  | 'Cluster algorithm visualization' | 
|  | ], | 
|  | height: 600, | 
|  | option: option | 
|  | }); | 
|  |  | 
|  |  | 
|  | }); | 
|  |  | 
|  | </script> | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | </body> | 
|  | </html> | 
|  |  |